From 3fcedec752108de5d99b9f0373ff880756a1e87d Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 26 Oct 2010 12:25:32 +0200 Subject: drivers/vhost/vhost.c: delete double assignment Delete successive assignments to the same location. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression i; @@ *i = ...; i = ...; // Signed-off-by: Julia Lawall Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 94701ff3a23a..ed277276fa98 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -157,7 +157,6 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->avail_idx = 0; vq->last_used_idx = 0; vq->used_flags = 0; - vq->used_flags = 0; vq->log_used = false; vq->log_addr = -1ull; vq->vhost_hlen = 0; -- cgit v1.2.3 From 533a19b4b88fcf81da3106b94f0ac4ac8b33a248 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 6 Oct 2010 15:34:38 +0200 Subject: vhost: put mm after thread stop makes it possible to batch use/unuse mm Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ed277276fa98..9920bae6ee43 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -401,15 +401,14 @@ void vhost_dev_cleanup(struct vhost_dev *dev) kfree(rcu_dereference_protected(dev->memory, lockdep_is_held(&dev->mutex))); RCU_INIT_POINTER(dev->memory, NULL); - if (dev->mm) - mmput(dev->mm); - dev->mm = NULL; - WARN_ON(!list_empty(&dev->work_list)); if (dev->worker) { kthread_stop(dev->worker); dev->worker = NULL; } + if (dev->mm) + mmput(dev->mm); + dev->mm = NULL; } static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) -- cgit v1.2.3 From 64e1c80748afca3b4818ebb232a9668bf529886d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 6 Oct 2010 15:34:45 +0200 Subject: vhost-net: batch use/unuse mm Move use/unuse mm to vhost.c which makes it possible to batch these operations. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 7 ------- drivers/vhost/vhost.c | 7 ++++++- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 4b4da5b86ff9..d10da280fa0f 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -142,7 +141,6 @@ static void handle_tx(struct vhost_net *net) return; } - use_mm(net->dev.mm); mutex_lock(&vq->mutex); vhost_disable_notify(vq); @@ -207,7 +205,6 @@ static void handle_tx(struct vhost_net *net) } mutex_unlock(&vq->mutex); - unuse_mm(net->dev.mm); } static int peek_head_len(struct sock *sk) @@ -312,7 +309,6 @@ static void handle_rx_big(struct vhost_net *net) if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) return; - use_mm(net->dev.mm); mutex_lock(&vq->mutex); vhost_disable_notify(vq); hdr_size = vq->vhost_hlen; @@ -391,7 +387,6 @@ static void handle_rx_big(struct vhost_net *net) } mutex_unlock(&vq->mutex); - unuse_mm(net->dev.mm); } /* Expects to be always run from workqueue - which acts as @@ -423,7 +418,6 @@ static void handle_rx_mergeable(struct vhost_net *net) if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) return; - use_mm(net->dev.mm); mutex_lock(&vq->mutex); vhost_disable_notify(vq); vhost_hlen = vq->vhost_hlen; @@ -500,7 +494,6 @@ static void handle_rx_mergeable(struct vhost_net *net) } mutex_unlock(&vq->mutex); - unuse_mm(net->dev.mm); } static void handle_rx(struct vhost_net *net) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 9920bae6ee43..c17c881e235a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -177,6 +178,8 @@ static int vhost_worker(void *data) struct vhost_work *work = NULL; unsigned uninitialized_var(seq); + use_mm(dev->mm); + for (;;) { /* mb paired w/ kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); @@ -191,7 +194,7 @@ static int vhost_worker(void *data) if (kthread_should_stop()) { spin_unlock_irq(&dev->work_lock); __set_current_state(TASK_RUNNING); - return 0; + break; } if (!list_empty(&dev->work_list)) { work = list_first_entry(&dev->work_list, @@ -209,6 +212,8 @@ static int vhost_worker(void *data) schedule(); } + unuse_mm(dev->mm); + return 0; } /* Helper to allocate iovec buffers for all vqs. */ -- cgit v1.2.3 From dfe5ac5b18be5b10d01a17e734a9905c0def6088 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 21 Sep 2010 14:18:01 +0200 Subject: vhost: copy_to_user -> __copy_to_user We do access_ok checks at setup time, so we don't need to redo them on each access. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c17c881e235a..e6a093187a0e 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1258,7 +1258,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq, start = vq->last_used_idx % vq->num; used = vq->used->ring + start; - if (copy_to_user(used, heads, count * sizeof *used)) { + if (__copy_to_user(used, heads, count * sizeof *used)) { vq_err(vq, "Failed to write used"); return -EFAULT; } -- cgit v1.2.3 From 8b7347aab6865ae8a2e5a8b0f1deea12da3d3aff Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 19 Sep 2010 15:56:30 +0200 Subject: vhost: get/put_user -> __get/__put_user We do access_ok checks on all ring values on an ioctl, so we don't need to redo them on each access. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e6a093187a0e..a29d91c776b4 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1095,7 +1095,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Check it isn't doing very strange things with descriptor numbers. */ last_avail_idx = vq->last_avail_idx; - if (unlikely(get_user(vq->avail_idx, &vq->avail->idx))) { + if (unlikely(__get_user(vq->avail_idx, &vq->avail->idx))) { vq_err(vq, "Failed to access avail idx at %p\n", &vq->avail->idx); return -EFAULT; @@ -1116,8 +1116,8 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, /* Grab the next descriptor number they're advertising, and increment * the index we've seen. */ - if (unlikely(get_user(head, - &vq->avail->ring[last_avail_idx % vq->num]))) { + if (unlikely(__get_user(head, + &vq->avail->ring[last_avail_idx % vq->num]))) { vq_err(vq, "Failed to read head: idx %d address %p\n", last_avail_idx, &vq->avail->ring[last_avail_idx % vq->num]); @@ -1216,17 +1216,17 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len) /* The virtqueue contains a ring of used buffers. Get a pointer to the * next entry in that used ring. */ used = &vq->used->ring[vq->last_used_idx % vq->num]; - if (put_user(head, &used->id)) { + if (__put_user(head, &used->id)) { vq_err(vq, "Failed to write used id"); return -EFAULT; } - if (put_user(len, &used->len)) { + if (__put_user(len, &used->len)) { vq_err(vq, "Failed to write used len"); return -EFAULT; } /* Make sure buffer is written before we update index. */ smp_wmb(); - if (put_user(vq->last_used_idx + 1, &vq->used->idx)) { + if (__put_user(vq->last_used_idx + 1, &vq->used->idx)) { vq_err(vq, "Failed to increment used idx"); return -EFAULT; } @@ -1319,7 +1319,7 @@ void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq) * interrupts. */ smp_mb(); - if (get_user(flags, &vq->avail->flags)) { + if (__get_user(flags, &vq->avail->flags)) { vq_err(vq, "Failed to get flags"); return; } @@ -1370,7 +1370,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) /* They could have slipped one in as we were doing that: make * sure it's written, then check again. */ smp_mb(); - r = get_user(avail_idx, &vq->avail->idx); + r = __get_user(avail_idx, &vq->avail->idx); if (r) { vq_err(vq, "Failed to check avail idx at %p: %d\n", &vq->avail->idx, r); -- cgit v1.2.3 From 1d5439b9a29b1386d44a617cbaf2f7acde1d697c Mon Sep 17 00:00:00 2001 From: "Arce, Abraham" Date: Thu, 28 Oct 2010 18:57:20 +0000 Subject: ks8851: suspend resume support Add suspend/resume support using default open/stop interface methods to do hardware dependant operations. On suspend, same low power state (soft power mode) will be kept, the following blocks will be disabled: - Internal PLL Clock - Tx/Rx PHY - MAC - SPI Interface Signed-off-by: Abraham Arce Signed-off-by: David S. Miller --- drivers/net/ks8851.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 51919fcd50c2..0fa4a9887ba2 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -1545,6 +1545,37 @@ static int ks8851_read_selftest(struct ks8851_net *ks) /* driver bus management functions */ +#ifdef CONFIG_PM +static int ks8851_suspend(struct spi_device *spi, pm_message_t state) +{ + struct ks8851_net *ks = dev_get_drvdata(&spi->dev); + struct net_device *dev = ks->netdev; + + if (netif_running(dev)) { + netif_device_detach(dev); + ks8851_net_stop(dev); + } + + return 0; +} + +static int ks8851_resume(struct spi_device *spi) +{ + struct ks8851_net *ks = dev_get_drvdata(&spi->dev); + struct net_device *dev = ks->netdev; + + if (netif_running(dev)) { + ks8851_net_open(dev); + netif_device_attach(dev); + } + + return 0; +} +#else +#define ks8851_suspend NULL +#define ks8851_resume NULL +#endif + static int __devinit ks8851_probe(struct spi_device *spi) { struct net_device *ndev; @@ -1679,6 +1710,8 @@ static struct spi_driver ks8851_driver = { }, .probe = ks8851_probe, .remove = __devexit_p(ks8851_remove), + .suspend = ks8851_suspend, + .resume = ks8851_resume, }; static int __init ks8851_init(void) -- cgit v1.2.3 From 840a185dddfd098b78b96a30da4cad722a7aef18 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Oct 2010 01:15:29 +0000 Subject: aoe: remove dev_base_lock use from aoecmd_cfg_pkts() dev_base_lock is the legacy way to lock the device list, and is planned to disappear. (writers hold RTNL, readers hold RCU lock) Convert aoecmd_cfg_pkts() to RCU locking. Signed-off-by: Eric Dumazet Cc: "Ed L. Cashin" Signed-off-by: David S. Miller --- drivers/block/aoe/aoecmd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 5674bd01d96d..de0435e63b02 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -297,8 +297,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu struct sk_buff *skb; struct net_device *ifp; - read_lock(&dev_base_lock); - for_each_netdev(&init_net, ifp) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, ifp) { dev_hold(ifp); if (!is_aoe_netif(ifp)) goto cont; @@ -325,7 +325,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff_head *qu cont: dev_put(ifp); } - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static void -- cgit v1.2.3 From e4a7b93bd5d84e1e79917d024d17d745d190fc9a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 29 Oct 2010 01:52:46 +0000 Subject: bonding: remove dev_base_lock use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bond_info_seq_start() uses a read_lock(&dev_base_lock) to make sure device doesn’t disappear. Same goal can be achieved using RCU. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bdb68a600382..518844852f06 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3209,7 +3209,7 @@ out: #ifdef CONFIG_PROC_FS static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(&dev_base_lock) + __acquires(RCU) __acquires(&bond->lock) { struct bonding *bond = seq->private; @@ -3218,7 +3218,7 @@ static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos) int i; /* make sure the bond won't be taken away */ - read_lock(&dev_base_lock); + rcu_read_lock(); read_lock(&bond->lock); if (*pos == 0) @@ -3248,12 +3248,12 @@ static void *bond_info_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void bond_info_seq_stop(struct seq_file *seq, void *v) __releases(&bond->lock) - __releases(&dev_base_lock) + __releases(RCU) { struct bonding *bond = seq->private; read_unlock(&bond->lock); - read_unlock(&dev_base_lock); + rcu_read_unlock(); } static void bond_info_show_master(struct seq_file *seq) -- cgit v1.2.3 From d6ff7d0fe22cdf3ea41c48b50da9a9181500d1bf Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Tue, 9 Nov 2010 02:42:39 +0300 Subject: ARM: Add support for the display controllers in VT8500 and WM8505 This adds drivers for the LCD controller found in VIA VT8500 SoC, GOVR display controller found in WonderMedia WM8505 SoC and for the Graphics Engine present in both of them that provides hardware accelerated raster operations (used for copyarea and fillrect). Signed-off-by: Alexey Charkov Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 26 +++ drivers/video/Makefile | 3 + drivers/video/vt8500lcdfb.c | 447 ++++++++++++++++++++++++++++++++++++++++++ drivers/video/vt8500lcdfb.h | 34 ++++ drivers/video/wm8505fb.c | 422 +++++++++++++++++++++++++++++++++++++++ drivers/video/wm8505fb_regs.h | 76 +++++++ drivers/video/wmt_ge_rops.c | 192 ++++++++++++++++++ drivers/video/wmt_ge_rops.h | 5 + 8 files changed, 1205 insertions(+) create mode 100644 drivers/video/vt8500lcdfb.c create mode 100644 drivers/video/vt8500lcdfb.h create mode 100644 drivers/video/wm8505fb.c create mode 100644 drivers/video/wm8505fb_regs.h create mode 100644 drivers/video/wmt_ge_rops.c create mode 100644 drivers/video/wmt_ge_rops.h (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 27c1fb4b1e0d..954f6e9d8d5a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -186,6 +186,14 @@ config FB_SYS_FOPS depends on FB default n +config FB_WMT_GE_ROPS + tristate + depends on FB + default n + ---help--- + Include functions for accelerated rectangle filling and area + copying using WonderMedia Graphics Engine operations. + config FB_DEFERRED_IO bool depends on FB @@ -1722,6 +1730,24 @@ config FB_AU1200 various panels and CRTs by passing in kernel cmd line option au1200fb:panel=. +config FB_VT8500 + bool "VT8500 LCD Driver" + depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_VT8500 + select FB_WMT_GE_ROPS + select FB_SYS_IMAGEBLIT + help + This is the framebuffer driver for VIA VT8500 integrated LCD + controller. + +config FB_WM8505 + bool "WM8505 frame buffer support" + depends on (FB = y) && ARM && ARCH_VT8500 && VTWM_VERSION_WM8505 + select FB_WMT_GE_ROPS + select FB_SYS_IMAGEBLIT + help + This is the framebuffer driver for WonderMedia WM8505 + integrated LCD controller. + source "drivers/video/geode/Kconfig" config FB_HIT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 485e8ed1318c..8d916dcb379f 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_FB_SVGALIB) += svgalib.o obj-$(CONFIG_FB_MACMODES) += macmodes.o obj-$(CONFIG_FB_DDC) += fb_ddc.o obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o +obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o # Hardware specific drivers go first obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o @@ -104,6 +105,8 @@ obj-$(CONFIG_FB_W100) += w100fb.o obj-$(CONFIG_FB_TMIO) += tmiofb.o obj-$(CONFIG_FB_AU1100) += au1100fb.o obj-$(CONFIG_FB_AU1200) += au1200fb.o +obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o +obj-$(CONFIG_FB_WM8505) += wm8505fb.o obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c new file mode 100644 index 000000000000..7617f12e4fd7 --- /dev/null +++ b/drivers/video/vt8500lcdfb.c @@ -0,0 +1,447 @@ +/* + * linux/drivers/video/vt8500lcdfb.c + * + * Copyright (C) 2010 Alexey Charkov + * + * Based on skeletonfb.c and pxafb.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "vt8500lcdfb.h" +#include "wmt_ge_rops.h" + +#define to_vt8500lcd_info(__info) container_of(__info, \ + struct vt8500lcd_info, fb) + +static int vt8500lcd_set_par(struct fb_info *info) +{ + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); + int reg_bpp = 5; /* 16bpp */ + int i; + unsigned long control0; + + if (!fbi) + return -EINVAL; + + if (info->var.bits_per_pixel <= 8) { + /* palettized */ + info->var.red.offset = 0; + info->var.red.length = info->var.bits_per_pixel; + info->var.red.msb_right = 0; + + info->var.green.offset = 0; + info->var.green.length = info->var.bits_per_pixel; + info->var.green.msb_right = 0; + + info->var.blue.offset = 0; + info->var.blue.length = info->var.bits_per_pixel; + info->var.blue.msb_right = 0; + + info->var.transp.offset = 0; + info->var.transp.length = 0; + info->var.transp.msb_right = 0; + + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + info->fix.line_length = info->var.xres_virtual / + (8/info->var.bits_per_pixel); + } else { + /* non-palettized */ + info->var.transp.offset = 0; + info->var.transp.length = 0; + info->var.transp.msb_right = 0; + + if (info->var.bits_per_pixel == 16) { + /* RGB565 */ + info->var.red.offset = 11; + info->var.red.length = 5; + info->var.red.msb_right = 0; + info->var.green.offset = 5; + info->var.green.length = 6; + info->var.green.msb_right = 0; + info->var.blue.offset = 0; + info->var.blue.length = 5; + info->var.blue.msb_right = 0; + } else { + /* Equal depths per channel */ + info->var.red.offset = info->var.bits_per_pixel + * 2 / 3; + info->var.red.length = info->var.bits_per_pixel / 3; + info->var.red.msb_right = 0; + info->var.green.offset = info->var.bits_per_pixel / 3; + info->var.green.length = info->var.bits_per_pixel / 3; + info->var.green.msb_right = 0; + info->var.blue.offset = 0; + info->var.blue.length = info->var.bits_per_pixel / 3; + info->var.blue.msb_right = 0; + } + + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.bits_per_pixel > 16 ? + info->var.xres_virtual << 2 : + info->var.xres_virtual << 1; + } + + for (i = 0; i < 8; i++) { + if (bpp_values[i] == info->var.bits_per_pixel) { + reg_bpp = i; + continue; + } + } + + control0 = readl(fbi->regbase) & ~0xf; + writel(0, fbi->regbase); + while (readl(fbi->regbase + 0x38) & 0x10) + /* wait */; + writel((((info->var.hsync_len - 1) & 0x3f) << 26) + | ((info->var.left_margin & 0xff) << 18) + | (((info->var.xres - 1) & 0x3ff) << 8) + | (info->var.right_margin & 0xff), fbi->regbase + 0x4); + writel((((info->var.vsync_len - 1) & 0x3f) << 26) + | ((info->var.upper_margin & 0xff) << 18) + | (((info->var.yres - 1) & 0x3ff) << 8) + | (info->var.lower_margin & 0xff), fbi->regbase + 0x8); + writel((((info->var.yres - 1) & 0x400) << 2) + | ((info->var.xres - 1) & 0x400), fbi->regbase + 0x10); + writel(0x80000000, fbi->regbase + 0x20); + writel(control0 | (reg_bpp << 1) | 0x100, fbi->regbase); + + return 0; +} + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int vt8500lcd_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); + int ret = 1; + unsigned int val; + if (regno >= 256) + return -EINVAL; + + if (info->var.grayscale) + red = green = blue = + (19595 * red + 38470 * green + 7471 * blue) >> 16; + + switch (fbi->fb.fix.visual) { + case FB_VISUAL_TRUECOLOR: + if (regno < 16) { + u32 *pal = fbi->fb.pseudo_palette; + + val = chan_to_field(red, &fbi->fb.var.red); + val |= chan_to_field(green, &fbi->fb.var.green); + val |= chan_to_field(blue, &fbi->fb.var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + writew((red & 0xf800) + | ((green >> 5) & 0x7e0) + | ((blue >> 11) & 0x1f), + fbi->palette_cpu + sizeof(u16) * regno); + break; + } + + return ret; +} + +static int vt8500lcd_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); + + if (cmd == FBIO_WAITFORVSYNC) { + /* Unmask End of Frame interrupt */ + writel(0xffffffff ^ (1 << 3), fbi->regbase + 0x3c); + ret = wait_event_interruptible_timeout(fbi->wait, + readl(fbi->regbase + 0x38) & (1 << 3), HZ / 10); + /* Mask back to reduce unwanted interrupt traffic */ + writel(0xffffffff, fbi->regbase + 0x3c); + if (ret < 0) + return ret; + if (ret == 0) + return -ETIMEDOUT; + } + + return ret; +} + +static int vt8500lcd_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + unsigned pixlen = info->fix.line_length / info->var.xres_virtual; + unsigned off = pixlen * var->xoffset + + info->fix.line_length * var->yoffset; + struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); + + writel((1 << 31) + | (((var->xres_virtual - var->xres) * pixlen / 4) << 20) + | (off >> 2), fbi->regbase + 0x20); + return 0; +} + +static struct fb_ops vt8500lcd_ops = { + .owner = THIS_MODULE, + .fb_set_par = vt8500lcd_set_par, + .fb_setcolreg = vt8500lcd_setcolreg, + .fb_fillrect = wmt_ge_fillrect, + .fb_copyarea = wmt_ge_copyarea, + .fb_imageblit = sys_imageblit, + .fb_sync = wmt_ge_sync, + .fb_ioctl = vt8500lcd_ioctl, + .fb_pan_display = vt8500lcd_pan_display, +}; + +static irqreturn_t vt8500lcd_handle_irq(int irq, void *dev_id) +{ + struct vt8500lcd_info *fbi = dev_id; + + if (readl(fbi->regbase + 0x38) & (1 << 3)) + wake_up_interruptible(&fbi->wait); + + writel(0xffffffff, fbi->regbase + 0x38); + return IRQ_HANDLED; +} + +static int __devinit vt8500lcd_probe(struct platform_device *pdev) +{ + struct vt8500lcd_info *fbi; + struct resource *res; + struct vt8500fb_platform_data *pdata = pdev->dev.platform_data; + void *addr; + int irq, ret; + + ret = -ENOMEM; + fbi = NULL; + + fbi = kzalloc(sizeof(struct vt8500lcd_info) + sizeof(u32) * 16, + GFP_KERNEL); + if (!fbi) { + dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); + ret = -ENOMEM; + goto failed; + } + + strcpy(fbi->fb.fix.id, "VT8500 LCD"); + + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fb.fix.xpanstep = 0; + fbi->fb.fix.ypanstep = 1; + fbi->fb.fix.ywrapstep = 0; + fbi->fb.fix.accel = FB_ACCEL_NONE; + + fbi->fb.var.nonstd = 0; + fbi->fb.var.activate = FB_ACTIVATE_NOW; + fbi->fb.var.height = -1; + fbi->fb.var.width = -1; + fbi->fb.var.vmode = FB_VMODE_NONINTERLACED; + + fbi->fb.fbops = &vt8500lcd_ops; + fbi->fb.flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_YPAN + | FBINFO_VIRTFB + | FBINFO_PARTIAL_PAN_OK; + fbi->fb.node = -1; + + addr = fbi; + addr = addr + sizeof(struct vt8500lcd_info); + fbi->fb.pseudo_palette = addr; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + ret = -ENODEV; + goto failed_fbi; + } + + res = request_mem_region(res->start, resource_size(res), "vt8500lcd"); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + ret = -EBUSY; + goto failed_fbi; + } + + fbi->regbase = ioremap(res->start, resource_size(res)); + if (fbi->regbase == NULL) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + ret = -EBUSY; + goto failed_free_res; + } + + fbi->fb.fix.smem_start = pdata->video_mem_phys; + fbi->fb.fix.smem_len = pdata->video_mem_len; + fbi->fb.screen_base = pdata->video_mem_virt; + + fbi->palette_size = PAGE_ALIGN(512); + fbi->palette_cpu = dma_alloc_coherent(&pdev->dev, + fbi->palette_size, + &fbi->palette_phys, + GFP_KERNEL); + if (fbi->palette_cpu == NULL) { + dev_err(&pdev->dev, "Failed to allocate palette buffer\n"); + ret = -ENOMEM; + goto failed_free_io; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no IRQ defined\n"); + ret = -ENODEV; + goto failed_free_palette; + } + + ret = request_irq(irq, vt8500lcd_handle_irq, IRQF_DISABLED, "LCD", fbi); + if (ret) { + dev_err(&pdev->dev, "request_irq failed: %d\n", ret); + ret = -EBUSY; + goto failed_free_palette; + } + + init_waitqueue_head(&fbi->wait); + + if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { + dev_err(&pdev->dev, "Failed to allocate color map\n"); + ret = -ENOMEM; + goto failed_free_irq; + } + + fb_videomode_to_var(&fbi->fb.var, &pdata->mode); + fbi->fb.var.bits_per_pixel = pdata->bpp; + fbi->fb.var.xres_virtual = pdata->xres_virtual; + fbi->fb.var.yres_virtual = pdata->yres_virtual; + + ret = vt8500lcd_set_par(&fbi->fb); + if (ret) { + dev_err(&pdev->dev, "Failed to set parameters\n"); + goto failed_free_cmap; + } + + writel(fbi->fb.fix.smem_start >> 22, fbi->regbase + 0x1c); + writel((fbi->palette_phys & 0xfffffe00) | 1, fbi->regbase + 0x18); + + platform_set_drvdata(pdev, fbi); + + ret = register_framebuffer(&fbi->fb); + if (ret < 0) { + dev_err(&pdev->dev, + "Failed to register framebuffer device: %d\n", ret); + goto failed_free_cmap; + } + + /* + * Ok, now enable the LCD controller + */ + writel(readl(fbi->regbase) | 1, fbi->regbase); + + return 0; + +failed_free_cmap: + if (fbi->fb.cmap.len) + fb_dealloc_cmap(&fbi->fb.cmap); +failed_free_irq: + free_irq(irq, fbi); +failed_free_palette: + dma_free_coherent(&pdev->dev, fbi->palette_size, + fbi->palette_cpu, fbi->palette_phys); +failed_free_io: + iounmap(fbi->regbase); +failed_free_res: + release_mem_region(res->start, resource_size(res)); +failed_fbi: + platform_set_drvdata(pdev, NULL); + kfree(fbi); +failed: + return ret; +} + +static int __devexit vt8500lcd_remove(struct platform_device *pdev) +{ + struct vt8500lcd_info *fbi = platform_get_drvdata(pdev); + struct resource *res; + int irq; + + unregister_framebuffer(&fbi->fb); + + writel(0, fbi->regbase); + + if (fbi->fb.cmap.len) + fb_dealloc_cmap(&fbi->fb.cmap); + + irq = platform_get_irq(pdev, 0); + free_irq(irq, fbi); + + dma_free_coherent(&pdev->dev, fbi->palette_size, + fbi->palette_cpu, fbi->palette_phys); + + iounmap(fbi->regbase); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(fbi); + + return 0; +} + +static struct platform_driver vt8500lcd_driver = { + .probe = vt8500lcd_probe, + .remove = __devexit_p(vt8500lcd_remove), + .driver = { + .owner = THIS_MODULE, + .name = "vt8500-lcd", + }, +}; + +static int __init vt8500lcd_init(void) +{ + return platform_driver_register(&vt8500lcd_driver); +} + +static void __exit vt8500lcd_exit(void) +{ + platform_driver_unregister(&vt8500lcd_driver); +} + +module_init(vt8500lcd_init); +module_exit(vt8500lcd_exit); + +MODULE_AUTHOR("Alexey Charkov "); +MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/vt8500lcdfb.h b/drivers/video/vt8500lcdfb.h new file mode 100644 index 000000000000..36ca3ca09d83 --- /dev/null +++ b/drivers/video/vt8500lcdfb.h @@ -0,0 +1,34 @@ +/* + * linux/drivers/video/vt8500lcdfb.h + * + * Copyright (C) 2010 Alexey Charkov + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +struct vt8500lcd_info { + struct fb_info fb; + void __iomem *regbase; + void __iomem *palette_cpu; + dma_addr_t palette_phys; + size_t palette_size; + wait_queue_head_t wait; +}; + +static int bpp_values[] = { + 1, + 2, + 4, + 8, + 12, + 16, + 18, + 24, +}; diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c new file mode 100644 index 000000000000..e37251b792c9 --- /dev/null +++ b/drivers/video/wm8505fb.c @@ -0,0 +1,422 @@ +/* + * WonderMedia WM8505 Frame Buffer device driver + * + * Copyright (C) 2010 Ed Spiridonov + * Based on vt8500lcdfb.c + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "wm8505fb_regs.h" +#include "wmt_ge_rops.h" + +#define DRIVER_NAME "wm8505-fb" + +#define to_wm8505fb_info(__info) container_of(__info, \ + struct wm8505fb_info, fb) +struct wm8505fb_info { + struct fb_info fb; + void __iomem *regbase; + unsigned int contrast; +}; + + +static int wm8505fb_init_hw(struct fb_info *info) +{ + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + int i; + + /* I know the purpose only of few registers, so clear unknown */ + for (i = 0; i < 0x200; i += 4) + writel(0, fbi->regbase + i); + + /* Set frame buffer address */ + writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR); + writel(fbi->fb.fix.smem_start, fbi->regbase + WMT_GOVR_FBADDR1); + + /* Set in-memory picture format to RGB 32bpp */ + writel(0x1c, fbi->regbase + WMT_GOVR_COLORSPACE); + writel(1, fbi->regbase + WMT_GOVR_COLORSPACE1); + + /* Virtual buffer size */ + writel(info->var.xres, fbi->regbase + WMT_GOVR_XRES); + writel(info->var.xres_virtual, fbi->regbase + WMT_GOVR_XRES_VIRTUAL); + + /* black magic ;) */ + writel(0xf, fbi->regbase + WMT_GOVR_FHI); + writel(4, fbi->regbase + WMT_GOVR_DVO_SET); + writel(1, fbi->regbase + WMT_GOVR_MIF_ENABLE); + writel(1, fbi->regbase + WMT_GOVR_REG_UPDATE); + + return 0; +} + +static int wm8505fb_set_timing(struct fb_info *info) +{ + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + int h_start = info->var.left_margin; + int h_end = h_start + info->var.xres; + int h_all = h_end + info->var.right_margin; + int h_sync = info->var.hsync_len; + + int v_start = info->var.upper_margin; + int v_end = v_start + info->var.yres; + int v_all = v_end + info->var.lower_margin; + int v_sync = info->var.vsync_len + 1; + + writel(0, fbi->regbase + WMT_GOVR_TG); + + writel(h_start, fbi->regbase + WMT_GOVR_TIMING_H_START); + writel(h_end, fbi->regbase + WMT_GOVR_TIMING_H_END); + writel(h_all, fbi->regbase + WMT_GOVR_TIMING_H_ALL); + writel(h_sync, fbi->regbase + WMT_GOVR_TIMING_H_SYNC); + + writel(v_start, fbi->regbase + WMT_GOVR_TIMING_V_START); + writel(v_end, fbi->regbase + WMT_GOVR_TIMING_V_END); + writel(v_all, fbi->regbase + WMT_GOVR_TIMING_V_ALL); + writel(v_sync, fbi->regbase + WMT_GOVR_TIMING_V_SYNC); + + writel(1, fbi->regbase + WMT_GOVR_TG); + + return 0; +} + + +static int wm8505fb_set_par(struct fb_info *info) +{ + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + if (!fbi) + return -EINVAL; + + if (info->var.bits_per_pixel == 32) { + info->var.red.offset = 16; + info->var.red.length = 8; + info->var.red.msb_right = 0; + info->var.green.offset = 8; + info->var.green.length = 8; + info->var.green.msb_right = 0; + info->var.blue.offset = 0; + info->var.blue.length = 8; + info->var.blue.msb_right = 0; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.line_length = info->var.xres_virtual << 2; + } + + wm8505fb_set_timing(info); + + writel(fbi->contrast<<16 | fbi->contrast<<8 | fbi->contrast, + fbi->regbase + WMT_GOVR_CONTRAST); + + return 0; +} + +static ssize_t contrast_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + return sprintf(buf, "%d\n", fbi->contrast); +} + +static ssize_t contrast_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *info = dev_get_drvdata(dev); + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + unsigned long tmp; + + if (strict_strtoul(buf, 10, &tmp) || (tmp > 0xff)) + return -EINVAL; + fbi->contrast = tmp; + + wm8505fb_set_par(info); + + return count; +} + +static DEVICE_ATTR(contrast, 0644, contrast_show, contrast_store); + +static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int wm8505fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) { + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + int ret = 1; + unsigned int val; + if (regno >= 256) + return -EINVAL; + + if (info->var.grayscale) + red = green = blue = + (19595 * red + 38470 * green + 7471 * blue) >> 16; + + switch (fbi->fb.fix.visual) { + case FB_VISUAL_TRUECOLOR: + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + val = chan_to_field(red, &fbi->fb.var.red); + val |= chan_to_field(green, &fbi->fb.var.green); + val |= chan_to_field(blue, &fbi->fb.var.blue); + + pal[regno] = val; + ret = 0; + } + break; + } + + return ret; +} + +static int wm8505fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + writel(var->xoffset, fbi->regbase + WMT_GOVR_XPAN); + writel(var->yoffset, fbi->regbase + WMT_GOVR_YPAN); + return 0; +} + +static int wm8505fb_blank(int blank, struct fb_info *info) +{ + struct wm8505fb_info *fbi = to_wm8505fb_info(info); + + switch (blank) { + case FB_BLANK_UNBLANK: + wm8505fb_set_timing(info); + break; + default: + writel(0, fbi->regbase + WMT_GOVR_TIMING_V_SYNC); + break; + } + + return 0; +} + +static struct fb_ops wm8505fb_ops = { + .owner = THIS_MODULE, + .fb_set_par = wm8505fb_set_par, + .fb_setcolreg = wm8505fb_setcolreg, + .fb_fillrect = wmt_ge_fillrect, + .fb_copyarea = wmt_ge_copyarea, + .fb_imageblit = sys_imageblit, + .fb_sync = wmt_ge_sync, + .fb_pan_display = wm8505fb_pan_display, + .fb_blank = wm8505fb_blank, +}; + +static int __devinit wm8505fb_probe(struct platform_device *pdev) +{ + struct wm8505fb_info *fbi; + struct resource *res; + void *addr; + struct vt8500fb_platform_data *pdata; + int ret; + + pdata = pdev->dev.platform_data; + + ret = -ENOMEM; + fbi = NULL; + + fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16, + GFP_KERNEL); + if (!fbi) { + dev_err(&pdev->dev, "Failed to initialize framebuffer device\n"); + ret = -ENOMEM; + goto failed; + } + + strcpy(fbi->fb.fix.id, DRIVER_NAME); + + fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fb.fix.xpanstep = 1; + fbi->fb.fix.ypanstep = 1; + fbi->fb.fix.ywrapstep = 0; + fbi->fb.fix.accel = FB_ACCEL_NONE; + + fbi->fb.fbops = &wm8505fb_ops; + fbi->fb.flags = FBINFO_DEFAULT + | FBINFO_HWACCEL_COPYAREA + | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_XPAN + | FBINFO_HWACCEL_YPAN + | FBINFO_VIRTFB + | FBINFO_PARTIAL_PAN_OK; + fbi->fb.node = -1; + + addr = fbi; + addr = addr + sizeof(struct wm8505fb_info); + fbi->fb.pseudo_palette = addr; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + ret = -ENODEV; + goto failed_fbi; + } + + res = request_mem_region(res->start, resource_size(res), "wm8505fb"); + if (res == NULL) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + ret = -EBUSY; + goto failed_fbi; + } + + fbi->regbase = ioremap(res->start, resource_size(res)); + if (fbi->regbase == NULL) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + ret = -EBUSY; + goto failed_free_res; + } + + fb_videomode_to_var(&fbi->fb.var, &pdata->mode); + + fbi->fb.var.nonstd = 0; + fbi->fb.var.activate = FB_ACTIVATE_NOW; + + fbi->fb.var.height = -1; + fbi->fb.var.width = -1; + fbi->fb.var.xres_virtual = pdata->xres_virtual; + fbi->fb.var.yres_virtual = pdata->yres_virtual; + fbi->fb.var.bits_per_pixel = pdata->bpp; + + fbi->fb.fix.smem_start = pdata->video_mem_phys; + fbi->fb.fix.smem_len = pdata->video_mem_len; + fbi->fb.screen_base = pdata->video_mem_virt; + fbi->fb.screen_size = pdata->video_mem_len; + + if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) { + dev_err(&pdev->dev, "Failed to allocate color map\n"); + ret = -ENOMEM; + goto failed_free_io; + } + + wm8505fb_init_hw(&fbi->fb); + + fbi->contrast = 0x80; + ret = wm8505fb_set_par(&fbi->fb); + if (ret) { + dev_err(&pdev->dev, "Failed to set parameters\n"); + goto failed_free_cmap; + } + + platform_set_drvdata(pdev, fbi); + + ret = register_framebuffer(&fbi->fb); + if (ret < 0) { + dev_err(&pdev->dev, + "Failed to register framebuffer device: %d\n", ret); + goto failed_free_cmap; + } + + ret = device_create_file(&pdev->dev, &dev_attr_contrast); + if (ret < 0) { + printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n", + fbi->fb.node, ret); + } + + printk(KERN_INFO "fb%d: %s frame buffer at 0x%lx-0x%lx\n", + fbi->fb.node, fbi->fb.fix.id, fbi->fb.fix.smem_start, + fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1); + + return 0; + +failed_free_cmap: + if (fbi->fb.cmap.len) + fb_dealloc_cmap(&fbi->fb.cmap); +failed_free_io: + iounmap(fbi->regbase); +failed_free_res: + release_mem_region(res->start, resource_size(res)); +failed_fbi: + platform_set_drvdata(pdev, NULL); + kfree(fbi); +failed: + return ret; +} + +static int __devexit wm8505fb_remove(struct platform_device *pdev) +{ + struct wm8505fb_info *fbi = platform_get_drvdata(pdev); + struct resource *res; + + device_remove_file(&pdev->dev, &dev_attr_contrast); + + unregister_framebuffer(&fbi->fb); + + writel(0, fbi->regbase); + + if (fbi->fb.cmap.len) + fb_dealloc_cmap(&fbi->fb.cmap); + + iounmap(fbi->regbase); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(fbi); + + return 0; +} + +static struct platform_driver wm8505fb_driver = { + .probe = wm8505fb_probe, + .remove = __devexit_p(wm8505fb_remove), + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, +}; + +static int __init wm8505fb_init(void) +{ + return platform_driver_register(&wm8505fb_driver); +} + +static void __exit wm8505fb_exit(void) +{ + platform_driver_unregister(&wm8505fb_driver); +} + +module_init(wm8505fb_init); +module_exit(wm8505fb_exit); + +MODULE_AUTHOR("Ed Spiridonov "); +MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/wm8505fb_regs.h b/drivers/video/wm8505fb_regs.h new file mode 100644 index 000000000000..4dd41668c6d1 --- /dev/null +++ b/drivers/video/wm8505fb_regs.h @@ -0,0 +1,76 @@ +/* + * GOVR registers list for WM8505 chips + * + * Copyright (C) 2010 Ed Spiridonov + * Based on VIA/WonderMedia wm8510-govrh-reg.h + * http://github.com/projectgus/kernel_wm8505/blob/wm8505_2.6.29/ + * drivers/video/wmt/register/wm8510/wm8510-govrh-reg.h + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _WM8505FB_REGS_H +#define _WM8505FB_REGS_H + +/* + * Color space select register, default value 0x1c + * BIT0 GOVRH_DVO_YUV2RGB_ENABLE + * BIT1 GOVRH_VGA_YUV2RGB_ENABLE + * BIT2 GOVRH_RGB_MODE + * BIT3 GOVRH_DAC_CLKINV + * BIT4 GOVRH_BLANK_ZERO + */ +#define WMT_GOVR_COLORSPACE 0x1e4 +/* + * Another colorspace select register, default value 1 + * BIT0 GOVRH_DVO_RGB + * BIT1 GOVRH_DVO_YUV422 + */ +#define WMT_GOVR_COLORSPACE1 0x30 + +#define WMT_GOVR_CONTRAST 0x1b8 +#define WMT_GOVR_BRGHTNESS 0x1bc /* incompatible with RGB? */ + +/* Framubeffer address */ +#define WMT_GOVR_FBADDR 0x90 +#define WMT_GOVR_FBADDR1 0x94 /* UV offset in YUV mode */ + +/* Offset of visible window */ +#define WMT_GOVR_XPAN 0xa4 +#define WMT_GOVR_YPAN 0xa0 + +#define WMT_GOVR_XRES 0x98 +#define WMT_GOVR_XRES_VIRTUAL 0x9c + +#define WMT_GOVR_MIF_ENABLE 0x80 +#define WMT_GOVR_FHI 0xa8 +#define WMT_GOVR_REG_UPDATE 0xe4 + +/* + * BIT0 GOVRH_DVO_OUTWIDTH + * BIT1 GOVRH_DVO_SYNC_POLAR + * BIT2 GOVRH_DVO_ENABLE + */ +#define WMT_GOVR_DVO_SET 0x148 + +/* Timing generator? */ +#define WMT_GOVR_TG 0x100 + +/* Timings */ +#define WMT_GOVR_TIMING_H_ALL 0x108 +#define WMT_GOVR_TIMING_V_ALL 0x10c +#define WMT_GOVR_TIMING_V_START 0x110 +#define WMT_GOVR_TIMING_V_END 0x114 +#define WMT_GOVR_TIMING_H_START 0x118 +#define WMT_GOVR_TIMING_H_END 0x11c +#define WMT_GOVR_TIMING_V_SYNC 0x128 +#define WMT_GOVR_TIMING_H_SYNC 0x12c + +#endif /* _WM8505FB_REGS_H */ diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c new file mode 100644 index 000000000000..f31883f8eaf7 --- /dev/null +++ b/drivers/video/wmt_ge_rops.c @@ -0,0 +1,192 @@ +/* + * linux/drivers/video/wmt_ge_rops.c + * + * Accelerators for raster operations using WonderMedia Graphics Engine + * + * Copyright (C) 2010 Alexey Charkov + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include "fb_draw.h" + +#define GE_COMMAND_OFF 0x00 +#define GE_DEPTH_OFF 0x04 +#define GE_HIGHCOLOR_OFF 0x08 +#define GE_ROPCODE_OFF 0x14 +#define GE_FIRE_OFF 0x18 +#define GE_SRCBASE_OFF 0x20 +#define GE_SRCDISPW_OFF 0x24 +#define GE_SRCDISPH_OFF 0x28 +#define GE_SRCAREAX_OFF 0x2c +#define GE_SRCAREAY_OFF 0x30 +#define GE_SRCAREAW_OFF 0x34 +#define GE_SRCAREAH_OFF 0x38 +#define GE_DESTBASE_OFF 0x3c +#define GE_DESTDISPW_OFF 0x40 +#define GE_DESTDISPH_OFF 0x44 +#define GE_DESTAREAX_OFF 0x48 +#define GE_DESTAREAY_OFF 0x4c +#define GE_DESTAREAW_OFF 0x50 +#define GE_DESTAREAH_OFF 0x54 +#define GE_PAT0C_OFF 0x88 /* Pattern 0 color */ +#define GE_ENABLE_OFF 0xec +#define GE_INTEN_OFF 0xf0 +#define GE_STATUS_OFF 0xf8 + +static void __iomem *regbase; + +void wmt_ge_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + unsigned long fg, pat; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR) + fg = ((u32 *) (p->pseudo_palette))[rect->color]; + else + fg = rect->color; + + pat = pixel_to_pat(p->var.bits_per_pixel, fg); + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + writel(p->var.bits_per_pixel == 32 ? 3 : + (p->var.bits_per_pixel == 8 ? 0 : 1), regbase + GE_DEPTH_OFF); + writel(p->var.bits_per_pixel == 15 ? 1 : 0, regbase + GE_HIGHCOLOR_OFF); + writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF); + writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF); + writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF); + writel(rect->dx, regbase + GE_DESTAREAX_OFF); + writel(rect->dy, regbase + GE_DESTAREAY_OFF); + writel(rect->width - 1, regbase + GE_DESTAREAW_OFF); + writel(rect->height - 1, regbase + GE_DESTAREAH_OFF); + + writel(pat, regbase + GE_PAT0C_OFF); + writel(1, regbase + GE_COMMAND_OFF); + writel(rect->rop == ROP_XOR ? 0x5a : 0xf0, regbase + GE_ROPCODE_OFF); + writel(1, regbase + GE_FIRE_OFF); +} +EXPORT_SYMBOL_GPL(wmt_ge_fillrect); + +void wmt_ge_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + if (p->state != FBINFO_STATE_RUNNING) + return; + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + writel(p->var.bits_per_pixel > 16 ? 3 : + (p->var.bits_per_pixel > 8 ? 1 : 0), regbase + GE_DEPTH_OFF); + + writel(p->fix.smem_start, regbase + GE_SRCBASE_OFF); + writel(p->var.xres_virtual - 1, regbase + GE_SRCDISPW_OFF); + writel(p->var.yres_virtual - 1, regbase + GE_SRCDISPH_OFF); + writel(area->sx, regbase + GE_SRCAREAX_OFF); + writel(area->sy, regbase + GE_SRCAREAY_OFF); + writel(area->width - 1, regbase + GE_SRCAREAW_OFF); + writel(area->height - 1, regbase + GE_SRCAREAH_OFF); + + writel(p->fix.smem_start, regbase + GE_DESTBASE_OFF); + writel(p->var.xres_virtual - 1, regbase + GE_DESTDISPW_OFF); + writel(p->var.yres_virtual - 1, regbase + GE_DESTDISPH_OFF); + writel(area->dx, regbase + GE_DESTAREAX_OFF); + writel(area->dy, regbase + GE_DESTAREAY_OFF); + writel(area->width - 1, regbase + GE_DESTAREAW_OFF); + writel(area->height - 1, regbase + GE_DESTAREAH_OFF); + + writel(0xcc, regbase + GE_ROPCODE_OFF); + writel(1, regbase + GE_COMMAND_OFF); + writel(1, regbase + GE_FIRE_OFF); +} +EXPORT_SYMBOL_GPL(wmt_ge_copyarea); + +int wmt_ge_sync(struct fb_info *p) +{ + int loops = 5000000; + while ((readl(regbase + GE_STATUS_OFF) & 4) && --loops) + cpu_relax(); + return loops > 0 ? 0 : -EBUSY; +} +EXPORT_SYMBOL_GPL(wmt_ge_sync); + +static int __devinit wmt_ge_rops_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "no I/O memory resource defined\n"); + ret = -ENODEV; + goto error; + } + + /* Only one ROP engine is presently supported. */ + if (unlikely(regbase)) { + WARN_ON(1); + return -EBUSY; + } + + regbase = ioremap(res->start, resource_size(res)); + if (regbase == NULL) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + ret = -EBUSY; + goto error; + } + + writel(1, regbase + GE_ENABLE_OFF); + printk(KERN_INFO "Enabled support for WMT GE raster acceleration\n"); + + return 0; + +error: + return ret; +} + +static int __devexit wmt_ge_rops_remove(struct platform_device *pdev) +{ + iounmap(regbase); + return 0; +} + +static struct platform_driver wmt_ge_rops_driver = { + .probe = wmt_ge_rops_probe, + .remove = __devexit_p(wmt_ge_rops_remove), + .driver = { + .owner = THIS_MODULE, + .name = "wmt_ge_rops", + }, +}; + +static int __init wmt_ge_rops_init(void) +{ + return platform_driver_register(&wmt_ge_rops_driver); +} + +static void __exit wmt_ge_rops_exit(void) +{ + platform_driver_unregister(&wmt_ge_rops_driver); +} + +module_init(wmt_ge_rops_init); +module_exit(wmt_ge_rops_exit); + +MODULE_AUTHOR("Alexey Charkov Date: Tue, 9 Nov 2010 11:22:58 +0000 Subject: x86/mrst: Add SFI platform device parsing code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SFI provides a series of tables. These describe the platform devices present including SPI and I²C devices, as well as various sensors, keypads and other glue as well as interfaces provided via the SCU IPC mechanism (intel_scu_ipc.c) This patch is a merge of the core elements and relevant fixes from the Intel development code by Feng, Alek, myself into a single coherent patch for upstream submission. It provides the needed infrastructure to register I2C, SPI and platform devices described by the tables, as well as handlers for some of the hardware already supported in kernel. The 0.8 firmware also provides GPIO tables. Devices are created at boot time or if they are SCU dependant at the point an SCU is discovered. The existing Linux device mechanisms will then handle the device binding. At an abstract level this is an SFI to Linux device translator. Device/platform specific setup/glue is in this file. This is done so that the drivers for the generic I²C and SPI bus devices remain cross platform as they should. (Updated from RFC version to correct the emc1403 name used by the firmware and a wrongly used #define) Signed-off-by: Alek Du LKML-Reference: <20101109112158.20013.6158.stgit@localhost.localdomain> [Clean ups, removal of 0.7 support] Signed-off-by: Feng Tang [Clean ups] Signed-off-by: Alan Cox Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 2 + arch/x86/include/asm/mrst.h | 4 + arch/x86/platform/mrst/mrst.c | 515 ++++++++++++++++++++++++++++++++++- drivers/platform/x86/intel_scu_ipc.c | 5 + include/linux/sfi.h | 8 +- 5 files changed, 527 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e8327686d3c5..b306b84fc8c8 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -385,6 +385,8 @@ config X86_MRST depends on X86_EXTENDED_PLATFORM depends on X86_IO_APIC select APB_TIMER + select I2C + select SPI ---help--- Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin Internet Device(MID) platform. Moorestown consists of two chips: diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h index 4a711a684b17..283debd29fc0 100644 --- a/arch/x86/include/asm/mrst.h +++ b/arch/x86/include/asm/mrst.h @@ -50,4 +50,8 @@ extern void mrst_early_console_init(void); extern struct console early_hsu_console; extern void hsu_early_console_init(void); + +extern void intel_scu_devices_create(void); +extern void intel_scu_devices_destroy(void); + #endif /* _ASM_X86_MRST_H */ diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 79ae68154e87..cfa1af24edd5 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -9,9 +9,19 @@ * as published by the Free Software Foundation; version 2 * of the License. */ + +#define pr_fmt(fmt) "mrst: " fmt + #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -23,8 +33,10 @@ #include #include #include +#include #include + /* * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock, * cmdline option x86_mrst_timer can be used to override the configuration @@ -102,10 +114,10 @@ static int __init sfi_parse_mtmr(struct sfi_table_header *table) memcpy(sfi_mtimer_array, pentry, totallen); } - printk(KERN_INFO "SFI: MTIMER info (num = %d):\n", sfi_mtimer_num); + pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num); pentry = sfi_mtimer_array; for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) { - printk(KERN_INFO "timer[%d]: paddr = 0x%08x, freq = %dHz," + pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz," " irq = %d\n", totallen, (u32)pentry->phys_addr, pentry->freq_hz, pentry->irq); if (!pentry->irq) @@ -176,10 +188,10 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table) memcpy(sfi_mrtc_array, pentry, totallen); } - printk(KERN_INFO "SFI: RTC info (num = %d):\n", sfi_mrtc_num); + pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num); pentry = sfi_mrtc_array; for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) { - printk(KERN_INFO "RTC[%d]: paddr = 0x%08x, irq = %d\n", + pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n", totallen, (u32)pentry->phys_addr, pentry->irq); mp_irq.type = MP_IOAPIC; mp_irq.irqtype = mp_INT; @@ -309,3 +321,498 @@ static inline int __init setup_x86_mrst_timer(char *arg) return 0; } __setup("x86_mrst_timer=", setup_x86_mrst_timer); + +/* + * Parsing GPIO table first, since the DEVS table will need this table + * to map the pin name to the actual pin. + */ +static struct sfi_gpio_table_entry *gpio_table; +static int gpio_num_entry; + +static int __init sfi_parse_gpio(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb; + struct sfi_gpio_table_entry *pentry; + int num, i; + + if (gpio_table) + return 0; + sb = (struct sfi_table_simple *)table; + num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); + pentry = (struct sfi_gpio_table_entry *)sb->pentry; + + gpio_table = (struct sfi_gpio_table_entry *) + kmalloc(num * sizeof(*pentry), GFP_KERNEL); + if (!gpio_table) + return -1; + memcpy(gpio_table, pentry, num * sizeof(*pentry)); + gpio_num_entry = num; + + pr_debug("GPIO pin info:\n"); + for (i = 0; i < num; i++, pentry++) + pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s," + " pin = %d\n", i, + pentry->controller_name, + pentry->pin_name, + pentry->pin_no); + return 0; +} + +static int get_gpio_by_name(const char *name) +{ + struct sfi_gpio_table_entry *pentry = gpio_table; + int i; + + if (!pentry) + return -1; + for (i = 0; i < gpio_num_entry; i++, pentry++) { + if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN)) + return pentry->pin_no; + } + return -1; +} + +/* + * Here defines the array of devices platform data that IAFW would export + * through SFI "DEVS" table, we use name and type to match the device and + * its platform data. + */ +struct devs_id { + char name[SFI_NAME_LEN + 1]; + u8 type; + u8 delay; + void *(*get_platform_data)(void *info); +}; + +/* the offset for the mapping of global gpio pin to irq */ +#define MRST_IRQ_OFFSET 0x100 + +static void __init *pmic_gpio_platform_data(void *info) +{ + static struct intel_pmic_gpio_platform_data pmic_gpio_pdata; + int gpio_base = get_gpio_by_name("pmic_gpio_base"); + + if (gpio_base == -1) + gpio_base = 64; + pmic_gpio_pdata.gpio_base = gpio_base; + pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET; + pmic_gpio_pdata.gpiointr = 0xffffeff8; + + return &pmic_gpio_pdata; +} + +static void __init *max3111_platform_data(void *info) +{ + struct spi_board_info *spi_info = info; + int intr = get_gpio_by_name("max3111_int"); + + if (intr == -1) + return NULL; + spi_info->irq = intr + MRST_IRQ_OFFSET; + return NULL; +} + +/* we have multiple max7315 on the board ... */ +#define MAX7315_NUM 2 +static void __init *max7315_platform_data(void *info) +{ + static struct pca953x_platform_data max7315_pdata[MAX7315_NUM]; + static int nr; + struct pca953x_platform_data *max7315 = &max7315_pdata[nr]; + struct i2c_board_info *i2c_info = info; + int gpio_base, intr; + char base_pin_name[SFI_NAME_LEN + 1]; + char intr_pin_name[SFI_NAME_LEN + 1]; + + if (nr == MAX7315_NUM) { + pr_err("too many max7315s, we only support %d\n", + MAX7315_NUM); + return NULL; + } + /* we have several max7315 on the board, we only need load several + * instances of the same pca953x driver to cover them + */ + strcpy(i2c_info->type, "max7315"); + if (nr++) { + sprintf(base_pin_name, "max7315_%d_base", nr); + sprintf(intr_pin_name, "max7315_%d_int", nr); + } else { + strcpy(base_pin_name, "max7315_base"); + strcpy(intr_pin_name, "max7315_int"); + } + + gpio_base = get_gpio_by_name(base_pin_name); + intr = get_gpio_by_name(intr_pin_name); + + if (gpio_base == -1) + return NULL; + max7315->gpio_base = gpio_base; + if (intr != -1) { + i2c_info->irq = intr + MRST_IRQ_OFFSET; + max7315->irq_base = gpio_base + MRST_IRQ_OFFSET; + } else { + i2c_info->irq = -1; + max7315->irq_base = -1; + } + return max7315; +} + +static void __init *emc1403_platform_data(void *info) +{ + static short intr2nd_pdata; + struct i2c_board_info *i2c_info = info; + int intr = get_gpio_by_name("thermal_int"); + int intr2nd = get_gpio_by_name("thermal_alert"); + + if (intr == -1 || intr2nd == -1) + return NULL; + + i2c_info->irq = intr + MRST_IRQ_OFFSET; + intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; + + return &intr2nd_pdata; +} + +static void __init *lis331dl_platform_data(void *info) +{ + static short intr2nd_pdata; + struct i2c_board_info *i2c_info = info; + int intr = get_gpio_by_name("accel_int"); + int intr2nd = get_gpio_by_name("accel_2"); + + if (intr == -1 || intr2nd == -1) + return NULL; + + i2c_info->irq = intr + MRST_IRQ_OFFSET; + intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET; + + return &intr2nd_pdata; +} + +static const struct devs_id __initconst device_ids[] = { + {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, + {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, + {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, + {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, + {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data}, + {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, + {}, +}; + +#define MAX_IPCDEVS 24 +static struct platform_device *ipc_devs[MAX_IPCDEVS]; +static int ipc_next_dev; + +#define MAX_SCU_SPI 24 +static struct spi_board_info *spi_devs[MAX_SCU_SPI]; +static int spi_next_dev; + +#define MAX_SCU_I2C 24 +static struct i2c_board_info *i2c_devs[MAX_SCU_I2C]; +static int i2c_bus[MAX_SCU_I2C]; +static int i2c_next_dev; + +static void __init intel_scu_device_register(struct platform_device *pdev) +{ + if(ipc_next_dev == MAX_IPCDEVS) + pr_err("too many SCU IPC devices"); + else + ipc_devs[ipc_next_dev++] = pdev; +} + +static void __init intel_scu_spi_device_register(struct spi_board_info *sdev) +{ + struct spi_board_info *new_dev; + + if (spi_next_dev == MAX_SCU_SPI) { + pr_err("too many SCU SPI devices"); + return; + } + + new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL); + if (!new_dev) { + pr_err("failed to alloc mem for delayed spi dev %s\n", + sdev->modalias); + return; + } + memcpy(new_dev, sdev, sizeof(*sdev)); + + spi_devs[spi_next_dev++] = new_dev; +} + +static void __init intel_scu_i2c_device_register(int bus, + struct i2c_board_info *idev) +{ + struct i2c_board_info *new_dev; + + if (i2c_next_dev == MAX_SCU_I2C) { + pr_err("too many SCU I2C devices"); + return; + } + + new_dev = kzalloc(sizeof(*idev), GFP_KERNEL); + if (!new_dev) { + pr_err("failed to alloc mem for delayed i2c dev %s\n", + idev->type); + return; + } + memcpy(new_dev, idev, sizeof(*idev)); + + i2c_bus[i2c_next_dev] = bus; + i2c_devs[i2c_next_dev++] = new_dev; +} + +/* Called by IPC driver */ +void intel_scu_devices_create(void) +{ + int i; + + for (i = 0; i < ipc_next_dev; i++) + platform_device_add(ipc_devs[i]); + + for (i = 0; i < spi_next_dev; i++) + spi_register_board_info(spi_devs[i], 1); + + for (i = 0; i < i2c_next_dev; i++) { + struct i2c_adapter *adapter; + struct i2c_client *client; + + adapter = i2c_get_adapter(i2c_bus[i]); + if (adapter) { + client = i2c_new_device(adapter, i2c_devs[i]); + if (!client) + pr_err("can't create i2c device %s\n", + i2c_devs[i]->type); + } else + i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1); + } +} +EXPORT_SYMBOL_GPL(intel_scu_devices_create); + +/* Called by IPC driver */ +void intel_scu_devices_destroy(void) +{ + int i; + + for (i = 0; i < ipc_next_dev; i++) + platform_device_del(ipc_devs[i]); +} +EXPORT_SYMBOL_GPL(intel_scu_devices_destroy); + +static void __init install_irq_resource(struct platform_device *pdev, int irq) +{ + /* Single threaded */ + static struct resource __initdata res = { + .name = "IRQ", + .flags = IORESOURCE_IRQ, + }; + res.start = irq; + platform_device_add_resources(pdev, &res, 1); +} + +static void __init sfi_handle_ipc_dev(struct platform_device *pdev) +{ + const struct devs_id *dev = device_ids; + void *pdata = NULL; + + while (dev->name[0]) { + if (dev->type == SFI_DEV_TYPE_IPC && + !strncmp(dev->name, pdev->name, SFI_NAME_LEN)) { + pdata = dev->get_platform_data(pdev); + break; + } + dev++; + } + pdev->dev.platform_data = pdata; + intel_scu_device_register(pdev); +} + +static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info) +{ + const struct devs_id *dev = device_ids; + void *pdata = NULL; + + while (dev->name[0]) { + if (dev->type == SFI_DEV_TYPE_SPI && + !strncmp(dev->name, spi_info->modalias, SFI_NAME_LEN)) { + pdata = dev->get_platform_data(spi_info); + break; + } + dev++; + } + spi_info->platform_data = pdata; + if (dev->delay) + intel_scu_spi_device_register(spi_info); + else + spi_register_board_info(spi_info, 1); +} + +static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) +{ + const struct devs_id *dev = device_ids; + void *pdata = NULL; + + while (dev->name[0]) { + if (dev->type == SFI_DEV_TYPE_I2C && + !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) { + pdata = dev->get_platform_data(i2c_info); + break; + } + dev++; + } + i2c_info->platform_data = pdata; + + if (dev->delay) + intel_scu_i2c_device_register(bus, i2c_info); + else + i2c_register_board_info(bus, i2c_info, 1); + } + + +static int __init sfi_parse_devs(struct sfi_table_header *table) +{ + struct sfi_table_simple *sb; + struct sfi_device_table_entry *pentry; + struct spi_board_info spi_info; + struct i2c_board_info i2c_info; + struct platform_device *pdev; + int num, i, bus; + int ioapic; + struct io_apic_irq_attr irq_attr; + + sb = (struct sfi_table_simple *)table; + num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); + pentry = (struct sfi_device_table_entry *)sb->pentry; + + for (i = 0; i < num; i++, pentry++) { + if (pentry->irq != (u8)0xff) { /* native RTE case */ + /* these SPI2 devices are not exposed to system as PCI + * devices, but they have separate RTE entry in IOAPIC + * so we have to enable them one by one here + */ + ioapic = mp_find_ioapic(pentry->irq); + irq_attr.ioapic = ioapic; + irq_attr.ioapic_pin = pentry->irq; + irq_attr.trigger = 1; + irq_attr.polarity = 1; + io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr); + } + switch (pentry->type) { + case SFI_DEV_TYPE_IPC: + /* ID as IRQ is a hack that will go away */ + pdev = platform_device_alloc(pentry->name, pentry->irq); + if (pdev == NULL) { + pr_err("out of memory for SFI platform device '%s'.\n", + pentry->name); + continue; + } + install_irq_resource(pdev, pentry->irq); + pr_debug("info[%2d]: IPC bus, name = %16.16s, " + "irq = 0x%2x\n", i, pentry->name, pentry->irq); + sfi_handle_ipc_dev(pdev); + break; + case SFI_DEV_TYPE_SPI: + memset(&spi_info, 0, sizeof(spi_info)); + strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); + spi_info.irq = pentry->irq; + spi_info.bus_num = pentry->host_num; + spi_info.chip_select = pentry->addr; + spi_info.max_speed_hz = pentry->max_freq; + pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, " + "irq = 0x%2x, max_freq = %d, cs = %d\n", i, + spi_info.bus_num, + spi_info.modalias, + spi_info.irq, + spi_info.max_speed_hz, + spi_info.chip_select); + sfi_handle_spi_dev(&spi_info); + break; + case SFI_DEV_TYPE_I2C: + memset(&i2c_info, 0, sizeof(i2c_info)); + bus = pentry->host_num; + strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); + i2c_info.irq = pentry->irq; + i2c_info.addr = pentry->addr; + pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " + "irq = 0x%2x, addr = 0x%x\n", i, bus, + i2c_info.type, + i2c_info.irq, + i2c_info.addr); + sfi_handle_i2c_dev(bus, &i2c_info); + break; + case SFI_DEV_TYPE_UART: + case SFI_DEV_TYPE_HSI: + default: + ; + } + } + return 0; +} + +static int __init mrst_platform_init(void) +{ + sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); + sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); + return 0; +} +arch_initcall(mrst_platform_init); + +/* + * we will search these buttons in SFI GPIO table (by name) + * and register them dynamically. Please add all possible + * buttons here, we will shrink them if no GPIO found. + */ +static struct gpio_keys_button gpio_button[] = { + {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000}, + {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20}, + {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20}, + {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20}, + {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20}, + {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20}, + {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20}, + {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20}, + {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20}, + {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20}, +}; + +static struct gpio_keys_platform_data mrst_gpio_keys = { + .buttons = gpio_button, + .rep = 1, + .nbuttons = -1, /* will fill it after search */ +}; + +static struct platform_device pb_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &mrst_gpio_keys, + }, +}; + +/* + * Shrink the non-existent buttons, register the gpio button + * device if there is some + */ +static int __init pb_keys_init(void) +{ + struct gpio_keys_button *gb = gpio_button; + int i, num, good = 0; + + num = sizeof(gpio_button) / sizeof(struct gpio_keys_button); + for (i = 0; i < num; i++) { + gb[i].gpio = get_gpio_by_name(gb[i].desc); + if (gb[i].gpio == -1) + continue; + + if (i != good) + gb[good] = gb[i]; + good++; + } + + if (good) { + mrst_gpio_keys.nbuttons = good; + return platform_device_register(&pb_device); + } + return 0; +} +late_initcall(pb_keys_init); diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 41a9e34899ac..ca35b0ce944a 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -26,6 +26,7 @@ #include #include #include +#include /* IPC defines the following message types */ #define IPCMSG_WATCHDOG_TIMER 0xF8 /* Set Kernel Watchdog Threshold */ @@ -699,6 +700,9 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) iounmap(ipcdev.ipc_base); return -ENOMEM; } + + intel_scu_devices_create(); + return 0; } @@ -720,6 +724,7 @@ static void ipc_remove(struct pci_dev *pdev) iounmap(ipcdev.ipc_base); iounmap(ipcdev.i2c_base); ipcdev.pdev = NULL; + intel_scu_devices_destroy(); } static const struct pci_device_id pci_ids[] = { diff --git a/include/linux/sfi.h b/include/linux/sfi.h index 7f770c638e99..fe817918b30e 100644 --- a/include/linux/sfi.h +++ b/include/linux/sfi.h @@ -77,6 +77,8 @@ #define SFI_OEM_ID_SIZE 6 #define SFI_OEM_TABLE_ID_SIZE 8 +#define SFI_NAME_LEN 16 + #define SFI_SYST_SEARCH_BEGIN 0x000E0000 #define SFI_SYST_SEARCH_END 0x000FFFFF @@ -156,13 +158,13 @@ struct sfi_device_table_entry { u16 addr; u8 irq; u32 max_freq; - char name[16]; + char name[SFI_NAME_LEN]; } __packed; struct sfi_gpio_table_entry { - char controller_name[16]; + char controller_name[SFI_NAME_LEN]; u16 pin_no; - char pin_name[16]; + char pin_name[SFI_NAME_LEN]; } __packed; typedef int (*sfi_table_handler) (struct sfi_table_header *table); -- cgit v1.2.3 From 751305d9b2fd3e03eaab7808e976241d85ca4353 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 28 Oct 2010 18:23:01 +0100 Subject: viafb: General power management infrastructure Multiple devices need S/R hooks (framebuffer, GPIO, camera). Add infrastructure and convert existing framebuffer code to the new model. This patch should create no functional change. Based on earlier work by Jonathan Corbet. Signed-off-by: Daniel Drake Acked-by: Jonathan Corbet Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/via-core.c | 79 ++++++++++++++++++++++++++++++++++++++++++-- drivers/video/via/viafbdev.c | 34 +++++++++---------- drivers/video/via/viafbdev.h | 2 -- include/linux/via-core.h | 15 +++++++++ 4 files changed, 107 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 31e30338e893..42be3d955887 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include /* * The default port config. @@ -563,6 +565,78 @@ static void via_teardown_subdevs(void) } } +/* + * Power management functions + */ +#ifdef CONFIG_PM +static LIST_HEAD(viafb_pm_hooks); +static DEFINE_MUTEX(viafb_pm_hooks_lock); + +void viafb_pm_register(struct viafb_pm_hooks *hooks) +{ + INIT_LIST_HEAD(&hooks->list); + + mutex_lock(&viafb_pm_hooks_lock); + list_add_tail(&hooks->list, &viafb_pm_hooks); + mutex_unlock(&viafb_pm_hooks_lock); +} +EXPORT_SYMBOL_GPL(viafb_pm_register); + +void viafb_pm_unregister(struct viafb_pm_hooks *hooks) +{ + mutex_lock(&viafb_pm_hooks_lock); + list_del(&hooks->list); + mutex_unlock(&viafb_pm_hooks_lock); +} +EXPORT_SYMBOL_GPL(viafb_pm_unregister); + +static int via_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct viafb_pm_hooks *hooks; + + if (state.event != PM_EVENT_SUSPEND) + return 0; + /* + * "I've occasionally hit a few drivers that caused suspend + * failures, and each and every time it was a driver bug, and + * the right thing to do was to just ignore the error and suspend + * anyway - returning an error code and trying to undo the suspend + * is not what anybody ever really wants, even if our model + *_allows_ for it." + * -- Linus Torvalds, Dec. 7, 2009 + */ + mutex_lock(&viafb_pm_hooks_lock); + list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list) + hooks->suspend(hooks->private); + mutex_unlock(&viafb_pm_hooks_lock); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int via_resume(struct pci_dev *pdev) +{ + struct viafb_pm_hooks *hooks; + + /* Get the bus side powered up */ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + if (pci_enable_device(pdev)) + return 0; + + pci_set_master(pdev); + + /* Now bring back any subdevs */ + mutex_lock(&viafb_pm_hooks_lock); + list_for_each_entry(hooks, &viafb_pm_hooks, list) + hooks->resume(hooks->private); + mutex_unlock(&viafb_pm_hooks_lock); + + return 0; +} +#endif /* CONFIG_PM */ static int __devinit via_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -572,6 +646,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, ret = pci_enable_device(pdev); if (ret) return ret; + /* * Global device initialization. */ @@ -651,8 +726,8 @@ static struct pci_driver via_driver = { .probe = via_pci_probe, .remove = __devexit_p(via_pci_remove), #ifdef CONFIG_PM - .suspend = viafb_suspend, - .resume = viafb_resume, + .suspend = via_suspend, + .resume = via_resume, #endif }; diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index d298cfccd6fc..289edd519527 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1672,31 +1672,19 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) #ifdef CONFIG_PM -int viafb_suspend(struct pci_dev *pdev, pm_message_t state) +static int viafb_suspend(void *unused) { - if (state.event == PM_EVENT_SUSPEND) { - acquire_console_sem(); - fb_set_suspend(viafbinfo, 1); - - viafb_sync(viafbinfo); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - release_console_sem(); - } + acquire_console_sem(); + fb_set_suspend(viafbinfo, 1); + viafb_sync(viafbinfo); + release_console_sem(); return 0; } -int viafb_resume(struct pci_dev *pdev) +static int viafb_resume(void *unused) { acquire_console_sem(); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - if (pci_enable_device(pdev)) - goto fail; - pci_set_master(pdev); if (viaparinfo->shared->vdev->engine_mmio) viafb_reset_engine(viaparinfo); viafb_set_par(viafbinfo); @@ -1704,11 +1692,15 @@ int viafb_resume(struct pci_dev *pdev) viafb_set_par(viafbinfo1); fb_set_suspend(viafbinfo, 0); -fail: release_console_sem(); return 0; } +static struct viafb_pm_hooks viafb_fb_pm_hooks = { + .suspend = viafb_suspend, + .resume = viafb_resume +}; + #endif @@ -1899,6 +1891,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) viafb_init_proc(viaparinfo->shared); viafb_init_dac(IGA2); + +#ifdef CONFIG_PM + viafb_pm_register(&viafb_fb_pm_hooks); +#endif return 0; out_fb_unreg: diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 4960e3da6645..d66f963e930e 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -108,6 +108,4 @@ void via_fb_pci_remove(struct pci_dev *pdev); /* Temporary */ int viafb_init(void); void viafb_exit(void); -int viafb_suspend(struct pci_dev *pdev, pm_message_t state); -int viafb_resume(struct pci_dev *pdev); #endif /* __VIAFBDEV_H__ */ diff --git a/include/linux/via-core.h b/include/linux/via-core.h index 7ffb521e1a7a..a4327a0c8efc 100644 --- a/include/linux/via-core.h +++ b/include/linux/via-core.h @@ -59,6 +59,21 @@ struct via_port_cfg { u8 ioport_index; }; +/* + * Allow subdevs to register suspend/resume hooks. + */ +#ifdef CONFIG_PM +struct viafb_pm_hooks { + struct list_head list; + int (*suspend)(void *private); + int (*resume)(void *private); + void *private; +}; + +void viafb_pm_register(struct viafb_pm_hooks *hooks); +void viafb_pm_unregister(struct viafb_pm_hooks *hooks); +#endif /* CONFIG_PM */ + /* * This is the global viafb "device" containing stuff needed by * all subdevs. -- cgit v1.2.3 From 67eb6f9617a24dfb033b584d6b1b42b39cc9297a Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Thu, 28 Oct 2010 18:23:21 +0100 Subject: viafb: suspend/resume for GPIOs Be sure to re-enable GPIO lines on resume. Users still have to be sure to set them properly. Signed-off-by: Jonathan Corbet Signed-off-by: Daniel Drake Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/via-gpio.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c index 39acb37e7a1d..c2a0a1cfd3b3 100644 --- a/drivers/video/via/via-gpio.c +++ b/drivers/video/via/via-gpio.c @@ -172,6 +172,28 @@ static void viafb_gpio_disable(struct viafb_gpio *gpio) via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); } +#ifdef CONFIG_PM + +static int viafb_gpio_suspend(void *private) +{ + return 0; +} + +static int viafb_gpio_resume(void *private) +{ + int i; + + for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2) + viafb_gpio_enable(gpio_config.active_gpios[i]); + return 0; +} + +static struct viafb_pm_hooks viafb_gpio_pm_hooks = { + .suspend = viafb_gpio_suspend, + .resume = viafb_gpio_resume +}; +#endif /* CONFIG_PM */ + /* * Look up a specific gpio and return the number it was assigned. */ @@ -236,6 +258,9 @@ static __devinit int viafb_gpio_probe(struct platform_device *platdev) printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); gpio_config.gpio_chip.ngpio = 0; } +#ifdef CONFIG_PM + viafb_pm_register(&viafb_gpio_pm_hooks); +#endif return ret; } @@ -245,6 +270,10 @@ static int viafb_gpio_remove(struct platform_device *platdev) unsigned long flags; int ret = 0, i; +#ifdef CONFIG_PM + viafb_pm_unregister(&viafb_gpio_pm_hooks); +#endif + /* * Get unregistered. */ -- cgit v1.2.3 From b884a94ed16d1a633e76f80fb1bd75d0e7373ce3 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 21 Sep 2010 16:37:26 +0100 Subject: viafb: Add OLPC XO-1.5 port configs The OLPC XO-1.5 does not use the standard port wiring suggested in the viafb driver. This is required for the upcoming OLPC DCON and via-camera drivers, to be submitted soon. Signed-off-by: Daniel Drake [fts: removed useless ifdef's and corrected comment] Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/via-core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 42be3d955887..86bd7197f366 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -17,6 +17,7 @@ #include #include #include +#include /* * The default port config. @@ -30,6 +31,19 @@ static struct via_port_cfg adap_configs[] = { { 0, 0, 0, 0 } }; +/* + * The OLPC XO-1.5 puts the camera power and reset lines onto + * GPIO 2C. + */ +static const struct via_port_cfg olpc_adap_configs[] = { + [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 }, + [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, + [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, + [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x2c }, + [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d }, + { 0, 0, 0, 0 } +}; + /* * We currently only support one viafb device (will there ever be * more than one?), so just declare it globally here. @@ -654,6 +668,9 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, global_dev.pdev = pdev; global_dev.chip_type = ent->driver_data; global_dev.port_cfg = adap_configs; + if (machine_is_olpc()) + global_dev.port_cfg = olpc_adap_configs; + spin_lock_init(&global_dev.reg_lock); ret = via_pci_setup_mmio(&global_dev); if (ret) -- cgit v1.2.3 From c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 3 Nov 2010 22:49:35 +0000 Subject: drivers/net: normalize TX_TIMEOUT Some network drivers use old TX_TIMEOUT definitions, assuming HZ=100 of old kernels. Convert these definitions to include HZ, since HZ can be 1000 these days. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/3c507.c | 2 +- drivers/net/3c515.c | 2 +- drivers/net/82596.c | 2 +- drivers/net/arm/w90p910_ether.c | 2 +- drivers/net/at1700.c | 2 +- drivers/net/atarilance.c | 2 +- drivers/net/eepro.c | 2 +- drivers/net/lance.c | 2 +- drivers/net/lib82596.c | 2 +- drivers/net/znet.c | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index ea9b7a098c9b..475a66d95b34 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -201,7 +201,7 @@ struct net_local { #define RX_BUF_SIZE (1518+14+18) /* packet+header+RBD */ #define RX_BUF_END (dev->mem_end - dev->mem_start) -#define TX_TIMEOUT 5 +#define TX_TIMEOUT (HZ/20) /* That's it: only 86 bytes to set up the beast, including every extra diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index cdf7226a7c43..d2bb4b254c57 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -98,7 +98,7 @@ static int rx_nocopy, rx_copy, queued_packet; #define WAIT_TX_AVAIL 200 /* Operational parameter that usually are not changed. */ -#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */ +#define TX_TIMEOUT ((4*HZ)/10) /* Time in jiffies before concluding Tx hung */ /* The size here is somewhat misleading: the Corkscrew also uses the ISA aliased registers at +0x400. diff --git a/drivers/net/82596.c b/drivers/net/82596.c index e2c9c5b949f9..be1f1970c842 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -191,7 +191,7 @@ enum commands { #define RX_SUSPEND 0x0030 #define RX_ABORT 0x0040 -#define TX_TIMEOUT 5 +#define TX_TIMEOUT (HZ/20) struct i596_reg { diff --git a/drivers/net/arm/w90p910_ether.c b/drivers/net/arm/w90p910_ether.c index 4545d5a06c24..bfea499a3513 100644 --- a/drivers/net/arm/w90p910_ether.c +++ b/drivers/net/arm/w90p910_ether.c @@ -117,7 +117,7 @@ #define TX_DESC_SIZE 10 #define MAX_RBUFF_SZ 0x600 #define MAX_TBUFF_SZ 0x600 -#define TX_TIMEOUT 50 +#define TX_TIMEOUT (HZ/2) #define DELAY 1000 #define CAM0 0x0 diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 89876897a6fe..871b1633f543 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -150,7 +150,7 @@ struct net_local { #define PORT_OFFSET(o) (o) -#define TX_TIMEOUT 10 +#define TX_TIMEOUT (HZ/10) /* Index to functions, as function prototypes. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 8cb27cb7bca1..ce0091eb06f5 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -116,7 +116,7 @@ MODULE_LICENSE("GPL"); #define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5) #define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define TX_TIMEOUT 20 +#define TX_TIMEOUT (HZ/5) /* The LANCE Rx and Tx ring descriptors. */ struct lance_rx_head { diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 7c826319ee5a..9e19fbc2f176 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -302,7 +302,7 @@ struct eepro_local { #define ee_id_eepro10p0 0x10 /* ID for eepro/10+ */ #define ee_id_eepro10p1 0x31 -#define TX_TIMEOUT 40 +#define TX_TIMEOUT ((4*HZ)/10) /* Index to functions, as function prototypes. */ diff --git a/drivers/net/lance.c b/drivers/net/lance.c index f06296bfe293..02336edce748 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -207,7 +207,7 @@ tx_full and tbusy flags. #define LANCE_BUS_IF 0x16 #define LANCE_TOTAL_SIZE 0x18 -#define TX_TIMEOUT 20 +#define TX_TIMEOUT (HZ/5) /* The LANCE Rx and Tx ring descriptors. */ struct lance_rx_head { diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index c27f4291b350..9e042894479b 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -161,7 +161,7 @@ enum commands { #define RX_SUSPEND 0x0030 #define RX_ABORT 0x0040 -#define TX_TIMEOUT 5 +#define TX_TIMEOUT (HZ/20) struct i596_reg { diff --git a/drivers/net/znet.c b/drivers/net/znet.c index c3a329204511..ae07b3dfbcc1 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -124,7 +124,7 @@ MODULE_LICENSE("GPL"); #define TX_BUF_SIZE 8192 #define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */ -#define TX_TIMEOUT 10 +#define TX_TIMEOUT (HZ/10) struct znet_private { int rx_dma, tx_dma; -- cgit v1.2.3 From c389ff80d4b598f57d56aa807d396d4351cac8a4 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 11:08:33 +0000 Subject: drivers/net/can: Update WARN uses Add missing newlines. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/can/mscan/mscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 64c378cd0c34..74cd880c7e06 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -182,7 +182,7 @@ static int mscan_restart(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; WARN(!(in_8(®s->canmisc) & MSCAN_BOHOLD), - "bus-off state expected"); + "bus-off state expected\n"); out_8(®s->canmisc, MSCAN_BOHOLD); /* Re-enable receive interrupts. */ out_8(®s->canrier, MSCAN_RX_INTS_ENABLE); -- cgit v1.2.3 From 9c413ed55d5b52159e85a3937cda7f210a318048 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 30 Oct 2010 11:08:34 +0000 Subject: drivers/net/usb: Update WARN uses Add missing newlines. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index b2bcf99e6f08..7d42f9a2c068 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -363,7 +363,7 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net) /* Paranoid */ if (skb->len > IPHETH_BUF_SIZE) { - WARN(1, "%s: skb too large: %d bytes", __func__, skb->len); + WARN(1, "%s: skb too large: %d bytes\n", __func__, skb->len); dev->net->stats.tx_dropped++; dev_kfree_skb_irq(skb); return NETDEV_TX_OK; -- cgit v1.2.3 From 038aaa382eb0a8fd6a0bbae7abc1383b9b57c543 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 14 Oct 2010 23:01:02 +0200 Subject: b43: N-PHY: define channel table struct for rev3+ devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2056.c | 51 +++++++++++++++++++++++++++++++++++ drivers/net/wireless/b43/radio_2056.h | 40 ++++++++++++++++++++++++--- 2 files changed, 88 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c index d8563192ce56..f710c01f2cc4 100644 --- a/drivers/net/wireless/b43/radio_2056.c +++ b/drivers/net/wireless/b43/radio_2056.c @@ -24,9 +24,60 @@ #include "radio_2056.h" #include "phy_common.h" +#define RADIOREGS3(r00, r01, r02, r03, r04, r05, r06, r07, r08, r09, \ + r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, \ + r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, \ + r30, r31, r32, r33, r34, r35, r36) \ + .radio_syn_pll_vcocal1 = r00, \ + .radio_syn_pll_vcocal2 = r01, \ + .radio_syn_pll_refdiv = r02, \ + .radio_syn_pll_mmd2 = r03, \ + .radio_syn_pll_mmd1 = r04, \ + .radio_syn_pll_loopfilter1 = r05, \ + .radio_syn_pll_loopfilter2 = r06, \ + .radio_syn_pll_loopfilter3 = r07, \ + .radio_syn_pll_loopfilter4 = r08, \ + .radio_syn_pll_loopfilter5 = r09, \ + .radio_syn_reserved_addr27 = r10, \ + .radio_syn_reserved_addr28 = r11, \ + .radio_syn_reserved_addr29 = r12, \ + .radio_syn_logen_vcobuf1 = r13, \ + .radio_syn_logen_mixer2 = r14, \ + .radio_syn_logen_buf3 = r15, \ + .radio_syn_logen_buf4 = r16, \ + .radio_rx0_lnaa_tune = r17, \ + .radio_rx0_lnag_tune = r18, \ + .radio_tx0_intpaa_boost_tune = r19, \ + .radio_tx0_intpag_boost_tune = r20, \ + .radio_tx0_pada_boost_tune = r21, \ + .radio_tx0_padg_boost_tune = r22, \ + .radio_tx0_pgaa_boost_tune = r23, \ + .radio_tx0_pgag_boost_tune = r24, \ + .radio_tx0_mixa_boost_tune = r25, \ + .radio_tx0_mixg_boost_tune = r26, \ + .radio_rx1_lnaa_tune = r27, \ + .radio_rx1_lnag_tune = r28, \ + .radio_tx1_intpaa_boost_tune = r29, \ + .radio_tx1_intpag_boost_tune = r30, \ + .radio_tx1_pada_boost_tune = r31, \ + .radio_tx1_padg_boost_tune = r32, \ + .radio_tx1_pgaa_boost_tune = r33, \ + .radio_tx1_pgag_boost_tune = r34, \ + .radio_tx1_mixa_boost_tune = r35, \ + .radio_tx1_mixg_boost_tune = r36 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_regs.phy_bw1a = r0, \ + .phy_regs.phy_bw2 = r1, \ + .phy_regs.phy_bw3 = r2, \ + .phy_regs.phy_bw4 = r3, \ + .phy_regs.phy_bw5 = r4, \ + .phy_regs.phy_bw6 = r5 + static const struct b43_nphy_channeltab_entry_rev3 b43_nphy_channeltab_rev3[] = { }; +/* TODO: add support for rev4+ devices by searching in rev4+ tables */ const struct b43_nphy_channeltab_entry_rev3 * b43_nphy_get_chantabent_rev3(struct b43_wldev *dev, u16 freq) { diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h index fda6dafecb8c..60341d7ae673 100644 --- a/drivers/net/wireless/b43/radio_2056.h +++ b/drivers/net/wireless/b43/radio_2056.h @@ -29,12 +29,46 @@ #include "tables_nphy.h" struct b43_nphy_channeltab_entry_rev3 { - /* The channel number */ - u8 channel; /* The channel frequency in MHz */ u16 freq; /* Radio register values on channelswitch */ - /* TODO */ + u8 radio_syn_pll_vcocal1; + u8 radio_syn_pll_vcocal2; + u8 radio_syn_pll_refdiv; + u8 radio_syn_pll_mmd2; + u8 radio_syn_pll_mmd1; + u8 radio_syn_pll_loopfilter1; + u8 radio_syn_pll_loopfilter2; + u8 radio_syn_pll_loopfilter3; + u8 radio_syn_pll_loopfilter4; + u8 radio_syn_pll_loopfilter5; + u8 radio_syn_reserved_addr27; + u8 radio_syn_reserved_addr28; + u8 radio_syn_reserved_addr29; + u8 radio_syn_logen_vcobuf1; + u8 radio_syn_logen_mixer2; + u8 radio_syn_logen_buf3; + u8 radio_syn_logen_buf4; + u8 radio_rx0_lnaa_tune; + u8 radio_rx0_lnag_tune; + u8 radio_tx0_intpaa_boost_tune; + u8 radio_tx0_intpag_boost_tune; + u8 radio_tx0_pada_boost_tune; + u8 radio_tx0_padg_boost_tune; + u8 radio_tx0_pgaa_boost_tune; + u8 radio_tx0_pgag_boost_tune; + u8 radio_tx0_mixa_boost_tune; + u8 radio_tx0_mixg_boost_tune; + u8 radio_rx1_lnaa_tune; + u8 radio_rx1_lnag_tune; + u8 radio_tx1_intpaa_boost_tune; + u8 radio_tx1_intpag_boost_tune; + u8 radio_tx1_pada_boost_tune; + u8 radio_tx1_padg_boost_tune; + u8 radio_tx1_pgaa_boost_tune; + u8 radio_tx1_pgag_boost_tune; + u8 radio_tx1_mixa_boost_tune; + u8 radio_tx1_mixg_boost_tune; /* PHY register values on channelswitch */ struct b43_phy_n_sfo_cfg phy_regs; }; -- cgit v1.2.3 From 794830e691a6b61d2de3fa9daeb609fd4ef4a4e7 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sun, 17 Oct 2010 15:38:51 +0200 Subject: b43: N-PHY: define registers names for 2056 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Cc: Henry Ptasinski Cc: Brett Rudley Cc: Nohee Ko Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2056.h | 522 ++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h index 60341d7ae673..6b3264774adf 100644 --- a/drivers/net/wireless/b43/radio_2056.h +++ b/drivers/net/wireless/b43/radio_2056.h @@ -4,6 +4,9 @@ Copyright (c) 2010 Rafał Miłecki + Some parts of the code in this file are derived from the brcm80211 + driver Copyright (c) 2010 Broadcom Corporation + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -28,6 +31,525 @@ #include "tables_nphy.h" +#define B2056_SYN (0x0 << 12) +#define B2056_TX0 (0x2 << 12) +#define B2056_TX1 (0x3 << 12) +#define B2056_RX0 (0x6 << 12) +#define B2056_RX1 (0x7 << 12) +#define B2056_ALLTX (0xE << 12) +#define B2056_ALLRX (0xF << 12) + +#define B2056_SYN_RESERVED_ADDR0 0x00 +#define B2056_SYN_IDCODE 0x01 +#define B2056_SYN_RESERVED_ADDR2 0x02 +#define B2056_SYN_RESERVED_ADDR3 0x03 +#define B2056_SYN_RESERVED_ADDR4 0x04 +#define B2056_SYN_RESERVED_ADDR5 0x05 +#define B2056_SYN_RESERVED_ADDR6 0x06 +#define B2056_SYN_RESERVED_ADDR7 0x07 +#define B2056_SYN_COM_CTRL 0x08 +#define B2056_SYN_COM_PU 0x09 +#define B2056_SYN_COM_OVR 0x0A +#define B2056_SYN_COM_RESET 0x0B +#define B2056_SYN_COM_RCAL 0x0C +#define B2056_SYN_COM_RC_RXLPF 0x0D +#define B2056_SYN_COM_RC_TXLPF 0x0E +#define B2056_SYN_COM_RC_RXHPF 0x0F +#define B2056_SYN_RESERVED_ADDR16 0x10 +#define B2056_SYN_RESERVED_ADDR17 0x11 +#define B2056_SYN_RESERVED_ADDR18 0x12 +#define B2056_SYN_RESERVED_ADDR19 0x13 +#define B2056_SYN_RESERVED_ADDR20 0x14 +#define B2056_SYN_RESERVED_ADDR21 0x15 +#define B2056_SYN_RESERVED_ADDR22 0x16 +#define B2056_SYN_RESERVED_ADDR23 0x17 +#define B2056_SYN_RESERVED_ADDR24 0x18 +#define B2056_SYN_RESERVED_ADDR25 0x19 +#define B2056_SYN_RESERVED_ADDR26 0x1A +#define B2056_SYN_RESERVED_ADDR27 0x1B +#define B2056_SYN_RESERVED_ADDR28 0x1C +#define B2056_SYN_RESERVED_ADDR29 0x1D +#define B2056_SYN_RESERVED_ADDR30 0x1E +#define B2056_SYN_RESERVED_ADDR31 0x1F +#define B2056_SYN_GPIO_MASTER1 0x20 +#define B2056_SYN_GPIO_MASTER2 0x21 +#define B2056_SYN_TOPBIAS_MASTER 0x22 +#define B2056_SYN_TOPBIAS_RCAL 0x23 +#define B2056_SYN_AFEREG 0x24 +#define B2056_SYN_TEMPPROCSENSE 0x25 +#define B2056_SYN_TEMPPROCSENSEIDAC 0x26 +#define B2056_SYN_TEMPPROCSENSERCAL 0x27 +#define B2056_SYN_LPO 0x28 +#define B2056_SYN_VDDCAL_MASTER 0x29 +#define B2056_SYN_VDDCAL_IDAC 0x2A +#define B2056_SYN_VDDCAL_STATUS 0x2B +#define B2056_SYN_RCAL_MASTER 0x2C +#define B2056_SYN_RCAL_CODE_OUT 0x2D +#define B2056_SYN_RCCAL_CTRL0 0x2E +#define B2056_SYN_RCCAL_CTRL1 0x2F +#define B2056_SYN_RCCAL_CTRL2 0x30 +#define B2056_SYN_RCCAL_CTRL3 0x31 +#define B2056_SYN_RCCAL_CTRL4 0x32 +#define B2056_SYN_RCCAL_CTRL5 0x33 +#define B2056_SYN_RCCAL_CTRL6 0x34 +#define B2056_SYN_RCCAL_CTRL7 0x35 +#define B2056_SYN_RCCAL_CTRL8 0x36 +#define B2056_SYN_RCCAL_CTRL9 0x37 +#define B2056_SYN_RCCAL_CTRL10 0x38 +#define B2056_SYN_RCCAL_CTRL11 0x39 +#define B2056_SYN_ZCAL_SPARE1 0x3A +#define B2056_SYN_ZCAL_SPARE2 0x3B +#define B2056_SYN_PLL_MAST1 0x3C +#define B2056_SYN_PLL_MAST2 0x3D +#define B2056_SYN_PLL_MAST3 0x3E +#define B2056_SYN_PLL_BIAS_RESET 0x3F +#define B2056_SYN_PLL_XTAL0 0x40 +#define B2056_SYN_PLL_XTAL1 0x41 +#define B2056_SYN_PLL_XTAL3 0x42 +#define B2056_SYN_PLL_XTAL4 0x43 +#define B2056_SYN_PLL_XTAL5 0x44 +#define B2056_SYN_PLL_XTAL6 0x45 +#define B2056_SYN_PLL_REFDIV 0x46 +#define B2056_SYN_PLL_PFD 0x47 +#define B2056_SYN_PLL_CP1 0x48 +#define B2056_SYN_PLL_CP2 0x49 +#define B2056_SYN_PLL_CP3 0x4A +#define B2056_SYN_PLL_LOOPFILTER1 0x4B +#define B2056_SYN_PLL_LOOPFILTER2 0x4C +#define B2056_SYN_PLL_LOOPFILTER3 0x4D +#define B2056_SYN_PLL_LOOPFILTER4 0x4E +#define B2056_SYN_PLL_LOOPFILTER5 0x4F +#define B2056_SYN_PLL_MMD1 0x50 +#define B2056_SYN_PLL_MMD2 0x51 +#define B2056_SYN_PLL_VCO1 0x52 +#define B2056_SYN_PLL_VCO2 0x53 +#define B2056_SYN_PLL_MONITOR1 0x54 +#define B2056_SYN_PLL_MONITOR2 0x55 +#define B2056_SYN_PLL_VCOCAL1 0x56 +#define B2056_SYN_PLL_VCOCAL2 0x57 +#define B2056_SYN_PLL_VCOCAL4 0x58 +#define B2056_SYN_PLL_VCOCAL5 0x59 +#define B2056_SYN_PLL_VCOCAL6 0x5A +#define B2056_SYN_PLL_VCOCAL7 0x5B +#define B2056_SYN_PLL_VCOCAL8 0x5C +#define B2056_SYN_PLL_VCOCAL9 0x5D +#define B2056_SYN_PLL_VCOCAL10 0x5E +#define B2056_SYN_PLL_VCOCAL11 0x5F +#define B2056_SYN_PLL_VCOCAL12 0x60 +#define B2056_SYN_PLL_VCOCAL13 0x61 +#define B2056_SYN_PLL_VREG 0x62 +#define B2056_SYN_PLL_STATUS1 0x63 +#define B2056_SYN_PLL_STATUS2 0x64 +#define B2056_SYN_PLL_STATUS3 0x65 +#define B2056_SYN_LOGEN_PU0 0x66 +#define B2056_SYN_LOGEN_PU1 0x67 +#define B2056_SYN_LOGEN_PU2 0x68 +#define B2056_SYN_LOGEN_PU3 0x69 +#define B2056_SYN_LOGEN_PU5 0x6A +#define B2056_SYN_LOGEN_PU6 0x6B +#define B2056_SYN_LOGEN_PU7 0x6C +#define B2056_SYN_LOGEN_PU8 0x6D +#define B2056_SYN_LOGEN_BIAS_RESET 0x6E +#define B2056_SYN_LOGEN_RCCR1 0x6F +#define B2056_SYN_LOGEN_VCOBUF1 0x70 +#define B2056_SYN_LOGEN_MIXER1 0x71 +#define B2056_SYN_LOGEN_MIXER2 0x72 +#define B2056_SYN_LOGEN_BUF1 0x73 +#define B2056_SYN_LOGENBUF2 0x74 +#define B2056_SYN_LOGEN_BUF3 0x75 +#define B2056_SYN_LOGEN_BUF4 0x76 +#define B2056_SYN_LOGEN_DIV1 0x77 +#define B2056_SYN_LOGEN_DIV2 0x78 +#define B2056_SYN_LOGEN_DIV3 0x79 +#define B2056_SYN_LOGEN_ACL1 0x7A +#define B2056_SYN_LOGEN_ACL2 0x7B +#define B2056_SYN_LOGEN_ACL3 0x7C +#define B2056_SYN_LOGEN_ACL4 0x7D +#define B2056_SYN_LOGEN_ACL5 0x7E +#define B2056_SYN_LOGEN_ACL6 0x7F +#define B2056_SYN_LOGEN_ACLOUT 0x80 +#define B2056_SYN_LOGEN_ACLCAL1 0x81 +#define B2056_SYN_LOGEN_ACLCAL2 0x82 +#define B2056_SYN_LOGEN_ACLCAL3 0x83 +#define B2056_SYN_CALEN 0x84 +#define B2056_SYN_LOGEN_PEAKDET1 0x85 +#define B2056_SYN_LOGEN_CORE_ACL_OVR 0x86 +#define B2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87 +#define B2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88 +#define B2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89 +#define B2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8A +#define B2056_SYN_LOGEN_VCOBUF2 0x8B +#define B2056_SYN_LOGEN_MIXER3 0x8C +#define B2056_SYN_LOGEN_BUF5 0x8D +#define B2056_SYN_LOGEN_BUF6 0x8E +#define B2056_SYN_LOGEN_CBUFRX1 0x8F +#define B2056_SYN_LOGEN_CBUFRX2 0x90 +#define B2056_SYN_LOGEN_CBUFRX3 0x91 +#define B2056_SYN_LOGEN_CBUFRX4 0x92 +#define B2056_SYN_LOGEN_CBUFTX1 0x93 +#define B2056_SYN_LOGEN_CBUFTX2 0x94 +#define B2056_SYN_LOGEN_CBUFTX3 0x95 +#define B2056_SYN_LOGEN_CBUFTX4 0x96 +#define B2056_SYN_LOGEN_CMOSRX1 0x97 +#define B2056_SYN_LOGEN_CMOSRX2 0x98 +#define B2056_SYN_LOGEN_CMOSRX3 0x99 +#define B2056_SYN_LOGEN_CMOSRX4 0x9A +#define B2056_SYN_LOGEN_CMOSTX1 0x9B +#define B2056_SYN_LOGEN_CMOSTX2 0x9C +#define B2056_SYN_LOGEN_CMOSTX3 0x9D +#define B2056_SYN_LOGEN_CMOSTX4 0x9E +#define B2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9F +#define B2056_SYN_LOGEN_MIXER3_OVRVAL 0xA0 +#define B2056_SYN_LOGEN_BUF5_OVRVAL 0xA1 +#define B2056_SYN_LOGEN_BUF6_OVRVAL 0xA2 +#define B2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xA3 +#define B2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xA4 +#define B2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xA5 +#define B2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xA6 +#define B2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xA7 +#define B2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xA8 +#define B2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xA9 +#define B2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xAA +#define B2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xAB +#define B2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xAC +#define B2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xAD +#define B2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xAE +#define B2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xAF +#define B2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xB0 +#define B2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xB1 +#define B2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xB2 +#define B2056_SYN_LOGEN_ACL_WAITCNT 0xB3 +#define B2056_SYN_LOGEN_CORE_CALVALID 0xB4 +#define B2056_SYN_LOGEN_RX_CMOS_CALVALID 0xB5 +#define B2056_SYN_LOGEN_TX_CMOS_VALID 0xB6 + +#define B2056_TX_RESERVED_ADDR0 0x00 +#define B2056_TX_IDCODE 0x01 +#define B2056_TX_RESERVED_ADDR2 0x02 +#define B2056_TX_RESERVED_ADDR3 0x03 +#define B2056_TX_RESERVED_ADDR4 0x04 +#define B2056_TX_RESERVED_ADDR5 0x05 +#define B2056_TX_RESERVED_ADDR6 0x06 +#define B2056_TX_RESERVED_ADDR7 0x07 +#define B2056_TX_COM_CTRL 0x08 +#define B2056_TX_COM_PU 0x09 +#define B2056_TX_COM_OVR 0x0A +#define B2056_TX_COM_RESET 0x0B +#define B2056_TX_COM_RCAL 0x0C +#define B2056_TX_COM_RC_RXLPF 0x0D +#define B2056_TX_COM_RC_TXLPF 0x0E +#define B2056_TX_COM_RC_RXHPF 0x0F +#define B2056_TX_RESERVED_ADDR16 0x10 +#define B2056_TX_RESERVED_ADDR17 0x11 +#define B2056_TX_RESERVED_ADDR18 0x12 +#define B2056_TX_RESERVED_ADDR19 0x13 +#define B2056_TX_RESERVED_ADDR20 0x14 +#define B2056_TX_RESERVED_ADDR21 0x15 +#define B2056_TX_RESERVED_ADDR22 0x16 +#define B2056_TX_RESERVED_ADDR23 0x17 +#define B2056_TX_RESERVED_ADDR24 0x18 +#define B2056_TX_RESERVED_ADDR25 0x19 +#define B2056_TX_RESERVED_ADDR26 0x1A +#define B2056_TX_RESERVED_ADDR27 0x1B +#define B2056_TX_RESERVED_ADDR28 0x1C +#define B2056_TX_RESERVED_ADDR29 0x1D +#define B2056_TX_RESERVED_ADDR30 0x1E +#define B2056_TX_RESERVED_ADDR31 0x1F +#define B2056_TX_IQCAL_GAIN_BW 0x20 +#define B2056_TX_LOFT_FINE_I 0x21 +#define B2056_TX_LOFT_FINE_Q 0x22 +#define B2056_TX_LOFT_COARSE_I 0x23 +#define B2056_TX_LOFT_COARSE_Q 0x24 +#define B2056_TX_TX_COM_MASTER1 0x25 +#define B2056_TX_TX_COM_MASTER2 0x26 +#define B2056_TX_RXIQCAL_TXMUX 0x27 +#define B2056_TX_TX_SSI_MASTER 0x28 +#define B2056_TX_IQCAL_VCM_HG 0x29 +#define B2056_TX_IQCAL_IDAC 0x2A +#define B2056_TX_TSSI_VCM 0x2B +#define B2056_TX_TX_AMP_DET 0x2C +#define B2056_TX_TX_SSI_MUX 0x2D +#define B2056_TX_TSSIA 0x2E +#define B2056_TX_TSSIG 0x2F +#define B2056_TX_TSSI_MISC1 0x30 +#define B2056_TX_TSSI_MISC2 0x31 +#define B2056_TX_TSSI_MISC3 0x32 +#define B2056_TX_PA_SPARE1 0x33 +#define B2056_TX_PA_SPARE2 0x34 +#define B2056_TX_INTPAA_MASTER 0x35 +#define B2056_TX_INTPAA_GAIN 0x36 +#define B2056_TX_INTPAA_BOOST_TUNE 0x37 +#define B2056_TX_INTPAA_IAUX_STAT 0x38 +#define B2056_TX_INTPAA_IAUX_DYN 0x39 +#define B2056_TX_INTPAA_IMAIN_STAT 0x3A +#define B2056_TX_INTPAA_IMAIN_DYN 0x3B +#define B2056_TX_INTPAA_CASCBIAS 0x3C +#define B2056_TX_INTPAA_PASLOPE 0x3D +#define B2056_TX_INTPAA_PA_MISC 0x3E +#define B2056_TX_INTPAG_MASTER 0x3F +#define B2056_TX_INTPAG_GAIN 0x40 +#define B2056_TX_INTPAG_BOOST_TUNE 0x41 +#define B2056_TX_INTPAG_IAUX_STAT 0x42 +#define B2056_TX_INTPAG_IAUX_DYN 0x43 +#define B2056_TX_INTPAG_IMAIN_STAT 0x44 +#define B2056_TX_INTPAG_IMAIN_DYN 0x45 +#define B2056_TX_INTPAG_CASCBIAS 0x46 +#define B2056_TX_INTPAG_PASLOPE 0x47 +#define B2056_TX_INTPAG_PA_MISC 0x48 +#define B2056_TX_PADA_MASTER 0x49 +#define B2056_TX_PADA_IDAC 0x4A +#define B2056_TX_PADA_CASCBIAS 0x4B +#define B2056_TX_PADA_GAIN 0x4C +#define B2056_TX_PADA_BOOST_TUNE 0x4D +#define B2056_TX_PADA_SLOPE 0x4E +#define B2056_TX_PADG_MASTER 0x4F +#define B2056_TX_PADG_IDAC 0x50 +#define B2056_TX_PADG_CASCBIAS 0x51 +#define B2056_TX_PADG_GAIN 0x52 +#define B2056_TX_PADG_BOOST_TUNE 0x53 +#define B2056_TX_PADG_SLOPE 0x54 +#define B2056_TX_PGAA_MASTER 0x55 +#define B2056_TX_PGAA_IDAC 0x56 +#define B2056_TX_PGAA_GAIN 0x57 +#define B2056_TX_PGAA_BOOST_TUNE 0x58 +#define B2056_TX_PGAA_SLOPE 0x59 +#define B2056_TX_PGAA_MISC 0x5A +#define B2056_TX_PGAG_MASTER 0x5B +#define B2056_TX_PGAG_IDAC 0x5C +#define B2056_TX_PGAG_GAIN 0x5D +#define B2056_TX_PGAG_BOOST_TUNE 0x5E +#define B2056_TX_PGAG_SLOPE 0x5F +#define B2056_TX_PGAG_MISC 0x60 +#define B2056_TX_MIXA_MASTER 0x61 +#define B2056_TX_MIXA_BOOST_TUNE 0x62 +#define B2056_TX_MIXG 0x63 +#define B2056_TX_MIXG_BOOST_TUNE 0x64 +#define B2056_TX_BB_GM_MASTER 0x65 +#define B2056_TX_GMBB_GM 0x66 +#define B2056_TX_GMBB_IDAC 0x67 +#define B2056_TX_TXLPF_MASTER 0x68 +#define B2056_TX_TXLPF_RCCAL 0x69 +#define B2056_TX_TXLPF_RCCAL_OFF0 0x6A +#define B2056_TX_TXLPF_RCCAL_OFF1 0x6B +#define B2056_TX_TXLPF_RCCAL_OFF2 0x6C +#define B2056_TX_TXLPF_RCCAL_OFF3 0x6D +#define B2056_TX_TXLPF_RCCAL_OFF4 0x6E +#define B2056_TX_TXLPF_RCCAL_OFF5 0x6F +#define B2056_TX_TXLPF_RCCAL_OFF6 0x70 +#define B2056_TX_TXLPF_BW 0x71 +#define B2056_TX_TXLPF_GAIN 0x72 +#define B2056_TX_TXLPF_IDAC 0x73 +#define B2056_TX_TXLPF_IDAC_0 0x74 +#define B2056_TX_TXLPF_IDAC_1 0x75 +#define B2056_TX_TXLPF_IDAC_2 0x76 +#define B2056_TX_TXLPF_IDAC_3 0x77 +#define B2056_TX_TXLPF_IDAC_4 0x78 +#define B2056_TX_TXLPF_IDAC_5 0x79 +#define B2056_TX_TXLPF_IDAC_6 0x7A +#define B2056_TX_TXLPF_OPAMP_IDAC 0x7B +#define B2056_TX_TXLPF_MISC 0x7C +#define B2056_TX_TXSPARE1 0x7D +#define B2056_TX_TXSPARE2 0x7E +#define B2056_TX_TXSPARE3 0x7F +#define B2056_TX_TXSPARE4 0x80 +#define B2056_TX_TXSPARE5 0x81 +#define B2056_TX_TXSPARE6 0x82 +#define B2056_TX_TXSPARE7 0x83 +#define B2056_TX_TXSPARE8 0x84 +#define B2056_TX_TXSPARE9 0x85 +#define B2056_TX_TXSPARE10 0x86 +#define B2056_TX_TXSPARE11 0x87 +#define B2056_TX_TXSPARE12 0x88 +#define B2056_TX_TXSPARE13 0x89 +#define B2056_TX_TXSPARE14 0x8A +#define B2056_TX_TXSPARE15 0x8B +#define B2056_TX_TXSPARE16 0x8C +#define B2056_TX_STATUS_INTPA_GAIN 0x8D +#define B2056_TX_STATUS_PAD_GAIN 0x8E +#define B2056_TX_STATUS_PGA_GAIN 0x8F +#define B2056_TX_STATUS_GM_TXLPF_GAIN 0x90 +#define B2056_TX_STATUS_TXLPF_BW 0x91 +#define B2056_TX_STATUS_TXLPF_RC 0x92 +#define B2056_TX_GMBB_IDAC0 0x93 +#define B2056_TX_GMBB_IDAC1 0x94 +#define B2056_TX_GMBB_IDAC2 0x95 +#define B2056_TX_GMBB_IDAC3 0x96 +#define B2056_TX_GMBB_IDAC4 0x97 +#define B2056_TX_GMBB_IDAC5 0x98 +#define B2056_TX_GMBB_IDAC6 0x99 +#define B2056_TX_GMBB_IDAC7 0x9A + +#define B2056_RX_RESERVED_ADDR0 0x00 +#define B2056_RX_IDCODE 0x01 +#define B2056_RX_RESERVED_ADDR2 0x02 +#define B2056_RX_RESERVED_ADDR3 0x03 +#define B2056_RX_RESERVED_ADDR4 0x04 +#define B2056_RX_RESERVED_ADDR5 0x05 +#define B2056_RX_RESERVED_ADDR6 0x06 +#define B2056_RX_RESERVED_ADDR7 0x07 +#define B2056_RX_COM_CTRL 0x08 +#define B2056_RX_COM_PU 0x09 +#define B2056_RX_COM_OVR 0x0A +#define B2056_RX_COM_RESET 0x0B +#define B2056_RX_COM_RCAL 0x0C +#define B2056_RX_COM_RC_RXLPF 0x0D +#define B2056_RX_COM_RC_TXLPF 0x0E +#define B2056_RX_COM_RC_RXHPF 0x0F +#define B2056_RX_RESERVED_ADDR16 0x10 +#define B2056_RX_RESERVED_ADDR17 0x11 +#define B2056_RX_RESERVED_ADDR18 0x12 +#define B2056_RX_RESERVED_ADDR19 0x13 +#define B2056_RX_RESERVED_ADDR20 0x14 +#define B2056_RX_RESERVED_ADDR21 0x15 +#define B2056_RX_RESERVED_ADDR22 0x16 +#define B2056_RX_RESERVED_ADDR23 0x17 +#define B2056_RX_RESERVED_ADDR24 0x18 +#define B2056_RX_RESERVED_ADDR25 0x19 +#define B2056_RX_RESERVED_ADDR26 0x1A +#define B2056_RX_RESERVED_ADDR27 0x1B +#define B2056_RX_RESERVED_ADDR28 0x1C +#define B2056_RX_RESERVED_ADDR29 0x1D +#define B2056_RX_RESERVED_ADDR30 0x1E +#define B2056_RX_RESERVED_ADDR31 0x1F +#define B2056_RX_RXIQCAL_RXMUX 0x20 +#define B2056_RX_RSSI_PU 0x21 +#define B2056_RX_RSSI_SEL 0x22 +#define B2056_RX_RSSI_GAIN 0x23 +#define B2056_RX_RSSI_NB_IDAC 0x24 +#define B2056_RX_RSSI_WB2I_IDAC_1 0x25 +#define B2056_RX_RSSI_WB2I_IDAC_2 0x26 +#define B2056_RX_RSSI_WB2Q_IDAC_1 0x27 +#define B2056_RX_RSSI_WB2Q_IDAC_2 0x28 +#define B2056_RX_RSSI_POLE 0x29 +#define B2056_RX_RSSI_WB1_IDAC 0x2A +#define B2056_RX_RSSI_MISC 0x2B +#define B2056_RX_LNAA_MASTER 0x2C +#define B2056_RX_LNAA_TUNE 0x2D +#define B2056_RX_LNAA_GAIN 0x2E +#define B2056_RX_LNA_A_SLOPE 0x2F +#define B2056_RX_BIASPOLE_LNAA1_IDAC 0x30 +#define B2056_RX_LNAA2_IDAC 0x31 +#define B2056_RX_LNA1A_MISC 0x32 +#define B2056_RX_LNAG_MASTER 0x33 +#define B2056_RX_LNAG_TUNE 0x34 +#define B2056_RX_LNAG_GAIN 0x35 +#define B2056_RX_LNA_G_SLOPE 0x36 +#define B2056_RX_BIASPOLE_LNAG1_IDAC 0x37 +#define B2056_RX_LNAG2_IDAC 0x38 +#define B2056_RX_LNA1G_MISC 0x39 +#define B2056_RX_MIXA_MASTER 0x3A +#define B2056_RX_MIXA_VCM 0x3B +#define B2056_RX_MIXA_CTRLPTAT 0x3C +#define B2056_RX_MIXA_LOB_BIAS 0x3D +#define B2056_RX_MIXA_CORE_IDAC 0x3E +#define B2056_RX_MIXA_CMFB_IDAC 0x3F +#define B2056_RX_MIXA_BIAS_AUX 0x40 +#define B2056_RX_MIXA_BIAS_MAIN 0x41 +#define B2056_RX_MIXA_BIAS_MISC 0x42 +#define B2056_RX_MIXA_MAST_BIAS 0x43 +#define B2056_RX_MIXG_MASTER 0x44 +#define B2056_RX_MIXG_VCM 0x45 +#define B2056_RX_MIXG_CTRLPTAT 0x46 +#define B2056_RX_MIXG_LOB_BIAS 0x47 +#define B2056_RX_MIXG_CORE_IDAC 0x48 +#define B2056_RX_MIXG_CMFB_IDAC 0x49 +#define B2056_RX_MIXG_BIAS_AUX 0x4A +#define B2056_RX_MIXG_BIAS_MAIN 0x4B +#define B2056_RX_MIXG_BIAS_MISC 0x4C +#define B2056_RX_MIXG_MAST_BIAS 0x4D +#define B2056_RX_TIA_MASTER 0x4E +#define B2056_RX_TIA_IOPAMP 0x4F +#define B2056_RX_TIA_QOPAMP 0x50 +#define B2056_RX_TIA_IMISC 0x51 +#define B2056_RX_TIA_QMISC 0x52 +#define B2056_RX_TIA_GAIN 0x53 +#define B2056_RX_TIA_SPARE1 0x54 +#define B2056_RX_TIA_SPARE2 0x55 +#define B2056_RX_BB_LPF_MASTER 0x56 +#define B2056_RX_AACI_MASTER 0x57 +#define B2056_RX_RXLPF_IDAC 0x58 +#define B2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59 +#define B2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5A +#define B2056_RX_RXLPF_BIAS_DCCANCEL 0x5B +#define B2056_RX_RXLPF_OUTVCM 0x5C +#define B2056_RX_RXLPF_INVCM_BODY 0x5D +#define B2056_RX_RXLPF_CC_OP 0x5E +#define B2056_RX_RXLPF_GAIN 0x5F +#define B2056_RX_RXLPF_Q_BW 0x60 +#define B2056_RX_RXLPF_HP_CORNER_BW 0x61 +#define B2056_RX_RXLPF_RCCAL_HPC 0x62 +#define B2056_RX_RXHPF_OFF0 0x63 +#define B2056_RX_RXHPF_OFF1 0x64 +#define B2056_RX_RXHPF_OFF2 0x65 +#define B2056_RX_RXHPF_OFF3 0x66 +#define B2056_RX_RXHPF_OFF4 0x67 +#define B2056_RX_RXHPF_OFF5 0x68 +#define B2056_RX_RXHPF_OFF6 0x69 +#define B2056_RX_RXHPF_OFF7 0x6A +#define B2056_RX_RXLPF_RCCAL_LPC 0x6B +#define B2056_RX_RXLPF_OFF_0 0x6C +#define B2056_RX_RXLPF_OFF_1 0x6D +#define B2056_RX_RXLPF_OFF_2 0x6E +#define B2056_RX_RXLPF_OFF_3 0x6F +#define B2056_RX_RXLPF_OFF_4 0x70 +#define B2056_RX_UNUSED 0x71 +#define B2056_RX_VGA_MASTER 0x72 +#define B2056_RX_VGA_BIAS 0x73 +#define B2056_RX_VGA_BIAS_DCCANCEL 0x74 +#define B2056_RX_VGA_GAIN 0x75 +#define B2056_RX_VGA_HP_CORNER_BW 0x76 +#define B2056_RX_VGABUF_BIAS 0x77 +#define B2056_RX_VGABUF_GAIN_BW 0x78 +#define B2056_RX_TXFBMIX_A 0x79 +#define B2056_RX_TXFBMIX_G 0x7A +#define B2056_RX_RXSPARE1 0x7B +#define B2056_RX_RXSPARE2 0x7C +#define B2056_RX_RXSPARE3 0x7D +#define B2056_RX_RXSPARE4 0x7E +#define B2056_RX_RXSPARE5 0x7F +#define B2056_RX_RXSPARE6 0x80 +#define B2056_RX_RXSPARE7 0x81 +#define B2056_RX_RXSPARE8 0x82 +#define B2056_RX_RXSPARE9 0x83 +#define B2056_RX_RXSPARE10 0x84 +#define B2056_RX_RXSPARE11 0x85 +#define B2056_RX_RXSPARE12 0x86 +#define B2056_RX_RXSPARE13 0x87 +#define B2056_RX_RXSPARE14 0x88 +#define B2056_RX_RXSPARE15 0x89 +#define B2056_RX_RXSPARE16 0x8A +#define B2056_RX_STATUS_LNAA_GAIN 0x8B +#define B2056_RX_STATUS_LNAG_GAIN 0x8C +#define B2056_RX_STATUS_MIXTIA_GAIN 0x8D +#define B2056_RX_STATUS_RXLPF_GAIN 0x8E +#define B2056_RX_STATUS_VGA_BUF_GAIN 0x8F +#define B2056_RX_STATUS_RXLPF_Q 0x90 +#define B2056_RX_STATUS_RXLPF_BUF_BW 0x91 +#define B2056_RX_STATUS_RXLPF_VGA_HPC 0x92 +#define B2056_RX_STATUS_RXLPF_RC 0x93 +#define B2056_RX_STATUS_HPC_RC 0x94 + +#define B2056_LNA1_A_PU 0x01 +#define B2056_LNA2_A_PU 0x02 +#define B2056_LNA1_G_PU 0x01 +#define B2056_LNA2_G_PU 0x02 +#define B2056_MIXA_PU_I 0x01 +#define B2056_MIXA_PU_Q 0x02 +#define B2056_MIXA_PU_GM 0x10 +#define B2056_MIXG_PU_I 0x01 +#define B2056_MIXG_PU_Q 0x02 +#define B2056_MIXG_PU_GM 0x10 +#define B2056_TIA_PU 0x01 +#define B2056_BB_LPF_PU 0x20 +#define B2056_W1_PU 0x02 +#define B2056_W2_PU 0x04 +#define B2056_NB_PU 0x08 +#define B2056_RSSI_W1_SEL 0x02 +#define B2056_RSSI_W2_SEL 0x04 +#define B2056_RSSI_NB_SEL 0x08 +#define B2056_VCM_MASK 0x1C +#define B2056_RSSI_VCM_SHIFT 0x02 + struct b43_nphy_channeltab_entry_rev3 { /* The channel frequency in MHz */ u16 freq; -- cgit v1.2.3 From 790a11f268373b60069bc1371dc05143107c607c Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 14 Oct 2010 23:04:40 +0200 Subject: b43: N-PHY: define registers names for 2056 radio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Cc: Henry Ptasinski Cc: Brett Rudley Cc: Nohee Ko Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2056.h | 519 ++++++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h index 6b3264774adf..302600c0afa4 100644 --- a/drivers/net/wireless/b43/radio_2056.h +++ b/drivers/net/wireless/b43/radio_2056.h @@ -550,6 +550,525 @@ #define B2056_VCM_MASK 0x1C #define B2056_RSSI_VCM_SHIFT 0x02 +#define B2056_SYN (0x0 << 12) +#define B2056_TX0 (0x2 << 12) +#define B2056_TX1 (0x3 << 12) +#define B2056_RX0 (0x6 << 12) +#define B2056_RX1 (0x7 << 12) +#define B2056_ALLTX (0xE << 12) +#define B2056_ALLRX (0xF << 12) + +#define B2056_SYN_RESERVED_ADDR0 0x00 +#define B2056_SYN_IDCODE 0x01 +#define B2056_SYN_RESERVED_ADDR2 0x02 +#define B2056_SYN_RESERVED_ADDR3 0x03 +#define B2056_SYN_RESERVED_ADDR4 0x04 +#define B2056_SYN_RESERVED_ADDR5 0x05 +#define B2056_SYN_RESERVED_ADDR6 0x06 +#define B2056_SYN_RESERVED_ADDR7 0x07 +#define B2056_SYN_COM_CTRL 0x08 +#define B2056_SYN_COM_PU 0x09 +#define B2056_SYN_COM_OVR 0x0A +#define B2056_SYN_COM_RESET 0x0B +#define B2056_SYN_COM_RCAL 0x0C +#define B2056_SYN_COM_RC_RXLPF 0x0D +#define B2056_SYN_COM_RC_TXLPF 0x0E +#define B2056_SYN_COM_RC_RXHPF 0x0F +#define B2056_SYN_RESERVED_ADDR16 0x10 +#define B2056_SYN_RESERVED_ADDR17 0x11 +#define B2056_SYN_RESERVED_ADDR18 0x12 +#define B2056_SYN_RESERVED_ADDR19 0x13 +#define B2056_SYN_RESERVED_ADDR20 0x14 +#define B2056_SYN_RESERVED_ADDR21 0x15 +#define B2056_SYN_RESERVED_ADDR22 0x16 +#define B2056_SYN_RESERVED_ADDR23 0x17 +#define B2056_SYN_RESERVED_ADDR24 0x18 +#define B2056_SYN_RESERVED_ADDR25 0x19 +#define B2056_SYN_RESERVED_ADDR26 0x1A +#define B2056_SYN_RESERVED_ADDR27 0x1B +#define B2056_SYN_RESERVED_ADDR28 0x1C +#define B2056_SYN_RESERVED_ADDR29 0x1D +#define B2056_SYN_RESERVED_ADDR30 0x1E +#define B2056_SYN_RESERVED_ADDR31 0x1F +#define B2056_SYN_GPIO_MASTER1 0x20 +#define B2056_SYN_GPIO_MASTER2 0x21 +#define B2056_SYN_TOPBIAS_MASTER 0x22 +#define B2056_SYN_TOPBIAS_RCAL 0x23 +#define B2056_SYN_AFEREG 0x24 +#define B2056_SYN_TEMPPROCSENSE 0x25 +#define B2056_SYN_TEMPPROCSENSEIDAC 0x26 +#define B2056_SYN_TEMPPROCSENSERCAL 0x27 +#define B2056_SYN_LPO 0x28 +#define B2056_SYN_VDDCAL_MASTER 0x29 +#define B2056_SYN_VDDCAL_IDAC 0x2A +#define B2056_SYN_VDDCAL_STATUS 0x2B +#define B2056_SYN_RCAL_MASTER 0x2C +#define B2056_SYN_RCAL_CODE_OUT 0x2D +#define B2056_SYN_RCCAL_CTRL0 0x2E +#define B2056_SYN_RCCAL_CTRL1 0x2F +#define B2056_SYN_RCCAL_CTRL2 0x30 +#define B2056_SYN_RCCAL_CTRL3 0x31 +#define B2056_SYN_RCCAL_CTRL4 0x32 +#define B2056_SYN_RCCAL_CTRL5 0x33 +#define B2056_SYN_RCCAL_CTRL6 0x34 +#define B2056_SYN_RCCAL_CTRL7 0x35 +#define B2056_SYN_RCCAL_CTRL8 0x36 +#define B2056_SYN_RCCAL_CTRL9 0x37 +#define B2056_SYN_RCCAL_CTRL10 0x38 +#define B2056_SYN_RCCAL_CTRL11 0x39 +#define B2056_SYN_ZCAL_SPARE1 0x3A +#define B2056_SYN_ZCAL_SPARE2 0x3B +#define B2056_SYN_PLL_MAST1 0x3C +#define B2056_SYN_PLL_MAST2 0x3D +#define B2056_SYN_PLL_MAST3 0x3E +#define B2056_SYN_PLL_BIAS_RESET 0x3F +#define B2056_SYN_PLL_XTAL0 0x40 +#define B2056_SYN_PLL_XTAL1 0x41 +#define B2056_SYN_PLL_XTAL3 0x42 +#define B2056_SYN_PLL_XTAL4 0x43 +#define B2056_SYN_PLL_XTAL5 0x44 +#define B2056_SYN_PLL_XTAL6 0x45 +#define B2056_SYN_PLL_REFDIV 0x46 +#define B2056_SYN_PLL_PFD 0x47 +#define B2056_SYN_PLL_CP1 0x48 +#define B2056_SYN_PLL_CP2 0x49 +#define B2056_SYN_PLL_CP3 0x4A +#define B2056_SYN_PLL_LOOPFILTER1 0x4B +#define B2056_SYN_PLL_LOOPFILTER2 0x4C +#define B2056_SYN_PLL_LOOPFILTER3 0x4D +#define B2056_SYN_PLL_LOOPFILTER4 0x4E +#define B2056_SYN_PLL_LOOPFILTER5 0x4F +#define B2056_SYN_PLL_MMD1 0x50 +#define B2056_SYN_PLL_MMD2 0x51 +#define B2056_SYN_PLL_VCO1 0x52 +#define B2056_SYN_PLL_VCO2 0x53 +#define B2056_SYN_PLL_MONITOR1 0x54 +#define B2056_SYN_PLL_MONITOR2 0x55 +#define B2056_SYN_PLL_VCOCAL1 0x56 +#define B2056_SYN_PLL_VCOCAL2 0x57 +#define B2056_SYN_PLL_VCOCAL4 0x58 +#define B2056_SYN_PLL_VCOCAL5 0x59 +#define B2056_SYN_PLL_VCOCAL6 0x5A +#define B2056_SYN_PLL_VCOCAL7 0x5B +#define B2056_SYN_PLL_VCOCAL8 0x5C +#define B2056_SYN_PLL_VCOCAL9 0x5D +#define B2056_SYN_PLL_VCOCAL10 0x5E +#define B2056_SYN_PLL_VCOCAL11 0x5F +#define B2056_SYN_PLL_VCOCAL12 0x60 +#define B2056_SYN_PLL_VCOCAL13 0x61 +#define B2056_SYN_PLL_VREG 0x62 +#define B2056_SYN_PLL_STATUS1 0x63 +#define B2056_SYN_PLL_STATUS2 0x64 +#define B2056_SYN_PLL_STATUS3 0x65 +#define B2056_SYN_LOGEN_PU0 0x66 +#define B2056_SYN_LOGEN_PU1 0x67 +#define B2056_SYN_LOGEN_PU2 0x68 +#define B2056_SYN_LOGEN_PU3 0x69 +#define B2056_SYN_LOGEN_PU5 0x6A +#define B2056_SYN_LOGEN_PU6 0x6B +#define B2056_SYN_LOGEN_PU7 0x6C +#define B2056_SYN_LOGEN_PU8 0x6D +#define B2056_SYN_LOGEN_BIAS_RESET 0x6E +#define B2056_SYN_LOGEN_RCCR1 0x6F +#define B2056_SYN_LOGEN_VCOBUF1 0x70 +#define B2056_SYN_LOGEN_MIXER1 0x71 +#define B2056_SYN_LOGEN_MIXER2 0x72 +#define B2056_SYN_LOGEN_BUF1 0x73 +#define B2056_SYN_LOGENBUF2 0x74 +#define B2056_SYN_LOGEN_BUF3 0x75 +#define B2056_SYN_LOGEN_BUF4 0x76 +#define B2056_SYN_LOGEN_DIV1 0x77 +#define B2056_SYN_LOGEN_DIV2 0x78 +#define B2056_SYN_LOGEN_DIV3 0x79 +#define B2056_SYN_LOGEN_ACL1 0x7A +#define B2056_SYN_LOGEN_ACL2 0x7B +#define B2056_SYN_LOGEN_ACL3 0x7C +#define B2056_SYN_LOGEN_ACL4 0x7D +#define B2056_SYN_LOGEN_ACL5 0x7E +#define B2056_SYN_LOGEN_ACL6 0x7F +#define B2056_SYN_LOGEN_ACLOUT 0x80 +#define B2056_SYN_LOGEN_ACLCAL1 0x81 +#define B2056_SYN_LOGEN_ACLCAL2 0x82 +#define B2056_SYN_LOGEN_ACLCAL3 0x83 +#define B2056_SYN_CALEN 0x84 +#define B2056_SYN_LOGEN_PEAKDET1 0x85 +#define B2056_SYN_LOGEN_CORE_ACL_OVR 0x86 +#define B2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87 +#define B2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88 +#define B2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89 +#define B2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8A +#define B2056_SYN_LOGEN_VCOBUF2 0x8B +#define B2056_SYN_LOGEN_MIXER3 0x8C +#define B2056_SYN_LOGEN_BUF5 0x8D +#define B2056_SYN_LOGEN_BUF6 0x8E +#define B2056_SYN_LOGEN_CBUFRX1 0x8F +#define B2056_SYN_LOGEN_CBUFRX2 0x90 +#define B2056_SYN_LOGEN_CBUFRX3 0x91 +#define B2056_SYN_LOGEN_CBUFRX4 0x92 +#define B2056_SYN_LOGEN_CBUFTX1 0x93 +#define B2056_SYN_LOGEN_CBUFTX2 0x94 +#define B2056_SYN_LOGEN_CBUFTX3 0x95 +#define B2056_SYN_LOGEN_CBUFTX4 0x96 +#define B2056_SYN_LOGEN_CMOSRX1 0x97 +#define B2056_SYN_LOGEN_CMOSRX2 0x98 +#define B2056_SYN_LOGEN_CMOSRX3 0x99 +#define B2056_SYN_LOGEN_CMOSRX4 0x9A +#define B2056_SYN_LOGEN_CMOSTX1 0x9B +#define B2056_SYN_LOGEN_CMOSTX2 0x9C +#define B2056_SYN_LOGEN_CMOSTX3 0x9D +#define B2056_SYN_LOGEN_CMOSTX4 0x9E +#define B2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9F +#define B2056_SYN_LOGEN_MIXER3_OVRVAL 0xA0 +#define B2056_SYN_LOGEN_BUF5_OVRVAL 0xA1 +#define B2056_SYN_LOGEN_BUF6_OVRVAL 0xA2 +#define B2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xA3 +#define B2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xA4 +#define B2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xA5 +#define B2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xA6 +#define B2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xA7 +#define B2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xA8 +#define B2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xA9 +#define B2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xAA +#define B2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xAB +#define B2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xAC +#define B2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xAD +#define B2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xAE +#define B2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xAF +#define B2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xB0 +#define B2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xB1 +#define B2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xB2 +#define B2056_SYN_LOGEN_ACL_WAITCNT 0xB3 +#define B2056_SYN_LOGEN_CORE_CALVALID 0xB4 +#define B2056_SYN_LOGEN_RX_CMOS_CALVALID 0xB5 +#define B2056_SYN_LOGEN_TX_CMOS_VALID 0xB6 + +#define B2056_TX_RESERVED_ADDR0 0x00 +#define B2056_TX_IDCODE 0x01 +#define B2056_TX_RESERVED_ADDR2 0x02 +#define B2056_TX_RESERVED_ADDR3 0x03 +#define B2056_TX_RESERVED_ADDR4 0x04 +#define B2056_TX_RESERVED_ADDR5 0x05 +#define B2056_TX_RESERVED_ADDR6 0x06 +#define B2056_TX_RESERVED_ADDR7 0x07 +#define B2056_TX_COM_CTRL 0x08 +#define B2056_TX_COM_PU 0x09 +#define B2056_TX_COM_OVR 0x0A +#define B2056_TX_COM_RESET 0x0B +#define B2056_TX_COM_RCAL 0x0C +#define B2056_TX_COM_RC_RXLPF 0x0D +#define B2056_TX_COM_RC_TXLPF 0x0E +#define B2056_TX_COM_RC_RXHPF 0x0F +#define B2056_TX_RESERVED_ADDR16 0x10 +#define B2056_TX_RESERVED_ADDR17 0x11 +#define B2056_TX_RESERVED_ADDR18 0x12 +#define B2056_TX_RESERVED_ADDR19 0x13 +#define B2056_TX_RESERVED_ADDR20 0x14 +#define B2056_TX_RESERVED_ADDR21 0x15 +#define B2056_TX_RESERVED_ADDR22 0x16 +#define B2056_TX_RESERVED_ADDR23 0x17 +#define B2056_TX_RESERVED_ADDR24 0x18 +#define B2056_TX_RESERVED_ADDR25 0x19 +#define B2056_TX_RESERVED_ADDR26 0x1A +#define B2056_TX_RESERVED_ADDR27 0x1B +#define B2056_TX_RESERVED_ADDR28 0x1C +#define B2056_TX_RESERVED_ADDR29 0x1D +#define B2056_TX_RESERVED_ADDR30 0x1E +#define B2056_TX_RESERVED_ADDR31 0x1F +#define B2056_TX_IQCAL_GAIN_BW 0x20 +#define B2056_TX_LOFT_FINE_I 0x21 +#define B2056_TX_LOFT_FINE_Q 0x22 +#define B2056_TX_LOFT_COARSE_I 0x23 +#define B2056_TX_LOFT_COARSE_Q 0x24 +#define B2056_TX_TX_COM_MASTER1 0x25 +#define B2056_TX_TX_COM_MASTER2 0x26 +#define B2056_TX_RXIQCAL_TXMUX 0x27 +#define B2056_TX_TX_SSI_MASTER 0x28 +#define B2056_TX_IQCAL_VCM_HG 0x29 +#define B2056_TX_IQCAL_IDAC 0x2A +#define B2056_TX_TSSI_VCM 0x2B +#define B2056_TX_TX_AMP_DET 0x2C +#define B2056_TX_TX_SSI_MUX 0x2D +#define B2056_TX_TSSIA 0x2E +#define B2056_TX_TSSIG 0x2F +#define B2056_TX_TSSI_MISC1 0x30 +#define B2056_TX_TSSI_MISC2 0x31 +#define B2056_TX_TSSI_MISC3 0x32 +#define B2056_TX_PA_SPARE1 0x33 +#define B2056_TX_PA_SPARE2 0x34 +#define B2056_TX_INTPAA_MASTER 0x35 +#define B2056_TX_INTPAA_GAIN 0x36 +#define B2056_TX_INTPAA_BOOST_TUNE 0x37 +#define B2056_TX_INTPAA_IAUX_STAT 0x38 +#define B2056_TX_INTPAA_IAUX_DYN 0x39 +#define B2056_TX_INTPAA_IMAIN_STAT 0x3A +#define B2056_TX_INTPAA_IMAIN_DYN 0x3B +#define B2056_TX_INTPAA_CASCBIAS 0x3C +#define B2056_TX_INTPAA_PASLOPE 0x3D +#define B2056_TX_INTPAA_PA_MISC 0x3E +#define B2056_TX_INTPAG_MASTER 0x3F +#define B2056_TX_INTPAG_GAIN 0x40 +#define B2056_TX_INTPAG_BOOST_TUNE 0x41 +#define B2056_TX_INTPAG_IAUX_STAT 0x42 +#define B2056_TX_INTPAG_IAUX_DYN 0x43 +#define B2056_TX_INTPAG_IMAIN_STAT 0x44 +#define B2056_TX_INTPAG_IMAIN_DYN 0x45 +#define B2056_TX_INTPAG_CASCBIAS 0x46 +#define B2056_TX_INTPAG_PASLOPE 0x47 +#define B2056_TX_INTPAG_PA_MISC 0x48 +#define B2056_TX_PADA_MASTER 0x49 +#define B2056_TX_PADA_IDAC 0x4A +#define B2056_TX_PADA_CASCBIAS 0x4B +#define B2056_TX_PADA_GAIN 0x4C +#define B2056_TX_PADA_BOOST_TUNE 0x4D +#define B2056_TX_PADA_SLOPE 0x4E +#define B2056_TX_PADG_MASTER 0x4F +#define B2056_TX_PADG_IDAC 0x50 +#define B2056_TX_PADG_CASCBIAS 0x51 +#define B2056_TX_PADG_GAIN 0x52 +#define B2056_TX_PADG_BOOST_TUNE 0x53 +#define B2056_TX_PADG_SLOPE 0x54 +#define B2056_TX_PGAA_MASTER 0x55 +#define B2056_TX_PGAA_IDAC 0x56 +#define B2056_TX_PGAA_GAIN 0x57 +#define B2056_TX_PGAA_BOOST_TUNE 0x58 +#define B2056_TX_PGAA_SLOPE 0x59 +#define B2056_TX_PGAA_MISC 0x5A +#define B2056_TX_PGAG_MASTER 0x5B +#define B2056_TX_PGAG_IDAC 0x5C +#define B2056_TX_PGAG_GAIN 0x5D +#define B2056_TX_PGAG_BOOST_TUNE 0x5E +#define B2056_TX_PGAG_SLOPE 0x5F +#define B2056_TX_PGAG_MISC 0x60 +#define B2056_TX_MIXA_MASTER 0x61 +#define B2056_TX_MIXA_BOOST_TUNE 0x62 +#define B2056_TX_MIXG 0x63 +#define B2056_TX_MIXG_BOOST_TUNE 0x64 +#define B2056_TX_BB_GM_MASTER 0x65 +#define B2056_TX_GMBB_GM 0x66 +#define B2056_TX_GMBB_IDAC 0x67 +#define B2056_TX_TXLPF_MASTER 0x68 +#define B2056_TX_TXLPF_RCCAL 0x69 +#define B2056_TX_TXLPF_RCCAL_OFF0 0x6A +#define B2056_TX_TXLPF_RCCAL_OFF1 0x6B +#define B2056_TX_TXLPF_RCCAL_OFF2 0x6C +#define B2056_TX_TXLPF_RCCAL_OFF3 0x6D +#define B2056_TX_TXLPF_RCCAL_OFF4 0x6E +#define B2056_TX_TXLPF_RCCAL_OFF5 0x6F +#define B2056_TX_TXLPF_RCCAL_OFF6 0x70 +#define B2056_TX_TXLPF_BW 0x71 +#define B2056_TX_TXLPF_GAIN 0x72 +#define B2056_TX_TXLPF_IDAC 0x73 +#define B2056_TX_TXLPF_IDAC_0 0x74 +#define B2056_TX_TXLPF_IDAC_1 0x75 +#define B2056_TX_TXLPF_IDAC_2 0x76 +#define B2056_TX_TXLPF_IDAC_3 0x77 +#define B2056_TX_TXLPF_IDAC_4 0x78 +#define B2056_TX_TXLPF_IDAC_5 0x79 +#define B2056_TX_TXLPF_IDAC_6 0x7A +#define B2056_TX_TXLPF_OPAMP_IDAC 0x7B +#define B2056_TX_TXLPF_MISC 0x7C +#define B2056_TX_TXSPARE1 0x7D +#define B2056_TX_TXSPARE2 0x7E +#define B2056_TX_TXSPARE3 0x7F +#define B2056_TX_TXSPARE4 0x80 +#define B2056_TX_TXSPARE5 0x81 +#define B2056_TX_TXSPARE6 0x82 +#define B2056_TX_TXSPARE7 0x83 +#define B2056_TX_TXSPARE8 0x84 +#define B2056_TX_TXSPARE9 0x85 +#define B2056_TX_TXSPARE10 0x86 +#define B2056_TX_TXSPARE11 0x87 +#define B2056_TX_TXSPARE12 0x88 +#define B2056_TX_TXSPARE13 0x89 +#define B2056_TX_TXSPARE14 0x8A +#define B2056_TX_TXSPARE15 0x8B +#define B2056_TX_TXSPARE16 0x8C +#define B2056_TX_STATUS_INTPA_GAIN 0x8D +#define B2056_TX_STATUS_PAD_GAIN 0x8E +#define B2056_TX_STATUS_PGA_GAIN 0x8F +#define B2056_TX_STATUS_GM_TXLPF_GAIN 0x90 +#define B2056_TX_STATUS_TXLPF_BW 0x91 +#define B2056_TX_STATUS_TXLPF_RC 0x92 +#define B2056_TX_GMBB_IDAC0 0x93 +#define B2056_TX_GMBB_IDAC1 0x94 +#define B2056_TX_GMBB_IDAC2 0x95 +#define B2056_TX_GMBB_IDAC3 0x96 +#define B2056_TX_GMBB_IDAC4 0x97 +#define B2056_TX_GMBB_IDAC5 0x98 +#define B2056_TX_GMBB_IDAC6 0x99 +#define B2056_TX_GMBB_IDAC7 0x9A + +#define B2056_RX_RESERVED_ADDR0 0x00 +#define B2056_RX_IDCODE 0x01 +#define B2056_RX_RESERVED_ADDR2 0x02 +#define B2056_RX_RESERVED_ADDR3 0x03 +#define B2056_RX_RESERVED_ADDR4 0x04 +#define B2056_RX_RESERVED_ADDR5 0x05 +#define B2056_RX_RESERVED_ADDR6 0x06 +#define B2056_RX_RESERVED_ADDR7 0x07 +#define B2056_RX_COM_CTRL 0x08 +#define B2056_RX_COM_PU 0x09 +#define B2056_RX_COM_OVR 0x0A +#define B2056_RX_COM_RESET 0x0B +#define B2056_RX_COM_RCAL 0x0C +#define B2056_RX_COM_RC_RXLPF 0x0D +#define B2056_RX_COM_RC_TXLPF 0x0E +#define B2056_RX_COM_RC_RXHPF 0x0F +#define B2056_RX_RESERVED_ADDR16 0x10 +#define B2056_RX_RESERVED_ADDR17 0x11 +#define B2056_RX_RESERVED_ADDR18 0x12 +#define B2056_RX_RESERVED_ADDR19 0x13 +#define B2056_RX_RESERVED_ADDR20 0x14 +#define B2056_RX_RESERVED_ADDR21 0x15 +#define B2056_RX_RESERVED_ADDR22 0x16 +#define B2056_RX_RESERVED_ADDR23 0x17 +#define B2056_RX_RESERVED_ADDR24 0x18 +#define B2056_RX_RESERVED_ADDR25 0x19 +#define B2056_RX_RESERVED_ADDR26 0x1A +#define B2056_RX_RESERVED_ADDR27 0x1B +#define B2056_RX_RESERVED_ADDR28 0x1C +#define B2056_RX_RESERVED_ADDR29 0x1D +#define B2056_RX_RESERVED_ADDR30 0x1E +#define B2056_RX_RESERVED_ADDR31 0x1F +#define B2056_RX_RXIQCAL_RXMUX 0x20 +#define B2056_RX_RSSI_PU 0x21 +#define B2056_RX_RSSI_SEL 0x22 +#define B2056_RX_RSSI_GAIN 0x23 +#define B2056_RX_RSSI_NB_IDAC 0x24 +#define B2056_RX_RSSI_WB2I_IDAC_1 0x25 +#define B2056_RX_RSSI_WB2I_IDAC_2 0x26 +#define B2056_RX_RSSI_WB2Q_IDAC_1 0x27 +#define B2056_RX_RSSI_WB2Q_IDAC_2 0x28 +#define B2056_RX_RSSI_POLE 0x29 +#define B2056_RX_RSSI_WB1_IDAC 0x2A +#define B2056_RX_RSSI_MISC 0x2B +#define B2056_RX_LNAA_MASTER 0x2C +#define B2056_RX_LNAA_TUNE 0x2D +#define B2056_RX_LNAA_GAIN 0x2E +#define B2056_RX_LNA_A_SLOPE 0x2F +#define B2056_RX_BIASPOLE_LNAA1_IDAC 0x30 +#define B2056_RX_LNAA2_IDAC 0x31 +#define B2056_RX_LNA1A_MISC 0x32 +#define B2056_RX_LNAG_MASTER 0x33 +#define B2056_RX_LNAG_TUNE 0x34 +#define B2056_RX_LNAG_GAIN 0x35 +#define B2056_RX_LNA_G_SLOPE 0x36 +#define B2056_RX_BIASPOLE_LNAG1_IDAC 0x37 +#define B2056_RX_LNAG2_IDAC 0x38 +#define B2056_RX_LNA1G_MISC 0x39 +#define B2056_RX_MIXA_MASTER 0x3A +#define B2056_RX_MIXA_VCM 0x3B +#define B2056_RX_MIXA_CTRLPTAT 0x3C +#define B2056_RX_MIXA_LOB_BIAS 0x3D +#define B2056_RX_MIXA_CORE_IDAC 0x3E +#define B2056_RX_MIXA_CMFB_IDAC 0x3F +#define B2056_RX_MIXA_BIAS_AUX 0x40 +#define B2056_RX_MIXA_BIAS_MAIN 0x41 +#define B2056_RX_MIXA_BIAS_MISC 0x42 +#define B2056_RX_MIXA_MAST_BIAS 0x43 +#define B2056_RX_MIXG_MASTER 0x44 +#define B2056_RX_MIXG_VCM 0x45 +#define B2056_RX_MIXG_CTRLPTAT 0x46 +#define B2056_RX_MIXG_LOB_BIAS 0x47 +#define B2056_RX_MIXG_CORE_IDAC 0x48 +#define B2056_RX_MIXG_CMFB_IDAC 0x49 +#define B2056_RX_MIXG_BIAS_AUX 0x4A +#define B2056_RX_MIXG_BIAS_MAIN 0x4B +#define B2056_RX_MIXG_BIAS_MISC 0x4C +#define B2056_RX_MIXG_MAST_BIAS 0x4D +#define B2056_RX_TIA_MASTER 0x4E +#define B2056_RX_TIA_IOPAMP 0x4F +#define B2056_RX_TIA_QOPAMP 0x50 +#define B2056_RX_TIA_IMISC 0x51 +#define B2056_RX_TIA_QMISC 0x52 +#define B2056_RX_TIA_GAIN 0x53 +#define B2056_RX_TIA_SPARE1 0x54 +#define B2056_RX_TIA_SPARE2 0x55 +#define B2056_RX_BB_LPF_MASTER 0x56 +#define B2056_RX_AACI_MASTER 0x57 +#define B2056_RX_RXLPF_IDAC 0x58 +#define B2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59 +#define B2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5A +#define B2056_RX_RXLPF_BIAS_DCCANCEL 0x5B +#define B2056_RX_RXLPF_OUTVCM 0x5C +#define B2056_RX_RXLPF_INVCM_BODY 0x5D +#define B2056_RX_RXLPF_CC_OP 0x5E +#define B2056_RX_RXLPF_GAIN 0x5F +#define B2056_RX_RXLPF_Q_BW 0x60 +#define B2056_RX_RXLPF_HP_CORNER_BW 0x61 +#define B2056_RX_RXLPF_RCCAL_HPC 0x62 +#define B2056_RX_RXHPF_OFF0 0x63 +#define B2056_RX_RXHPF_OFF1 0x64 +#define B2056_RX_RXHPF_OFF2 0x65 +#define B2056_RX_RXHPF_OFF3 0x66 +#define B2056_RX_RXHPF_OFF4 0x67 +#define B2056_RX_RXHPF_OFF5 0x68 +#define B2056_RX_RXHPF_OFF6 0x69 +#define B2056_RX_RXHPF_OFF7 0x6A +#define B2056_RX_RXLPF_RCCAL_LPC 0x6B +#define B2056_RX_RXLPF_OFF_0 0x6C +#define B2056_RX_RXLPF_OFF_1 0x6D +#define B2056_RX_RXLPF_OFF_2 0x6E +#define B2056_RX_RXLPF_OFF_3 0x6F +#define B2056_RX_RXLPF_OFF_4 0x70 +#define B2056_RX_UNUSED 0x71 +#define B2056_RX_VGA_MASTER 0x72 +#define B2056_RX_VGA_BIAS 0x73 +#define B2056_RX_VGA_BIAS_DCCANCEL 0x74 +#define B2056_RX_VGA_GAIN 0x75 +#define B2056_RX_VGA_HP_CORNER_BW 0x76 +#define B2056_RX_VGABUF_BIAS 0x77 +#define B2056_RX_VGABUF_GAIN_BW 0x78 +#define B2056_RX_TXFBMIX_A 0x79 +#define B2056_RX_TXFBMIX_G 0x7A +#define B2056_RX_RXSPARE1 0x7B +#define B2056_RX_RXSPARE2 0x7C +#define B2056_RX_RXSPARE3 0x7D +#define B2056_RX_RXSPARE4 0x7E +#define B2056_RX_RXSPARE5 0x7F +#define B2056_RX_RXSPARE6 0x80 +#define B2056_RX_RXSPARE7 0x81 +#define B2056_RX_RXSPARE8 0x82 +#define B2056_RX_RXSPARE9 0x83 +#define B2056_RX_RXSPARE10 0x84 +#define B2056_RX_RXSPARE11 0x85 +#define B2056_RX_RXSPARE12 0x86 +#define B2056_RX_RXSPARE13 0x87 +#define B2056_RX_RXSPARE14 0x88 +#define B2056_RX_RXSPARE15 0x89 +#define B2056_RX_RXSPARE16 0x8A +#define B2056_RX_STATUS_LNAA_GAIN 0x8B +#define B2056_RX_STATUS_LNAG_GAIN 0x8C +#define B2056_RX_STATUS_MIXTIA_GAIN 0x8D +#define B2056_RX_STATUS_RXLPF_GAIN 0x8E +#define B2056_RX_STATUS_VGA_BUF_GAIN 0x8F +#define B2056_RX_STATUS_RXLPF_Q 0x90 +#define B2056_RX_STATUS_RXLPF_BUF_BW 0x91 +#define B2056_RX_STATUS_RXLPF_VGA_HPC 0x92 +#define B2056_RX_STATUS_RXLPF_RC 0x93 +#define B2056_RX_STATUS_HPC_RC 0x94 + +#define B2056_LNA1_A_PU 0x01 +#define B2056_LNA2_A_PU 0x02 +#define B2056_LNA1_G_PU 0x01 +#define B2056_LNA2_G_PU 0x02 +#define B2056_MIXA_PU_I 0x01 +#define B2056_MIXA_PU_Q 0x02 +#define B2056_MIXA_PU_GM 0x10 +#define B2056_MIXG_PU_I 0x01 +#define B2056_MIXG_PU_Q 0x02 +#define B2056_MIXG_PU_GM 0x10 +#define B2056_TIA_PU 0x01 +#define B2056_BB_LPF_PU 0x20 +#define B2056_W1_PU 0x02 +#define B2056_W2_PU 0x04 +#define B2056_NB_PU 0x08 +#define B2056_RSSI_W1_SEL 0x02 +#define B2056_RSSI_W2_SEL 0x04 +#define B2056_RSSI_NB_SEL 0x08 +#define B2056_VCM_MASK 0x1C +#define B2056_RSSI_VCM_SHIFT 0x02 + struct b43_nphy_channeltab_entry_rev3 { /* The channel frequency in MHz */ u16 freq; -- cgit v1.2.3 From 4df3071ebd92ef7115b409da64d0eb405d24a631 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 8 Nov 2010 20:54:47 +0100 Subject: ath9k_hw: optimize interrupt mask changes OProfile showed that ath9k was spending way too much time in ath9k_hw_set_interrupts. Since most of the interrupt mask changes only need to globally enable/disable interrupts, it makes sense to split this part into separate functions, replacing all calls to ath9k_hw_set_interrupts(ah, 0) with ath9k_hw_disable_interrupts(ah). ath9k_hw_set_interrupts(ah, ah->imask) only gets changed to ath9k_hw_enable_interrupts(ah), whenever ah->imask was not changed since the point where interrupts were disabled. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/beacon.c | 6 +-- drivers/net/wireless/ath/ath9k/gpio.c | 4 +- drivers/net/wireless/ath/ath9k/mac.c | 86 +++++++++++++++++++-------------- drivers/net/wireless/ath/ath9k/mac.h | 6 ++- drivers/net/wireless/ath/ath9k/main.c | 18 +++---- 5 files changed, 68 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 19891e7d49ae..333da7bf2d7d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -503,7 +503,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc, /* Set the computed AP beacon timers */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); @@ -638,7 +638,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, /* Set the computed STA beacon timers */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; ath9k_hw_set_interrupts(ah, ah->imask); @@ -686,7 +686,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, /* Set the computed ADHOC beacon timers */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, ah->imask); diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 4a9a68bba324..db9c6fed799c 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -259,7 +259,7 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ah->imask |= ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); } @@ -273,7 +273,7 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) /* if no timer is enabled, turn off interrupt mask */ if (timer_table->timer_mask.val == 0) { - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ah->imask &= ~ATH9K_INT_GENTIMER; ath9k_hw_set_interrupts(ah, ah->imask); } diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 8c13479b17cd..65b1ee2a9792 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -117,12 +117,11 @@ EXPORT_SYMBOL(ath9k_hw_numtxpending); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) { u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; if (ah->tx_trig_level >= ah->config.max_txtrig_level) return false; - omask = ath9k_hw_set_interrupts(ah, ah->imask & ~ATH9K_INT_GLOBAL); + ath9k_hw_disable_interrupts(ah); txcfg = REG_READ(ah, AR_TXCFG); curLevel = MS(txcfg, AR_FTRIG); @@ -136,7 +135,7 @@ bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel) REG_WRITE(ah, AR_TXCFG, (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); - ath9k_hw_set_interrupts(ah, omask); + ath9k_hw_enable_interrupts(ah); ah->tx_trig_level = newLevel; @@ -849,28 +848,59 @@ bool ath9k_hw_intrpend(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_intrpend); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, - enum ath9k_int ints) +void ath9k_hw_disable_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_DISABLE); + (void) REG_READ(ah, AR_IER); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); + } +} +EXPORT_SYMBOL(ath9k_hw_disable_interrupts); + +void ath9k_hw_enable_interrupts(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (!(ah->imask & ATH9K_INT_GLOBAL)) + return; + + ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); + REG_WRITE(ah, AR_IER, AR_IER_ENABLE); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, + AR_INTR_MAC_IRQ); + REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); + + + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, + AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, + AR_INTR_SYNC_DEFAULT); + } + ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", + REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); +} +EXPORT_SYMBOL(ath9k_hw_enable_interrupts); + +void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) { enum ath9k_int omask = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); - ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); - - if (omask & ATH9K_INT_GLOBAL) { - ath_print(common, ATH_DBG_INTERRUPT, "disable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_DISABLE); - (void) REG_READ(ah, AR_IER); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_ASYNC_ENABLE); + if (!(ints & ATH9K_INT_GLOBAL)) + ath9k_hw_enable_interrupts(ah); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - (void) REG_READ(ah, AR_INTR_SYNC_ENABLE); - } - } + ath_print(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); /* TODO: global int Ref count */ mask = ints & ATH9K_INT_COMMON; @@ -946,24 +976,8 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } - if (ints & ATH9K_INT_GLOBAL) { - ath_print(common, ATH_DBG_INTERRUPT, "enable IER\n"); - REG_WRITE(ah, AR_IER, AR_IER_ENABLE); - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, - AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - - - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); - } - ath_print(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", - REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); - } + ath9k_hw_enable_interrupts(ah); - return omask; + return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 7c1a34d64f6d..538c676e799c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -669,6 +669,7 @@ enum ath9k_key_type { struct ath_hw; struct ath9k_channel; +enum ath9k_int; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); @@ -700,8 +701,9 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, - enum ath9k_int ints); +void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +void ath9k_hw_enable_interrupts(struct ath_hw *ah); +void ath9k_hw_disable_interrupts(struct ath_hw *ah); void ar9002_hw_attach_mac_ops(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b52f1cf8a603..ade9d7c16032 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -239,7 +239,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, * hardware at the new frequency, and then re-enable * the relevant bits of the h/w. */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); spin_lock_bh(&sc->rx.pcu_lock); @@ -653,7 +653,7 @@ void ath9k_tasklet(unsigned long data) ath_gen_timer_isr(sc->sc_ah); /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); ath9k_ps_restore(sc); } @@ -752,7 +752,7 @@ irqreturn_t ath_isr(int irq, void *dev) * interrupt; otherwise it will continue to * fire. */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); /* * Let the hal handle the event. We assume * it will clear whatever condition caused @@ -761,7 +761,7 @@ irqreturn_t ath_isr(int irq, void *dev) spin_lock(&common->cc_lock); ath9k_hw_proc_mib_event(ah); spin_unlock(&common->cc_lock); - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_enable_interrupts(ah); } if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) @@ -778,8 +778,8 @@ chip_reset: ath_debug_stat_interrupt(sc, status); if (sched) { - /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (ah->imask & ATH9K_INT_SWBA)); + /* turn off every interrupt */ + ath9k_hw_disable_interrupts(ah); tasklet_schedule(&sc->intr_tq); } @@ -937,7 +937,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) } /* Disable interrupts */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); /* clear pending tx frames */ @@ -980,7 +980,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ieee80211_stop_queues(hw); - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, retry_tx); spin_lock_bh(&sc->rx.pcu_lock); @@ -1394,7 +1394,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ - ath9k_hw_set_interrupts(ah, 0); + ath9k_hw_disable_interrupts(ah); spin_lock_bh(&sc->rx.pcu_lock); if (!(sc->sc_flags & SC_OP_INVALID)) { -- cgit v1.2.3 From 45684c75f9aa80eb477465bddcf79c9ad95206c7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Oct 2010 20:03:29 +0200 Subject: ath9k_hw: small optimization in ar9002_hw_get_isr ah->config.rx_intr_mitigation does not need to be checked before checking the rx interrupt mask for AR_ISR_RXMINTR or AR_ISR_RXINTM, as those interrupts will be masked out if rx interrupt mitigation is disabled. Avoid reading AR_ISR_S5_S twice by reordering the code to be more concise. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 32 ++++++++++------------------- 1 file changed, 11 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 50dda394f8be..f5ed73dac254 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -90,13 +90,10 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; - if (ah->config.rx_intr_mitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) - *masked |= ATH9K_INT_RX; - } - - if (isr & (AR_ISR_RXOK | AR_ISR_RXERR)) + if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM | + AR_ISR_RXOK | AR_ISR_RXERR)) *masked |= ATH9K_INT_RX; + if (isr & (AR_ISR_TXOK | AR_ISR_TXDESC | AR_ISR_TXERR | AR_ISR_TXEOL)) { @@ -118,14 +115,6 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) "receive FIFO overrun interrupt\n"); } - if (!AR_SREV_9100(ah)) { - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - u32 isr5 = REG_READ(ah, AR_ISR_S5_S); - if (isr5 & AR_ISR_S5_TIM_TIMER) - *masked |= ATH9K_INT_TIM_TIMER; - } - } - *masked |= mask2; } @@ -136,17 +125,18 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 s5_s; s5_s = REG_READ(ah, AR_ISR_S5_S); - if (isr & AR_ISR_GENTMR) { - ah->intr_gen_timer_trigger = + ah->intr_gen_timer_trigger = MS(s5_s, AR_ISR_S5_GENTIMER_TRIG); - ah->intr_gen_timer_thresh = - MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); + ah->intr_gen_timer_thresh = + MS(s5_s, AR_ISR_S5_GENTIMER_THRESH); - if (ah->intr_gen_timer_trigger) - *masked |= ATH9K_INT_GENTIMER; + if (ah->intr_gen_timer_trigger) + *masked |= ATH9K_INT_GENTIMER; - } + if ((s5_s & AR_ISR_S5_TIM_TIMER) && + !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + *masked |= ATH9K_INT_TIM_TIMER; } if (sync_cause) { -- cgit v1.2.3 From e0e9bc82fb0813fd353b0abbba0f1d6a680cc77c Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Oct 2010 20:03:30 +0200 Subject: ath9k_hw: optimize tx status descriptor processing Disassembly shows, that at least on MIPS, the compiler generates a lot of memory accesses to the same location in the descriptor field parsing. Since it is operating on uncached memory, this can be quite expensive in this hot path. Change the code a bit to help the compiler optimize it properly, and get rid of some unused fields in the ath_tx_status struct. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 81 +++++++++++++---------------- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 69 ++++++++++++------------ drivers/net/wireless/ath/ath9k/mac.h | 3 -- 3 files changed, 72 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index f5ed73dac254..3b4c52c9181c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -208,77 +208,68 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { struct ar5416_desc *ads = AR5416DESC(ds); + u32 status; - if ((ads->ds_txstatus9 & AR_TxDone) == 0) + status = ACCESS_ONCE(ads->ds_txstatus9); + if ((status & AR_TxDone) == 0) return -EINPROGRESS; - ts->ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); ts->ts_tstamp = ads->AR_SendTimestamp; ts->ts_status = 0; ts->ts_flags = 0; - if (ads->ds_txstatus1 & AR_FrmXmitOK) + if (status & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; + ts->tid = MS(status, AR_TxTid); + ts->ts_rateindex = MS(status, AR_FinalTxIdx); + ts->ts_seqnum = MS(status, AR_SeqNum); + + status = ACCESS_ONCE(ads->ds_txstatus0); + ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); + ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); + ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); + if (status & AR_TxBaStatus) { + ts->ts_flags |= ATH9K_TX_BA; + ts->ba_low = ads->AR_BaBitmapLow; + ts->ba_high = ads->AR_BaBitmapHigh; + } + + status = ACCESS_ONCE(ads->ds_txstatus1); + if (status & AR_FrmXmitOK) ts->ts_status |= ATH9K_TX_ACKED; - if (ads->ds_txstatus1 & AR_ExcessiveRetries) + if (status & AR_ExcessiveRetries) ts->ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) + if (status & AR_Filtered) ts->ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) { + if (status & AR_FIFOUnderrun) { ts->ts_status |= ATH9K_TXERR_FIFO; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ts->ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) + if (status & AR_TxTimerExpired) ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) + if (status & AR_DescCfgErr) ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + if (status & AR_TxDataUnderrun) { ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + if (status & AR_TxDelimUnderrun) { ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ts->ts_flags |= ATH9K_TX_BA; - ts->ba_low = ads->AR_BaBitmapLow; - ts->ba_high = ads->AR_BaBitmapHigh; - } + ts->ts_shortretry = MS(status, AR_RTSFailCnt); + ts->ts_longretry = MS(status, AR_DataFailCnt); + ts->ts_virtcol = MS(status, AR_VirtRetryCnt); - ts->ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ts->ts_rateindex) { - case 0: - ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ts->ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; - } + status = ACCESS_ONCE(ads->ds_txstatus5); + ts->ts_rssi = MS(status, AR_TxRSSICombined); + ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); + ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); + ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); - ts->ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ts->ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ts->ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ts->ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ts->ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ts->ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ts->ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); ts->evm0 = ads->AR_TxEVM0; ts->evm1 = ads->AR_TxEVM1; ts->evm2 = ads->AR_TxEVM2; - ts->ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ts->ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ts->ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ts->tid = MS(ads->ds_txstatus9, AR_TxTid); - ts->ts_antenna = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 3b424ca1ba84..10c812e353a6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -237,10 +237,12 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { struct ar9003_txs *ads; + u32 status; ads = &ah->ts_ring[ah->ts_tail]; - if ((ads->status8 & AR_TxDone) == 0) + status = ACCESS_ONCE(ads->status8); + if ((status & AR_TxDone) == 0) return -EINPROGRESS; ah->ts_tail = (ah->ts_tail + 1) % ah->ts_size; @@ -253,57 +255,58 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, return -EIO; } + if (status & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; + ts->ts_rateindex = MS(status, AR_FinalTxIdx); + ts->ts_seqnum = MS(status, AR_SeqNum); + ts->tid = MS(status, AR_TxTid); + ts->qid = MS(ads->ds_info, AR_TxQcuNum); ts->desc_id = MS(ads->status1, AR_TxDescId); - ts->ts_seqnum = MS(ads->status8, AR_SeqNum); ts->ts_tstamp = ads->status4; ts->ts_status = 0; ts->ts_flags = 0; - if (ads->status3 & AR_ExcessiveRetries) + status = ACCESS_ONCE(ads->status2); + ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); + ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); + ts->ts_rssi_ctl2 = MS(status, AR_TxRSSIAnt02); + if (status & AR_TxBaStatus) { + ts->ts_flags |= ATH9K_TX_BA; + ts->ba_low = ads->status5; + ts->ba_high = ads->status6; + } + + status = ACCESS_ONCE(ads->status3); + if (status & AR_ExcessiveRetries) ts->ts_status |= ATH9K_TXERR_XRETRY; - if (ads->status3 & AR_Filtered) + if (status & AR_Filtered) ts->ts_status |= ATH9K_TXERR_FILT; - if (ads->status3 & AR_FIFOUnderrun) { + if (status & AR_FIFOUnderrun) { ts->ts_status |= ATH9K_TXERR_FIFO; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->status8 & AR_TxOpExceeded) - ts->ts_status |= ATH9K_TXERR_XTXOP; - if (ads->status3 & AR_TxTimerExpired) + if (status & AR_TxTimerExpired) ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->status3 & AR_DescCfgErr) + if (status & AR_DescCfgErr) ts->ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->status3 & AR_TxDataUnderrun) { + if (status & AR_TxDataUnderrun) { ts->ts_flags |= ATH9K_TX_DATA_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->status3 & AR_TxDelimUnderrun) { + if (status & AR_TxDelimUnderrun) { ts->ts_flags |= ATH9K_TX_DELIM_UNDERRUN; ath9k_hw_updatetxtriglevel(ah, true); } - if (ads->status2 & AR_TxBaStatus) { - ts->ts_flags |= ATH9K_TX_BA; - ts->ba_low = ads->status5; - ts->ba_high = ads->status6; - } - - ts->ts_rateindex = MS(ads->status8, AR_FinalTxIdx); - - ts->ts_rssi = MS(ads->status7, AR_TxRSSICombined); - ts->ts_rssi_ctl0 = MS(ads->status2, AR_TxRSSIAnt00); - ts->ts_rssi_ctl1 = MS(ads->status2, AR_TxRSSIAnt01); - ts->ts_rssi_ctl2 = MS(ads->status2, AR_TxRSSIAnt02); - ts->ts_rssi_ext0 = MS(ads->status7, AR_TxRSSIAnt10); - ts->ts_rssi_ext1 = MS(ads->status7, AR_TxRSSIAnt11); - ts->ts_rssi_ext2 = MS(ads->status7, AR_TxRSSIAnt12); - ts->ts_shortretry = MS(ads->status3, AR_RTSFailCnt); - ts->ts_longretry = MS(ads->status3, AR_DataFailCnt); - ts->ts_virtcol = MS(ads->status3, AR_VirtRetryCnt); - ts->ts_antenna = 0; - - ts->tid = MS(ads->status8, AR_TxTid); + ts->ts_shortretry = MS(status, AR_RTSFailCnt); + ts->ts_longretry = MS(status, AR_DataFailCnt); + ts->ts_virtcol = MS(status, AR_VirtRetryCnt); + + status = ACCESS_ONCE(ads->status7); + ts->ts_rssi = MS(status, AR_TxRSSICombined); + ts->ts_rssi_ext0 = MS(status, AR_TxRSSIAnt10); + ts->ts_rssi_ext1 = MS(status, AR_TxRSSIAnt11); + ts->ts_rssi_ext2 = MS(status, AR_TxRSSIAnt12); memset(ads, 0, sizeof(*ads)); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 538c676e799c..fdc25074ca1f 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -104,13 +104,11 @@ struct ath_tx_status { u32 ts_tstamp; u16 ts_seqnum; u8 ts_status; - u8 ts_ratecode; u8 ts_rateindex; int8_t ts_rssi; u8 ts_shortretry; u8 ts_longretry; u8 ts_virtcol; - u8 ts_antenna; u8 ts_flags; int8_t ts_rssi_ctl0; int8_t ts_rssi_ctl1; @@ -121,7 +119,6 @@ struct ath_tx_status { u8 qid; u16 desc_id; u8 tid; - u8 pad[2]; u32 ba_low; u32 ba_high; u32 evm0; -- cgit v1.2.3 From 9fa23e1741404207c414fad69212a8763c138bf0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Oct 2010 20:03:31 +0200 Subject: ath9k: optimize/fix ANI RSSI processing ANI needs the RSSI average only in station mode, and only for tracking the signal strength of beacons of the AP that it is connected to. Adjust the code to track on the beacon RSSI, and store the average of that in the ath_wiphy struct. With these changes, we can get rid of this extra station lookup in the rx path, which saves precious CPU cycles. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/init.c | 2 ++ drivers/net/wireless/ath/ath9k/main.c | 6 +++-- drivers/net/wireless/ath/ath9k/recv.c | 38 ++++++++++---------------------- drivers/net/wireless/ath/ath9k/virtual.c | 1 + 5 files changed, 20 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 9b8e7e3fcebd..81fed83add7a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -270,7 +270,6 @@ struct ath_node { struct ath_atx_ac ac[WME_NUM_AC]; u16 maxampdu; u8 mpdudensity; - int last_rssi; }; #define AGGR_CLEANUP BIT(1) @@ -662,6 +661,7 @@ struct ath_wiphy { bool idle; int chan_idx; int chan_is_ht; + int last_rssi; }; void ath9k_tasklet(unsigned long data); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 95b41db0d86b..12f4fd79c907 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -703,6 +703,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; + struct ath_wiphy *aphy = hw->priv; struct ath_common *common; struct ath_hw *ah; int error = 0; @@ -752,6 +753,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work); INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work); sc->wiphy_scheduler_int = msecs_to_jiffies(500); + aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); ath_start_rfkill_poll(sc); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index ade9d7c16032..7185ef3a3bff 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -562,7 +562,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); - an->last_rssi = ATH_RSSI_DUMMY_MARKER; } } @@ -831,9 +830,11 @@ static u32 ath_get_extchanmode(struct ath_softc *sc, } static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf) { + struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -857,6 +858,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, ath_beacon_config(sc, vif); /* Reset rssi stats */ + aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; sc->sc_flags |= SC_OP_ANI_RUN; @@ -1998,7 +2000,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { ath_print(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); - ath9k_bss_assoc_info(sc, vif, bss_conf); + ath9k_bss_assoc_info(sc, hw, vif, bss_conf); } mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fddb0129bb57..c04a940550bd 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -962,36 +962,23 @@ static void ath9k_process_rssi(struct ath_common *common, struct ieee80211_hdr *hdr, struct ath_rx_status *rx_stats) { + struct ath_wiphy *aphy = hw->priv; struct ath_hw *ah = common->ah; - struct ieee80211_sta *sta; - struct ath_node *an; - int last_rssi = ATH_RSSI_DUMMY_MARKER; + int last_rssi; __le16 fc; + if (ah->opmode != NL80211_IFTYPE_STATION) + return; + fc = hdr->frame_control; + if (!ieee80211_is_beacon(fc) || + compare_ether_addr(hdr->addr3, common->curbssid)) + return; - rcu_read_lock(); - /* - * XXX: use ieee80211_find_sta! This requires quite a bit of work - * under the current ath9k virtual wiphy implementation as we have - * no way of tying a vif to wiphy. Typically vifs are attached to - * at least one sdata of a wiphy on mac80211 but with ath9k virtual - * wiphy you'd have to iterate over every wiphy and each sdata. - */ - if (is_multicast_ether_addr(hdr->addr1)) - sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL); - else - sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, hdr->addr1); - - if (sta) { - an = (struct ath_node *) sta->drv_priv; - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && - !rx_stats->rs_moreaggr) - ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi); - last_rssi = an->last_rssi; - } - rcu_read_unlock(); + if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) + ATH_RSSI_LPF(aphy->last_rssi, rx_stats->rs_rssi); + last_rssi = aphy->last_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) rx_stats->rs_rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); @@ -999,8 +986,7 @@ static void ath9k_process_rssi(struct ath_common *common, rx_stats->rs_rssi = 0; /* Update Beacon RSSI, this is used by ANI. */ - if (ieee80211_is_beacon(fc)) - ah->stats.avgbrssi = rx_stats->rs_rssi; + ah->stats.avgbrssi = rx_stats->rs_rssi; } /* diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index ec7cf5ee56bc..cb6c48be1245 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -107,6 +107,7 @@ int ath9k_wiphy_add(struct ath_softc *sc) aphy->sc = sc; aphy->hw = hw; sc->sec_wiphy[i] = aphy; + aphy->last_rssi = ATH_RSSI_DUMMY_MARKER; spin_unlock_bh(&sc->wiphy_lock); memcpy(addr, common->macaddr, ETH_ALEN); -- cgit v1.2.3 From 8eb1dabbd10e067cff671935d3e0c819f8e80d54 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Oct 2010 20:03:32 +0200 Subject: ath9k: remove a redundant call to ath9k_hw_gettsf32 When the timer_next argument to ath9k_gen_timer_start is behind the tsf value, tsf + timer_period is used, which is what ath_btcoex_period_timer was setting it to. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/gpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index db9c6fed799c..6a1a482f9dc3 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -310,10 +310,8 @@ static void ath_btcoex_period_timer(unsigned long data) timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; - ath9k_gen_timer_start(ah, - btcoex->no_stomp_timer, - (ath9k_hw_gettsf32(ah) + - timer_period), timer_period * 10); + ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0, + timer_period * 10); btcoex->hw_timer_enabled = true; } -- cgit v1.2.3 From 744bcb42a1ff1b9200e82dd074468877e31ff161 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Oct 2010 20:03:33 +0200 Subject: ath9k_hw: make ath9k_hw_gettsf32 static It is now only used in hw.c Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 3 +-- drivers/net/wireless/ath/ath9k/hw.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cc13ee117823..d37a8ad03d74 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2312,11 +2312,10 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask) return timer_table->gen_timer_index[b]; } -u32 ath9k_hw_gettsf32(struct ath_hw *ah) +static u32 ath9k_hw_gettsf32(struct ath_hw *ah) { return REG_READ(ah, AR_TSF_L32); } -EXPORT_SYMBOL(ath9k_hw_gettsf32); struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index d032939768b0..e68204ae899c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -892,7 +892,6 @@ void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_isr(struct ath_hw *hw); -u32 ath9k_hw_gettsf32(struct ath_hw *ah); void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len); -- cgit v1.2.3 From 191d6a1186f65bc86c24b9d6d9d91acc155285ba Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 15 Oct 2010 13:27:49 -0700 Subject: ath9k: fix sparse complaint on aphy for debugfs This fixes this sparse complaint: CHECK drivers/net/wireless/ath/ath9k/debug.c drivers/net/wireless/ath/ath9k/debug.c:548:34: warning: symbol 'aphy' shadows an earlier one drivers/net/wireless/ath/ath9k/debug.c:491:26: originally declared here Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/debug.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 43e71a944cb1..a4052711eca8 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -461,16 +461,16 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, /* Put variable-length stuff down here, and check for overflows. */ for (i = 0; i < sc->num_sec_wiphy; i++) { - struct ath_wiphy *aphy = sc->sec_wiphy[i]; - if (aphy == NULL) + struct ath_wiphy *aphy_tmp = sc->sec_wiphy[i]; + if (aphy_tmp == NULL) continue; - chan = aphy->hw->conf.channel; + chan = aphy_tmp->hw->conf.channel; len += snprintf(buf + len, sizeof(buf) - len, "secondary: %s (%s chan=%d ht=%d)\n", - wiphy_name(aphy->hw->wiphy), - ath_wiphy_state_str(aphy->state), + wiphy_name(aphy_tmp->hw->wiphy), + ath_wiphy_state_str(aphy_tmp->state), ieee80211_frequency_to_channel(chan->center_freq), - aphy->chan_is_ht); + aphy_tmp->chan_is_ht); } if (len > sizeof(buf)) len = sizeof(buf); -- cgit v1.2.3 From f0e94b479c987abef17eb18e5c8e0ed178d00cd4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 16 Oct 2010 00:36:17 +0200 Subject: ath9k: Convert to new PCI PM framework The ath9k driver uses the legacy PCI power management (suspend and resume) callbacks that apparently cause intermittent problems to happen (the adapter sometimes doesn't resume correctly on my Acer Ferrari One). Make it use the new PCI PM and let the PCI core code handle the PCI-specific details of power transitions. Signed-off-by: Rafael J. Wysocki Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/pci.c | 40 ++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index b5b651413e77..6605bc2c2036 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -247,34 +247,25 @@ static void ath_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int ath_pci_suspend(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } -static int ath_pci_resume(struct pci_dev *pdev) +static int ath_pci_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; u32 val; - int err; - - pci_restore_state(pdev); - - err = pci_enable_device(pdev); - if (err) - return err; /* * Suspend/Resume resets the PCI configuration space, so we have to @@ -293,7 +284,23 @@ static int ath_pci_resume(struct pci_dev *pdev) return 0; } -#endif /* CONFIG_PM */ +static const struct dev_pm_ops ath9k_pm_ops = { + .suspend = ath_pci_suspend, + .resume = ath_pci_resume, + .freeze = ath_pci_suspend, + .thaw = ath_pci_resume, + .poweroff = ath_pci_suspend, + .restore = ath_pci_resume, +}; + +#define ATH9K_PM_OPS (&ath9k_pm_ops) + +#else /* !CONFIG_PM */ + +#define ATH9K_PM_OPS NULL + +#endif /* !CONFIG_PM */ + MODULE_DEVICE_TABLE(pci, ath_pci_id_table); @@ -302,10 +309,7 @@ static struct pci_driver ath_pci_driver = { .id_table = ath_pci_id_table, .probe = ath_pci_probe, .remove = ath_pci_remove, -#ifdef CONFIG_PM - .suspend = ath_pci_suspend, - .resume = ath_pci_resume, -#endif /* CONFIG_PM */ + .driver.pm = ATH9K_PM_OPS, }; int ath_pci_init(void) -- cgit v1.2.3 From ada9f1cacb66b74a68254521bb5e3ca4eb8fa871 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 16 Oct 2010 01:01:48 +0200 Subject: ath9k_hw: optimize all descriptor access functions Because all of the descriptor data structures are marked as __packed, GCC assumes the worst case wrt. alignment and generates unaligned load/store instructions on MIPS for access to all fields. Since descriptors always have to be 4-byte-aligned, we can just mark the data structures with __aligned(4), which allows GCC to generate much more efficient code. Verified through disassembly and OProfile comparisons. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_mac.h | 6 +++--- drivers/net/wireless/ath/ath9k/mac.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h index 9f2cea70a840..45cc7e80436c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h @@ -65,7 +65,7 @@ struct ar9003_rxs { u32 status9; u32 status10; u32 status11; -} __packed; +} __packed __aligned(4); /* Transmit Control Descriptor */ struct ar9003_txc { @@ -93,7 +93,7 @@ struct ar9003_txc { u32 ctl21; /* DMA control 21 */ u32 ctl22; /* DMA control 22 */ u32 pad[9]; /* pad to cache line (128 bytes/32 dwords) */ -} __packed; +} __packed __aligned(4); struct ar9003_txs { u32 ds_info; @@ -105,7 +105,7 @@ struct ar9003_txs { u32 status6; u32 status7; u32 status8; -} __packed; +} __packed __aligned(4); void ar9003_hw_attach_mac_ops(struct ath_hw *hw); void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index fdc25074ca1f..22907e21cc46 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -237,7 +237,7 @@ struct ath_desc { u32 ds_ctl1; u32 ds_hw[20]; void *ds_vdata; -} __packed; +} __packed __aligned(4); #define ATH9K_TXDESC_CLRDMASK 0x0001 #define ATH9K_TXDESC_NOACK 0x0002 @@ -307,7 +307,7 @@ struct ar5416_desc { u32 status8; } rx; } u; -} __packed; +} __packed __aligned(4); #define AR5416DESC(_ds) ((struct ar5416_desc *)(_ds)) #define AR5416DESC_CONST(_ds) ((const struct ar5416_desc *)(_ds)) -- cgit v1.2.3 From 123f5b8e6f411d342f2fc8a15c4d9349ace5074a Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 18 Oct 2010 11:37:17 +0530 Subject: ath9k: Remove the median function in rate control With the current rate control selection method the median function is nowhere used, so remove it. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 89978d71617f..1095e18b3627 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -381,25 +381,6 @@ static const struct ath_rate_table ar5416_11g_ratetable = { static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table, struct ieee80211_tx_rate *rate); -static inline int8_t median(int8_t a, int8_t b, int8_t c) -{ - if (a >= b) { - if (b >= c) - return b; - else if (a > c) - return c; - else - return a; - } else { - if (a >= c) - return a; - else if (b >= c) - return c; - else - return b; - } -} - static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv) { -- cgit v1.2.3 From 3dd0923de491d72a041f82a9d0aaccc473fd2c42 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 19 Oct 2010 16:56:48 +0900 Subject: ath5k: Optimize descriptor alignment Similar to Felix Fietkau "ath9k_hw: optimize all descriptor access functions" (13db2a80244908833502189a24de82a856668b8a). Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/desc.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/desc.h b/drivers/net/wireless/ath/ath5k/desc.h index b2adb2a281c2..2509d0bf037d 100644 --- a/drivers/net/wireless/ath/ath5k/desc.h +++ b/drivers/net/wireless/ath/ath5k/desc.h @@ -26,7 +26,7 @@ struct ath5k_hw_rx_ctl { u32 rx_control_0; /* RX control word 0 */ u32 rx_control_1; /* RX control word 1 */ -} __packed; +} __packed __aligned(4); /* RX control word 1 fields/flags */ #define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff /* data buffer length */ @@ -39,7 +39,7 @@ struct ath5k_hw_rx_ctl { struct ath5k_hw_rx_status { u32 rx_status_0; /* RX status word 0 */ u32 rx_status_1; /* RX status word 1 */ -} __packed; +} __packed __aligned(4); /* 5210/5211 */ /* RX status word 0 fields/flags */ @@ -129,7 +129,7 @@ enum ath5k_phy_error_code { struct ath5k_hw_2w_tx_ctl { u32 tx_control_0; /* TX control word 0 */ u32 tx_control_1; /* TX control word 1 */ -} __packed; +} __packed __aligned(4); /* TX control word 0 fields/flags */ #define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */ @@ -185,7 +185,7 @@ struct ath5k_hw_4w_tx_ctl { u32 tx_control_1; /* TX control word 1 */ u32 tx_control_2; /* TX control word 2 */ u32 tx_control_3; /* TX control word 3 */ -} __packed; +} __packed __aligned(4); /* TX control word 0 fields/flags */ #define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff /* frame length */ @@ -244,7 +244,7 @@ struct ath5k_hw_4w_tx_ctl { struct ath5k_hw_tx_status { u32 tx_status_0; /* TX status word 0 */ u32 tx_status_1; /* TX status word 1 */ -} __packed; +} __packed __aligned(4); /* TX status word 0 fields/flags */ #define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 /* TX success */ @@ -282,7 +282,7 @@ struct ath5k_hw_tx_status { struct ath5k_hw_5210_tx_desc { struct ath5k_hw_2w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; -} __packed; +} __packed __aligned(4); /* * 5212 hardware TX descriptor @@ -290,7 +290,7 @@ struct ath5k_hw_5210_tx_desc { struct ath5k_hw_5212_tx_desc { struct ath5k_hw_4w_tx_ctl tx_ctl; struct ath5k_hw_tx_status tx_stat; -} __packed; +} __packed __aligned(4); /* * Common hardware RX descriptor @@ -298,7 +298,7 @@ struct ath5k_hw_5212_tx_desc { struct ath5k_hw_all_rx_desc { struct ath5k_hw_rx_ctl rx_ctl; struct ath5k_hw_rx_status rx_stat; -} __packed; +} __packed __aligned(4); /* * Atheros hardware DMA descriptor @@ -313,7 +313,7 @@ struct ath5k_desc { struct ath5k_hw_5212_tx_desc ds_tx5212; struct ath5k_hw_all_rx_desc ds_rx; } ud; -} __packed; +} __packed __aligned(4); #define AR5K_RXDESC_INTREQ 0x0020 -- cgit v1.2.3 From edb40a23c8dc5b5be219bf4561074b6233bba65f Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Tue, 19 Oct 2010 16:56:54 +0900 Subject: ath5k: Add channel time to survey data Include the channel utilization (busy, rx, tx) in the survey results. Signed-off-by: Bruno Randolf Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 8251946842e6..484aad5b11b5 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -3206,14 +3206,32 @@ static int ath5k_get_survey(struct ieee80211_hw *hw, int idx, { struct ath5k_softc *sc = hw->priv; struct ieee80211_conf *conf = &hw->conf; + struct ath_common *common = ath5k_hw_common(sc->ah); + struct ath_cycle_counters *cc = &common->cc_survey; + unsigned int div = common->clockrate * 1000; - if (idx != 0) + if (idx != 0) return -ENOENT; survey->channel = conf->channel; survey->filled = SURVEY_INFO_NOISE_DBM; survey->noise = sc->ah->ah_noise_floor; + spin_lock_bh(&common->cc_lock); + ath_hw_cycle_counters_update(common); + if (cc->cycles > 0) { + survey->filled |= SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_RX | + SURVEY_INFO_CHANNEL_TIME_TX; + survey->channel_time += cc->cycles / div; + survey->channel_time_busy += cc->rx_busy / div; + survey->channel_time_rx += cc->rx_frame / div; + survey->channel_time_tx += cc->tx_frame / div; + } + memset(cc, 0, sizeof(*cc)); + spin_unlock_bh(&common->cc_lock); + return 0; } -- cgit v1.2.3 From c36940e678fc30779c99246c034deca1fed61ae4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Nov 2010 11:27:16 +0000 Subject: fbdev: sh_mobile_hdmi: add support for more precise HDMI clock configuration The HDMI clock has to be reconfigured for different video modes. However, the precision of the supplying SoC clock on SH-Mobile systems is often insufficient. This patch allows to additionally reconfigure the parent clock to achieve the optimal HDMI clock frequency, in case this is supported by the platform. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 112 +++++++++++++++++++++++++---------------- include/video/sh_mobile_hdmi.h | 3 ++ 2 files changed, 71 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index d7df10315d8d..ef41c215abae 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -685,11 +685,21 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) } static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, - const struct fb_videomode *mode) + const struct fb_videomode *mode, + unsigned long *hdmi_rate, unsigned long *parent_rate) { - long target = PICOS2KHZ(mode->pixclock) * 1000, - rate = clk_round_rate(hdmi->hdmi_clk, target); - unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; + unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error; + struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; + + *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target); + if ((long)*hdmi_rate < 0) + *hdmi_rate = clk_get_rate(hdmi->hdmi_clk); + + rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX; + if (rate_error && pdata->clk_optimize_parent) + rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate); + else if (clk_get_parent(hdmi->hdmi_clk)) + *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk)); dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", mode->left_margin, mode->xres, @@ -697,14 +707,15 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, mode->upper_margin, mode->yres, mode->lower_margin, mode->vsync_len); - dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, - rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, - mode->refresh); + dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target, + rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, + mode->refresh, *parent_rate); return rate_error; } -static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) +static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, + unsigned long *parent_rate) { struct fb_var_screeninfo tmpvar; struct fb_var_screeninfo *var = &tmpvar; @@ -754,11 +765,14 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) for (i = 0, mode = hdmi->monspec.modedb; f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; i++, mode++) { - unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); + unsigned long rate_error; /* No interest in unmatching modes */ if (f_width != mode->xres || f_height != mode->yres) continue; + + rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); + if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) /* * Exact match if either the refresh rate matches or it @@ -802,7 +816,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (modelist) { found = &modelist->mode; - found_rate_error = sh_hdmi_rate_error(hdmi, found); + found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate); } } @@ -810,10 +824,6 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (!found) return -ENXIO; - dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", - modelist ? "default" : "EDID", found->xres, found->yres, - found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); - if ((found->xres == 720 && found->yres == 480) || (found->xres == 1280 && found->yres == 720) || (found->xres == 1920 && found->yres == 1080)) @@ -821,6 +831,11 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) else hdmi->preprogrammed_mode = false; + dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", + modelist ? "default" : "EDID", hdmi->preprogrammed_mode ? "VIC" : "external", + found->xres, found->yres, found->refresh, + PICOS2KHZ(found->pixclock) * 1000, found_rate_error); + fb_videomode_to_var(&hdmi->var, found); sh_hdmi_external_video_param(hdmi); @@ -972,39 +987,38 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) /** * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock - * @hdmi: driver context - * @pixclock: pixel clock period in picoseconds - * return: configured positive rate if successful - * 0 if couldn't set the rate, but managed to enable the clock - * negative error, if couldn't enable the clock + * @hdmi: driver context + * @hdmi_rate: HDMI clock frequency in Hz + * @parent_rate: if != 0 - set parent clock rate for optimal precision + * return: configured positive rate if successful + * 0 if couldn't set the rate, but managed to enable the + * clock, negative error, if couldn't enable the clock */ -static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) +static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, + unsigned long parent_rate) { - long rate; + struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; int ret; - rate = PICOS2KHZ(pixclock) * 1000; - rate = clk_round_rate(hdmi->hdmi_clk, rate); - if (rate > 0) { - ret = clk_set_rate(hdmi->hdmi_clk, rate); + if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { + ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate); if (ret < 0) { - dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); - rate = 0; + dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret); + hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate); } else { - dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); + dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate); } - } else { - rate = 0; - dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); } - ret = clk_enable(hdmi->hdmi_clk); + ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate); if (ret < 0) { - dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); - return ret; + dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret); + hdmi_rate = 0; + } else { + dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate); } - return rate; + return hdmi_rate; } /* Hotplug interrupt occurred, read EDID */ @@ -1024,16 +1038,17 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { + unsigned long parent_rate = 0, hdmi_rate; + /* A device has been plugged in */ pm_runtime_get_sync(hdmi->dev); - ret = sh_hdmi_read_edid(hdmi); + ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); if (ret < 0) goto out; /* Reconfigure the clock */ - clk_disable(hdmi->hdmi_clk); - ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); + ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); if (ret < 0) goto out; @@ -1166,13 +1181,22 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } - /* Some arbitrary relaxed pixclock just to get things started */ - rate = sh_hdmi_clk_configure(hdmi, 37037); + /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ + rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); + if (rate > 0) + rate = sh_hdmi_clk_configure(hdmi, rate, 0); + if (rate < 0) { ret = rate; goto erate; } + ret = clk_enable(hdmi->hdmi_clk); + if (ret < 0) { + dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); + goto erate; + } + dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { @@ -1190,10 +1214,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); - /* Product and revision IDs are 0 in sh-mobile version */ - dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", - hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); - /* Set up LCDC callbacks */ board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; @@ -1206,6 +1226,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); + /* Product and revision IDs are 0 in sh-mobile version */ + dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", + hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); + ret = request_irq(irq, sh_hdmi_hotplug, 0, dev_name(&pdev->dev), hdmi); if (ret < 0) { diff --git a/include/video/sh_mobile_hdmi.h b/include/video/sh_mobile_hdmi.h index 1e1aa54ab2e4..b56932927d0a 100644 --- a/include/video/sh_mobile_hdmi.h +++ b/include/video/sh_mobile_hdmi.h @@ -13,6 +13,7 @@ struct sh_mobile_lcdc_chan_cfg; struct device; +struct clk; /* * flags format @@ -33,6 +34,8 @@ struct sh_mobile_hdmi_info { struct sh_mobile_lcdc_chan_cfg *lcd_chan; struct device *lcd_dev; unsigned int flags; + long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq, + unsigned long *parent_freq); }; #endif -- cgit v1.2.3 From 8c183ecee23991dd6c0476a537c6bae8afd2567e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Nov 2010 11:27:20 +0000 Subject: fbdev: sh_mobile_hdmi: improve support for more video modes Configure pre-programmed VIC modes for VGA (640x480@60) and 720x576@50 modes, change PHY mode selection to be based on pixel clock frequency. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index ef41c215abae..3adffe6acafc 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -466,7 +466,7 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - if (hdmi->var.yres > 480) { + if (hdmi->var.pixclock < 30000) { /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ /* * [1:0] Speed_A @@ -570,8 +570,12 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) */ if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) vic = 16; + else if (hdmi->var.yres == 576 && hdmi->var.xres == 720) + vic = 17; else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) vic = 2; + else if (hdmi->var.yres == 480 && hdmi->var.xres == 640) + vic = 1; else vic = 4; hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); @@ -824,9 +828,11 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, if (!found) return -ENXIO; - if ((found->xres == 720 && found->yres == 480) || - (found->xres == 1280 && found->yres == 720) || - (found->xres == 1920 && found->yres == 1080)) + if ((found->xres == 640 && found->yres == 480 && found->refresh == 60) || + (found->xres == 720 && found->yres == 480 && found->refresh == 60) || + (found->xres == 720 && found->yres == 576 && found->refresh == 50) || + (found->xres == 1280 && found->yres == 720 && found->refresh == 60) || + (found->xres == 1920 && found->yres == 1080 && found->refresh == 60)) hdmi->preprogrammed_mode = true; else hdmi->preprogrammed_mode = false; -- cgit v1.2.3 From d2ecbab5960d9814a269d36723647d6ef391ba8f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 4 Nov 2010 11:06:06 +0000 Subject: fbdev: sh_mobile_lcdc: increase maximum framebuffer size to support 1080p LCDC hardware can support 1920x1080 formats, adjust the driver to cover them. Besides, instead of guessing some "reasonable" validity checks, only verify values in .fb_check_var(), that we are sure, we cannot support. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 9b1364723c65..993be381c21c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) -#define DEFAULT_XRES 1280 -#define DEFAULT_YRES 1024 +#define MAX_XRES 1920 +#define MAX_YRES 1080 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, @@ -914,22 +914,12 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in { struct sh_mobile_lcdc_chan *ch = info->par; - if (var->xres < 160 || var->xres > 1920 || - var->yres < 120 || var->yres > 1080 || - var->left_margin < 32 || var->left_margin > 320 || - var->right_margin < 12 || var->right_margin > 240 || - var->upper_margin < 12 || var->upper_margin > 120 || - var->lower_margin < 1 || var->lower_margin > 64 || - var->hsync_len < 32 || var->hsync_len > 240 || - var->vsync_len < 2 || var->vsync_len > 64 || - var->pixclock < 6000 || var->pixclock > 40000 || + if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { - dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", - var->xres, var->yres, - var->left_margin, var->right_margin, - var->upper_margin, var->lower_margin, - var->hsync_len, var->vsync_len, - var->pixclock); + dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n", + var->left_margin, var->xres, var->right_margin, var->hsync_len, + var->upper_margin, var->yres, var->lower_margin, var->vsync_len, + PICOS2KHZ(var->pixclock)); return -EINVAL; } return 0; @@ -1226,7 +1216,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } if (!mode) - max_size = DEFAULT_XRES * DEFAULT_YRES; + max_size = MAX_XRES * MAX_YRES; else if (max_cfg) dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", max_cfg->xres, max_cfg->yres); -- cgit v1.2.3 From 0ea2af1c15b730dba9ce741420352d298bcd7862 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 4 Nov 2010 11:06:17 +0000 Subject: fbdev: sh_mobile_hdmi: add support for 1080p modes Add support for 3 more preprogrammed video modes: 1080p at 24, 50, and 60Hz. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 57 ++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 3adffe6acafc..8338bd4d277e 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -209,7 +209,8 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; /* hot-plug status */ - bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ + u8 preprogrammed_vic; /* use a pre-programmed VIC or + the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; @@ -342,7 +343,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ - if (!hdmi->preprogrammed_mode) + if (!hdmi->preprogrammed_vic) hdmi_write(hdmi, sync | 1 | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } @@ -466,7 +467,18 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - if (hdmi->var.pixclock < 30000) { + if (hdmi->var.pixclock < 10000) { + /* for 1080p8bit 148MHz */ + hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } else if (hdmi->var.pixclock < 30000) { /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ /* * [1:0] Speed_A @@ -524,6 +536,7 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) { + struct fb_var_screeninfo *var = &hdmi->var; u8 vic; /* AVI InfoFrame */ @@ -565,17 +578,11 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); /* - * VIC = 1280 x 720p: ignored if external config is used - * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode + * VIC should be ignored if external config is used, so, we could just use 0, + * but play safe and use a valid value in any case just in case */ - if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) - vic = 16; - else if (hdmi->var.yres == 576 && hdmi->var.xres == 720) - vic = 17; - else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) - vic = 2; - else if (hdmi->var.yres == 480 && hdmi->var.xres == 640) - vic = 1; + if (hdmi->preprogrammed_vic) + vic = hdmi->preprogrammed_vic; else vic = 4; hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); @@ -828,17 +835,25 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, if (!found) return -ENXIO; - if ((found->xres == 640 && found->yres == 480 && found->refresh == 60) || - (found->xres == 720 && found->yres == 480 && found->refresh == 60) || - (found->xres == 720 && found->yres == 576 && found->refresh == 50) || - (found->xres == 1280 && found->yres == 720 && found->refresh == 60) || - (found->xres == 1920 && found->yres == 1080 && found->refresh == 60)) - hdmi->preprogrammed_mode = true; + if (found->xres == 640 && found->yres == 480 && found->refresh == 60) + hdmi->preprogrammed_vic = 1; + else if (found->xres == 720 && found->yres == 480 && found->refresh == 60) + hdmi->preprogrammed_vic = 2; + else if (found->xres == 720 && found->yres == 576 && found->refresh == 50) + hdmi->preprogrammed_vic = 17; + else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60) + hdmi->preprogrammed_vic = 4; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24) + hdmi->preprogrammed_vic = 32; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50) + hdmi->preprogrammed_vic = 31; + else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60) + hdmi->preprogrammed_vic = 16; else - hdmi->preprogrammed_mode = false; + hdmi->preprogrammed_vic = 0; dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", - modelist ? "default" : "EDID", hdmi->preprogrammed_mode ? "VIC" : "external", + modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", found->xres, found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); -- cgit v1.2.3 From 830539d14379d0f5cb07832a3e4466418011f843 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 10 Nov 2010 17:51:44 +0900 Subject: fbdev: sh_mobile_lcdcfb: fix up compiler warnings. CC drivers/video/sh_mobile_lcdcfb.o drivers/video/sh_mobile_lcdcfb.c: In function 'sh_mobile_check_var': drivers/video/sh_mobile_lcdcfb.c:922: warning: format '%u' expects type 'unsigned int', but argument 11 has type 'long unsigned int' Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 993be381c21c..37419ba2c29a 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -916,7 +916,7 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { - dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %ukHz!\n", + dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n", var->left_margin, var->xres, var->right_margin, var->hsync_len, var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); -- cgit v1.2.3 From c724d07a56e60e91b0aa75193f86fb000545ffe4 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Wed, 10 Nov 2010 17:54:20 +0900 Subject: fbdev: sh_mobile_hdmi: fix up compiler warnings. CC drivers/video/sh_mobile_hdmi.o drivers/video/sh_mobile_hdmi.c: In function 'sh_hdmi_avi_infoframe_setup': drivers/video/sh_mobile_hdmi.c:539: warning: unused variable 'var' drivers/video/sh_mobile_hdmi.c: In function 'sh_hdmi_clk_configure': drivers/video/sh_mobile_hdmi.c:1021: warning: unused variable 'pdata' Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 8338bd4d277e..3b4cf987fb43 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -536,7 +536,6 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) { - struct fb_var_screeninfo *var = &hdmi->var; u8 vic; /* AVI InfoFrame */ @@ -1018,7 +1017,6 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, unsigned long parent_rate) { - struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; int ret; if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { -- cgit v1.2.3 From 2686b4b408c25349aee7b35558722d5730d67224 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 12:39:48 +0100 Subject: ARM: 6311/2: mmci: work with only one irq The DBx500 variants have only one IRQ line hooked up. Allow these (and any other implementations which choose to use only one irq) to work by directing the PIO interrupts also to the first IRQ line. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 50 ++++++++++++++++++++++++++++++++++++++++--------- drivers/mmc/host/mmci.h | 6 ++++++ 2 files changed, 47 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87b4fc6c98c2..ed700a5b03ae 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -129,10 +129,26 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) spin_lock(&host->lock); } +static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +{ + void __iomem *base = host->base; + + if (host->singleirq) { + unsigned int mask0 = readl(base + MMCIMASK0); + + mask0 &= ~MCI_IRQ1MASK; + mask0 |= mask; + + writel(mask0, base + MMCIMASK0); + } + + writel(mask, base + MMCIMASK1); +} + static void mmci_stop_data(struct mmci_host *host) { writel(0, host->base + MMCIDATACTRL); - writel(0, host->base + MMCIMASK1); + mmci_set_mask1(host, 0); host->data = NULL; } @@ -198,7 +214,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); - writel(irqmask, base + MMCIMASK1); + mmci_set_mask1(host, irqmask); } static void @@ -437,7 +453,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * "any data available" mode. */ if (status & MCI_RXACTIVE && host->size < variant->fifosize) - writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1); + mmci_set_mask1(host, MCI_RXDATAAVLBLMASK); /* * If we run out of data, disable the data IRQs; this @@ -446,7 +462,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) * stops us racing with our data end IRQ. */ if (host->size == 0) { - writel(0, base + MMCIMASK1); + mmci_set_mask1(host, 0); writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0); } @@ -469,6 +485,14 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) struct mmc_data *data; status = readl(host->base + MMCISTATUS); + + if (host->singleirq) { + if (status & readl(host->base + MMCIMASK1)) + mmci_pio_irq(irq, dev_id); + + status &= ~MCI_IRQ1MASK; + } + status &= readl(host->base + MMCIMASK0); writel(status, host->base + MMCICLEAR); @@ -635,6 +659,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) struct variant_data *variant = id->data; struct mmci_host *host; struct mmc_host *mmc; + unsigned int mask; int ret; /* must have platform data */ @@ -806,11 +831,17 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) if (ret) goto unmap; - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host); - if (ret) - goto irq0_free; + if (dev->irq[1] == NO_IRQ) + host->singleirq = true; + else { + ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, + DRIVER_NAME " (pio)", host); + if (ret) + goto irq0_free; + } - writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mask = MCI_IRQENABLE; + writel(mask, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); @@ -864,7 +895,8 @@ static int __devexit mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); free_irq(dev->irq[0], host); - free_irq(dev->irq[1], host); + if (!host->singleirq) + free_irq(dev->irq[1], host); if (host->gpio_wp != -ENOSYS) gpio_free(host->gpio_wp); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 4ae887fc0189..b4e48bde1b4e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -139,6 +139,11 @@ MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK) +/* These interrupts are directed to IRQ1 when two IRQ lines are available */ +#define MCI_IRQ1MASK \ + (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ + MCI_TXFIFOHALFEMPTYMASK) + #define NR_SG 16 struct clk; @@ -154,6 +159,7 @@ struct mmci_host { int gpio_cd; int gpio_wp; int gpio_cd_irq; + bool singleirq; unsigned int data_xfered; -- cgit v1.2.3 From f20f8f21e0402c785c342547f7e49eafc42cfb52 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 13:41:24 +0100 Subject: ARM: 6399/3: mmci: handle broken MCI_DATABLOCKEND hardware On the U300 the MCI_DATAEND and MCI_DATABLOCKEND IRQs can arrive out-of-order. Replace an ugly #ifdef hack with a proper runtime solution which models what is really happening. In the U300 DMA mode and on all Ux500 models, the MCI_DATABLOCKEND flag isn't properly cleared in hardware following and ACK leading to all kind of weird behaviour when the flag is still up in subsequent interrupts, so we add two flags indicating the error and handle this runtime. Cc: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 93 ++++++++++++++++++++++++++++++++++++++++--------- drivers/mmc/host/mmci.h | 3 ++ 2 files changed, 80 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ed700a5b03ae..976c9d0e8080 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -45,6 +45,10 @@ static unsigned int fmax = 515633; * is asserted (likewise for RX) * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY * is asserted (likewise for RX) + * @broken_blockend: the MCI_DATABLOCKEND is broken on the hardware + * and will not work at all. + * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when + * using DMA. */ struct variant_data { unsigned int clkreg; @@ -52,6 +56,8 @@ struct variant_data { unsigned int datalength_bits; unsigned int fifosize; unsigned int fifohalfsize; + bool broken_blockend; + bool broken_blockend_dma; }; static struct variant_data variant_arm = { @@ -65,6 +71,7 @@ static struct variant_data variant_u300 = { .fifohalfsize = 8 * 4, .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, + .broken_blockend_dma = true, }; static struct variant_data variant_ux500 = { @@ -73,6 +80,7 @@ static struct variant_data variant_ux500 = { .clkreg = MCI_CLK_ENABLE, .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, + .broken_blockend = true, }; /* * This must be called with host->lock held @@ -178,6 +186,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) host->data = data; host->size = data->blksz * data->blocks; host->data_xfered = 0; + host->blockend = false; + host->dataend = false; mmci_init_sg(host, data); @@ -249,20 +259,9 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { - if (status & MCI_DATABLOCKEND) { - host->data_xfered += data->blksz; -#ifdef CONFIG_ARCH_U300 - /* - * On the U300 some signal or other is - * badly routed so that a data write does - * not properly terminate with a MCI_DATAEND - * status flag. This quirk will make writes - * work again. - */ - if (data->flags & MMC_DATA_WRITE) - status |= MCI_DATAEND; -#endif - } + struct variant_data *variant = host->variant; + + /* First check for errors */ if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ (status %08x)\n", status); if (status & MCI_DATACRCFAIL) @@ -271,7 +270,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, data->error = -ETIMEDOUT; else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) data->error = -EIO; - status |= MCI_DATAEND; + + /* Force-complete the transaction */ + host->blockend = true; + host->dataend = true; /* * We hit an error condition. Ensure that any data @@ -289,9 +291,64 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, local_irq_restore(flags); } } - if (status & MCI_DATAEND) { + + /* + * On ARM variants in PIO mode, MCI_DATABLOCKEND + * is always sent first, and we increase the + * transfered number of bytes for that IRQ. Then + * MCI_DATAEND follows and we conclude the transaction. + * + * On the Ux500 single-IRQ variant MCI_DATABLOCKEND + * doesn't seem to immediately clear from the status, + * so we can't use it keep count when only one irq is + * used because the irq will hit for other reasons, and + * then the flag is still up. So we use the MCI_DATAEND + * IRQ at the end of the entire transfer because + * MCI_DATABLOCKEND is broken. + * + * In the U300, the IRQs can arrive out-of-order, + * e.g. MCI_DATABLOCKEND sometimes arrives after MCI_DATAEND, + * so for this case we use the flags "blockend" and + * "dataend" to make sure both IRQs have arrived before + * concluding the transaction. (This does not apply + * to the Ux500 which doesn't fire MCI_DATABLOCKEND + * at all.) In DMA mode it suffers from the same problem + * as the Ux500. + */ + if (status & MCI_DATABLOCKEND) { + /* + * Just being a little over-cautious, we do not + * use this progressive update if the hardware blockend + * flag is unreliable: since it can stay high between + * IRQs it will corrupt the transfer counter. + */ + if (!variant->broken_blockend) + host->data_xfered += data->blksz; + host->blockend = true; + } + + if (status & MCI_DATAEND) + host->dataend = true; + + /* + * On variants with broken blockend we shall only wait for dataend, + * on others we must sync with the blockend signal since they can + * appear out-of-order. + */ + if (host->dataend && (host->blockend || variant->broken_blockend)) { mmci_stop_data(host); + /* Reset these flags */ + host->blockend = false; + host->dataend = false; + + /* + * Variants with broken blockend flags need to handle the + * end of the entire transfer here. + */ + if (variant->broken_blockend && !data->error) + host->data_xfered += data->blksz * data->blocks; + if (!data->stop) { mmci_request_end(host, data->mrq); } else { @@ -841,6 +898,10 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id) } mask = MCI_IRQENABLE; + /* Don't use the datablockend flag if it's broken */ + if (variant->broken_blockend) + mask &= ~MCI_DATABLOCKEND; + writel(mask, host->base + MMCIMASK0); amba_set_drvdata(dev, mmc); diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index b4e48bde1b4e..df06f01aac89 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -177,6 +177,9 @@ struct mmci_host { struct timer_list timer; unsigned int oldstat; + bool blockend; + bool dataend; + /* pio stuff */ struct sg_mapping_iter sg_miter; unsigned int size; -- cgit v1.2.3 From 34177802001894e064c857cac2759f68119550cd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Oct 2010 12:43:58 +0100 Subject: ARM: 6438/2: mmci: add SDIO support for ST Variants This adds some minor variant data and trickery to enable SDIO on the ST Micro variants of MMCI/PL180. Signed-off-by: Marcin Mielczarczyk Signed-off-by: Linus Walleij Signed-off-by: Russell King --- drivers/mmc/host/mmci.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 976c9d0e8080..0814b88b44d6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static unsigned int fmax = 515633; * and will not work at all. * @broken_blockend_dma: the MCI_DATABLOCKEND is broken on the hardware when * using DMA. + * @sdio: variant supports SDIO */ struct variant_data { unsigned int clkreg; @@ -58,6 +60,7 @@ struct variant_data { unsigned int fifohalfsize; bool broken_blockend; bool broken_blockend_dma; + bool sdio; }; static struct variant_data variant_arm = { @@ -72,6 +75,7 @@ static struct variant_data variant_u300 = { .clkreg_enable = 1 << 13, /* HWFCEN */ .datalength_bits = 16, .broken_blockend_dma = true, + .sdio = true, }; static struct variant_data variant_ux500 = { @@ -81,6 +85,7 @@ static struct variant_data variant_ux500 = { .clkreg_enable = 1 << 14, /* HWFCEN */ .datalength_bits = 24, .broken_blockend = true, + .sdio = true, }; /* * This must be called with host->lock held @@ -222,6 +227,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } + /* The ST Micro variants has a special bit to enable SDIO */ + if (variant->sdio && host->mmc->card) + if (mmc_card_sdio(host->mmc->card)) + datactrl |= MCI_ST_DPSM_SDIOEN; + writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); @@ -429,7 +439,32 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem variant->fifosize : variant->fifohalfsize; count = min(remain, maxcnt); - writesl(base + MMCIFIFO, ptr, count >> 2); + /* + * The ST Micro variant for SDIO transfer sizes + * less then 8 bytes should have clock H/W flow + * control disabled. + */ + if (variant->sdio && + mmc_card_sdio(host->mmc->card)) { + if (count < 8) + writel(readl(host->base + MMCICLOCK) & + ~variant->clkreg_enable, + host->base + MMCICLOCK); + else + writel(readl(host->base + MMCICLOCK) | + variant->clkreg_enable, + host->base + MMCICLOCK); + } + + /* + * SDIO especially may want to send something that is + * not divisible by 4 (as opposed to card sectors + * etc), and the FIFO only accept full 32-bit writes. + * So compensate by adding +3 on the count, a single + * byte become a 32bit write, 7 bytes will be two + * 32bit writes etc. + */ + writesl(base + MMCIFIFO, ptr, (count + 3) >> 2); ptr += count; remain -= count; -- cgit v1.2.3 From a404ad1ff593589bdd34c48ebecddada9edbfaf3 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:33:53 +0100 Subject: ARM: 6452/1: Fix checkpatch.pl issues in drivers/rtc/rtc-sa1100.c. This patch fixes checkpatch.pl issues in drivers/rtc/rtc-sa1100.c, which I will later modify. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e4a44b641702..e19ed0f6dca0 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -39,7 +39,7 @@ #include #endif -#define RTC_DEF_DIVIDER 32768 - 1 +#define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 static unsigned long rtc_freq = 1024; @@ -61,7 +61,8 @@ static inline int rtc_periodic_alarm(struct rtc_time *tm) * Calculate the next alarm time given the requested alarm time mask * and the current time. */ -static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm) +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, + struct rtc_time *alrm) { unsigned long next_time; unsigned long now_time; @@ -178,7 +179,7 @@ static int sa1100_rtc_read_callback(struct device *dev, int data) * Here we compare (match - OSCR) 8 instead of 0 -- * see comment in pxa_timer_interrupt() for explanation. */ - while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) { + while ((signed long)((osmr1 = OSMR1) - OSCR) <= 8) { data += 0x100; OSSR = OSSR_M1; /* clear match on timer 1 */ OSMR1 = osmr1 + period; @@ -192,19 +193,19 @@ static int sa1100_rtc_open(struct device *dev) int ret; ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc 1Hz", dev); + "rtc 1Hz", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); goto fail_ui; } ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED, - "rtc Alrm", dev); + "rtc Alrm", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED, - "rtc timer", dev); + "rtc timer", dev); if (ret) { dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; @@ -236,7 +237,7 @@ static void sa1100_rtc_release(struct device *dev) static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - switch(cmd) { + switch (cmd) { case RTC_AIE_OFF: spin_lock_irq(&sa1100_rtc_lock); RTSR &= ~RTSR_ALE; @@ -364,7 +365,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) */ if (RTTR == 0) { RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); + dev_warn(&pdev->dev, "warning: " + "initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ RCNR = 0; } @@ -386,7 +388,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev) { struct rtc_device *rtc = platform_get_drvdata(pdev); - if (rtc) + if (rtc) rtc_device_unregister(rtc); return 0; -- cgit v1.2.3 From fd3ee6d3421bc05ce42ee7f48071aee72051af28 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:34:47 +0100 Subject: ARM: 6453/1: sa1100: Print the value of RTSR on /proc/drivers/rtc. This patch adds a line to the output of /proc/drivers/rtc to show the value of the RTSR register. It will be used to demonstrate a nasty initialization bug that will be fixed in the sequence. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index e19ed0f6dca0..b04c8374a279 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -334,6 +334,7 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) seq_printf(seq, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no"); seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq); + seq_printf(seq, "RTSR\t\t: 0x%08x\n", (u32)RTSR); return 0; } -- cgit v1.2.3 From 7decaa557a20f48aabef35f817ec16ef563567b0 Mon Sep 17 00:00:00 2001 From: Marcelo Roberto Jimenez Date: Mon, 18 Oct 2010 22:35:54 +0100 Subject: ARM: 6454/1: sa1100: Fix for a nasty initialization bug in the RTSR. This patch fixes a nasty initialization condition on the RTSR register. Sometimes, bit 1 will wake up set, sometimes not. This can be seen by checking the value of the RTSR by typing '$ cat /proc/driver/rtc', which has been provided by the previous patch. If this bit is set, the command '$ cat /dev/rtc0' will lock the system in an endless interrupt routine calling loop. This patch fixes the issue both at sa1100_rtc_probe(), where it avoids a spurious interrupt from happening, and at sa1100_rtc_interrupt(), which is the robust solution, though it does not avoid the first spurious interrupt. Signed-off-by: Marcelo Roberto Jimenez Signed-off-by: Russell King --- drivers/rtc/rtc-sa1100.c | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b04c8374a279..b0985f727078 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -117,7 +117,23 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) rtsr = RTSR; /* clear interrupt sources */ RTSR = 0; - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_probe(). */ + if (rtsr & (RTSR_ALE | RTSR_HZE)) { + /* This is the original code, before there was the if test + * above. This code does not clear interrupts that were not + * enabled. */ + RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + } else { + /* For some reason, it is possible to enter this routine + * without interruptions enabled, it has been tested with + * several units (Bug in SA11xx chip?). + * + * This situation leads to an infinite "loop" of interrupt + * routine calling and as a result the processor seems to + * lock on its first call to open(). */ + RTSR = RTSR_AL | RTSR_HZ; + } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) @@ -382,6 +398,30 @@ static int sa1100_rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, rtc); + /* Fix for a nasty initialization problem the in SA11xx RTSR register. + * See also the comments in sa1100_rtc_interrupt(). + * + * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an + * interrupt pending, even though interrupts were never enabled. + * In this case, this bit it must be reset before enabling + * interruptions to avoid a nonexistent interrupt to occur. + * + * In principle, the same problem would apply to bit 0, although it has + * never been observed to happen. + * + * This issue is addressed both here and in sa1100_rtc_interrupt(). + * If the issue is not addressed here, in the times when the processor + * wakes up with the bit set there will be one spurious interrupt. + * + * The issue is also dealt with in sa1100_rtc_interrupt() to be on the + * safe side, once the condition that lead to this strange + * initialization is unknown and could in principle happen during + * normal processing. + * + * Notice that clearing bit 1 and 0 is accomplished by writting ONES to + * the corresponding bits in RTSR. */ + RTSR = RTSR_AL | RTSR_HZ; + return 0; } -- cgit v1.2.3 From 673483c7d3a25c43d1208bb07e3888bc5136e8cf Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 10 Nov 2010 09:29:45 +0000 Subject: qlge: Add firmware info to ethtool get regs. By default we add firmware information to ethtool get regs. Optionally firmware info can instead be sent to log. Signed-off-by: Jitendra Kalsaria Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 2 ++ drivers/net/qlge/qlge_dbg.c | 21 ++++++++++++++++++++- drivers/net/qlge/qlge_ethtool.c | 19 ++++++++++++++++--- drivers/net/qlge/qlge_mpi.c | 2 +- 4 files changed, 39 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 22821398fc63..b1e815127cde 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -2221,6 +2221,7 @@ int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data); int ql_unpause_mpi_risc(struct ql_adapter *qdev); int ql_pause_mpi_risc(struct ql_adapter *qdev); int ql_hard_reset_mpi_risc(struct ql_adapter *qdev); +int ql_soft_reset_mpi_risc(struct ql_adapter *qdev); int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, u32 ram_addr, int word_count); int ql_core_dump(struct ql_adapter *qdev, @@ -2236,6 +2237,7 @@ int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control); int ql_mb_get_port_cfg(struct ql_adapter *qdev); int ql_mb_set_port_cfg(struct ql_adapter *qdev); int ql_wait_fifo_empty(struct ql_adapter *qdev); +void ql_get_dump(struct ql_adapter *qdev, void *buff); void ql_gen_reg_dump(struct ql_adapter *qdev, struct ql_reg_dump *mpi_coredump); netdev_tx_t ql_lb_send(struct sk_buff *skb, struct net_device *ndev); diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 4747492935ef..fca804f36d61 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -1317,9 +1317,28 @@ void ql_gen_reg_dump(struct ql_adapter *qdev, status = ql_get_ets_regs(qdev, &mpi_coredump->ets[0]); if (status) return; +} + +void ql_get_dump(struct ql_adapter *qdev, void *buff) +{ + /* + * If the dump has already been taken and is stored + * in our internal buffer and if force dump is set then + * just start the spool to dump it to the log file + * and also, take a snapshot of the general regs to + * to the user's buffer or else take complete dump + * to the user's buffer if force is not set. + */ - if (test_bit(QL_FRC_COREDUMP, &qdev->flags)) + if (!test_bit(QL_FRC_COREDUMP, &qdev->flags)) { + if (!ql_core_dump(qdev, buff)) + ql_soft_reset_mpi_risc(qdev); + else + netif_err(qdev, drv, qdev->ndev, "coredump failed!\n"); + } else { + ql_gen_reg_dump(qdev, buff); ql_get_core_dump(qdev); + } } /* Coredump to messages log file using separate worker thread */ diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 4892d64f4e05..8149cc9de4ca 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -375,7 +375,10 @@ static void ql_get_drvinfo(struct net_device *ndev, strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32); drvinfo->n_stats = 0; drvinfo->testinfo_len = 0; - drvinfo->regdump_len = 0; + if (!test_bit(QL_FRC_COREDUMP, &qdev->flags)) + drvinfo->regdump_len = sizeof(struct ql_mpi_coredump); + else + drvinfo->regdump_len = sizeof(struct ql_reg_dump); drvinfo->eedump_len = 0; } @@ -547,7 +550,12 @@ static void ql_self_test(struct net_device *ndev, static int ql_get_regs_len(struct net_device *ndev) { - return sizeof(struct ql_reg_dump); + struct ql_adapter *qdev = netdev_priv(ndev); + + if (!test_bit(QL_FRC_COREDUMP, &qdev->flags)) + return sizeof(struct ql_mpi_coredump); + else + return sizeof(struct ql_reg_dump); } static void ql_get_regs(struct net_device *ndev, @@ -555,7 +563,12 @@ static void ql_get_regs(struct net_device *ndev, { struct ql_adapter *qdev = netdev_priv(ndev); - ql_gen_reg_dump(qdev, p); + ql_get_dump(qdev, p); + qdev->core_is_dumped = 0; + if (!test_bit(QL_FRC_COREDUMP, &qdev->flags)) + regs->len = sizeof(struct ql_mpi_coredump); + else + regs->len = sizeof(struct ql_reg_dump); } static int ql_get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 0e7c7c7ee164..100a462cc916 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -87,7 +87,7 @@ exit: return status; } -static int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) +int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) { int status; status = ql_write_mpi_reg(qdev, 0x00001010, 1); -- cgit v1.2.3 From 0c6202b3278b417444a59cecc59e6e5af04db7fd Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 10 Nov 2010 09:29:46 +0000 Subject: qlge: Version change to v1.00.00.27 Signed-off-by: Jitendra Kalsaria Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index b1e815127cde..bdb8fe868539 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -16,7 +16,7 @@ */ #define DRV_NAME "qlge" #define DRV_STRING "QLogic 10 Gigabit PCI-E Ethernet Driver " -#define DRV_VERSION "v1.00.00.25.00.00-01" +#define DRV_VERSION "v1.00.00.27.00.00-01" #define WQ_ADDR_ALIGN 0x3 /* 4 byte alignment */ -- cgit v1.2.3 From 0146f26145af75d53e12dbf23a36996aff373680 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Wed, 10 Nov 2010 17:29:17 +0000 Subject: rtc: Add drivers/rtc/rtc-mrst.c Provide the standard kernel rtc driver interface on top of the vrtc layer added in the previous patch. Signed-off-by: Feng Tang LKML-Reference: <20101110172911.3311.20593.stgit@localhost.localdomain> [Fixed swapped arguments on IPC] Signed-off-by: Arjan van de Ven [Cleaned up and the device creation moved to arch/x86/platform] Signed-off-by: Alan Cox Signed-off-by: Thomas Gleixner --- arch/x86/platform/mrst/vrtc.c | 46 ++++ drivers/rtc/Kconfig | 12 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-mrst.c | 578 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 637 insertions(+) create mode 100644 drivers/rtc/rtc-mrst.c (limited to 'drivers') diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c index 4944bd521d2c..4d3f770456f7 100644 --- a/arch/x86/platform/mrst/vrtc.c +++ b/arch/x86/platform/mrst/vrtc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -118,3 +119,48 @@ void __init mrst_rtc_init(void) x86_platform.get_wallclock = vrtc_get_time; x86_platform.set_wallclock = vrtc_set_mmss; } + +/* + * The Moorestown platform has a memory mapped virtual RTC device that emulates + * the programming interface of the RTC. + */ + +static struct resource vrtc_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device vrtc_device = { + .name = "rtc_mrst", + .id = -1, + .resource = vrtc_resources, + .num_resources = ARRAY_SIZE(vrtc_resources), +}; + +/* Register the RTC device if appropriate */ +static int __init mrst_device_create(void) +{ + /* No Moorestown, no device */ + if (!mrst_identify_cpu()) + return -ENODEV; + /* No timer, no device */ + if (!sfi_mrtc_num) + return -ENODEV; + + /* iomem resource */ + vrtc_resources[0].start = sfi_mrtc_array[0].phys_addr; + vrtc_resources[0].end = sfi_mrtc_array[0].phys_addr + + MRST_VRTC_MAP_SZ; + /* irq resource */ + vrtc_resources[1].start = sfi_mrtc_array[0].irq; + vrtc_resources[1].end = sfi_mrtc_array[0].irq; + + platform_device_register(&vrtc_device); + return 0; +} + +module_init(mrst_device_create); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2883428d5ac8..4941cade319f 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -463,6 +463,18 @@ config RTC_DRV_CMOS This driver can also be built as a module. If so, the module will be called rtc-cmos. +config RTC_DRV_VRTC + tristate "Virtual RTC for Moorestown platforms" + depends on X86_MRST + default y if X86_MRST + + help + Say "yes" here to get direct support for the real time clock + found on Moorestown platforms. The VRTC is a emulated RTC that + derives its clock source from a real RTC in the PMIC. The MC146818 + style programming interface is mostly conserved, but any + updates are done via IPC calls to the system controller FW. + config RTC_DRV_DS1216 tristate "Dallas DS1216" depends on SNI_RM diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 4c2832df4697..2afdaf3ff986 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o +obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c new file mode 100644 index 000000000000..67b6be2b874d --- /dev/null +++ b/drivers/rtc/rtc-mrst.c @@ -0,0 +1,578 @@ +/* + * rtc-mrst.c: Driver for Moorestown virtual RTC + * + * (C) Copyright 2009 Intel Corporation + * Author: Jacob Pan (jacob.jun.pan@intel.com) + * Feng Tang (feng.tang@intel.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + * + * Note: + * VRTC is emulated by system controller firmware, the real HW + * RTC is located in the PMIC device. SCU FW shadows PMIC RTC + * in a memory mapped IO space that is visible to the host IA + * processor. + * + * This driver is based upon drivers/rtc/rtc-cmos.c + */ + +/* + * Note: + * * vRTC only supports binary mode and 24H mode + * * vRTC only support PIE and AIE, no UIE, and its PIE only happens + * at 23:59:59pm everyday, no support for adjustable frequency + * * Alarm function is also limited to hr/min/sec. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct mrst_rtc { + struct rtc_device *rtc; + struct device *dev; + int irq; + struct resource *iomem; + + u8 enabled_wake; + u8 suspend_ctrl; +}; + +static const char driver_name[] = "rtc_mrst"; + +#define RTC_IRQMASK (RTC_PF | RTC_AF) + +static inline int is_intr(u8 rtc_intr) +{ + if (!(rtc_intr & RTC_IRQF)) + return 0; + return rtc_intr & RTC_IRQMASK; +} + +/* + * rtc_time's year contains the increment over 1900, but vRTC's YEAR + * register can't be programmed to value larger than 0x64, so vRTC + * driver chose to use 1960 (1970 is UNIX time start point) as the base, + * and does the translation at read/write time + */ +static int mrst_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long flags; + + if (rtc_is_updating()) + mdelay(20); + + spin_lock_irqsave(&rtc_lock, flags); + time->tm_sec = vrtc_cmos_read(RTC_SECONDS); + time->tm_min = vrtc_cmos_read(RTC_MINUTES); + time->tm_hour = vrtc_cmos_read(RTC_HOURS); + time->tm_mday = vrtc_cmos_read(RTC_DAY_OF_MONTH); + time->tm_mon = vrtc_cmos_read(RTC_MONTH); + time->tm_year = vrtc_cmos_read(RTC_YEAR); + spin_unlock_irqrestore(&rtc_lock, flags); + + /* Adjust for the 1960/1900 */ + time->tm_year += 60; + time->tm_mon--; + return RTC_24H; +} + +static int mrst_set_time(struct device *dev, struct rtc_time *time) +{ + int ret; + unsigned long flags; + unsigned char mon, day, hrs, min, sec; + unsigned int yrs; + + yrs = time->tm_year; + mon = time->tm_mon + 1; /* tm_mon starts at zero */ + day = time->tm_mday; + hrs = time->tm_hour; + min = time->tm_min; + sec = time->tm_sec; + + if (yrs < 70 || yrs > 138) + return -EINVAL; + yrs -= 60; + + spin_lock_irqsave(&rtc_lock, flags); + + vrtc_cmos_write(yrs, RTC_YEAR); + vrtc_cmos_write(mon, RTC_MONTH); + vrtc_cmos_write(day, RTC_DAY_OF_MONTH); + vrtc_cmos_write(hrs, RTC_HOURS); + vrtc_cmos_write(min, RTC_MINUTES); + vrtc_cmos_write(sec, RTC_SECONDS); + + spin_unlock_irqrestore(&rtc_lock, flags); + + ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME); + return ret; +} + +static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned char rtc_control; + + if (mrst->irq <= 0) + return -EIO; + + /* Basic alarms only support hour, minute, and seconds fields. + * Some also support day and month, for alarms up to a year in + * the future. + */ + t->time.tm_mday = -1; + t->time.tm_mon = -1; + t->time.tm_year = -1; + + /* vRTC only supports binary mode */ + spin_lock_irq(&rtc_lock); + t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM); + t->time.tm_min = vrtc_cmos_read(RTC_MINUTES_ALARM); + t->time.tm_hour = vrtc_cmos_read(RTC_HOURS_ALARM); + + rtc_control = vrtc_cmos_read(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + t->enabled = !!(rtc_control & RTC_AIE); + t->pending = 0; + + return 0; +} + +static void mrst_checkintr(struct mrst_rtc *mrst, unsigned char rtc_control) +{ + unsigned char rtc_intr; + + /* + * NOTE after changing RTC_xIE bits we always read INTR_FLAGS; + * allegedly some older rtcs need that to handle irqs properly + */ + rtc_intr = vrtc_cmos_read(RTC_INTR_FLAGS); + rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; + if (is_intr(rtc_intr)) + rtc_update_irq(mrst->rtc, 1, rtc_intr); +} + +static void mrst_irq_enable(struct mrst_rtc *mrst, unsigned char mask) +{ + unsigned char rtc_control; + + /* + * Flush any pending IRQ status, notably for update irqs, + * before we enable new IRQs + */ + rtc_control = vrtc_cmos_read(RTC_CONTROL); + mrst_checkintr(mrst, rtc_control); + + rtc_control |= mask; + vrtc_cmos_write(rtc_control, RTC_CONTROL); + + mrst_checkintr(mrst, rtc_control); +} + +static void mrst_irq_disable(struct mrst_rtc *mrst, unsigned char mask) +{ + unsigned char rtc_control; + + rtc_control = vrtc_cmos_read(RTC_CONTROL); + rtc_control &= ~mask; + vrtc_cmos_write(rtc_control, RTC_CONTROL); + mrst_checkintr(mrst, rtc_control); +} + +static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned char hrs, min, sec; + int ret = 0; + + if (!mrst->irq) + return -EIO; + + hrs = t->time.tm_hour; + min = t->time.tm_min; + sec = t->time.tm_sec; + + spin_lock_irq(&rtc_lock); + /* Next rtc irq must not be from previous alarm setting */ + mrst_irq_disable(mrst, RTC_AIE); + + /* Update alarm */ + vrtc_cmos_write(hrs, RTC_HOURS_ALARM); + vrtc_cmos_write(min, RTC_MINUTES_ALARM); + vrtc_cmos_write(sec, RTC_SECONDS_ALARM); + + spin_unlock_irq(&rtc_lock); + + ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM); + if (ret) + return ret; + + spin_lock_irq(&rtc_lock); + if (t->enabled) + mrst_irq_enable(mrst, RTC_AIE); + + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static int mrst_irq_set_state(struct device *dev, int enabled) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned long flags; + + if (!mrst->irq) + return -ENXIO; + + spin_lock_irqsave(&rtc_lock, flags); + + if (enabled) + mrst_irq_enable(mrst, RTC_PIE); + else + mrst_irq_disable(mrst, RTC_PIE); + + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; +} + +#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) + +/* Currently, the vRTC doesn't support UIE ON/OFF */ +static int +mrst_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned long flags; + + switch (cmd) { + case RTC_AIE_OFF: + case RTC_AIE_ON: + if (!mrst->irq) + return -EINVAL; + break; + default: + /* PIE ON/OFF is handled by mrst_irq_set_state() */ + return -ENOIOCTLCMD; + } + + spin_lock_irqsave(&rtc_lock, flags); + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + mrst_irq_disable(mrst, RTC_AIE); + break; + case RTC_AIE_ON: /* alarm on */ + mrst_irq_enable(mrst, RTC_AIE); + break; + } + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; +} + +#else +#define mrst_rtc_ioctl NULL +#endif + +#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) + +static int mrst_procfs(struct device *dev, struct seq_file *seq) +{ + unsigned char rtc_control, valid; + + spin_lock_irq(&rtc_lock); + rtc_control = vrtc_cmos_read(RTC_CONTROL); + valid = vrtc_cmos_read(RTC_VALID); + spin_unlock_irq(&rtc_lock); + + return seq_printf(seq, + "periodic_IRQ\t: %s\n" + "alarm\t\t: %s\n" + "BCD\t\t: no\n" + "periodic_freq\t: daily (not adjustable)\n", + (rtc_control & RTC_PIE) ? "on" : "off", + (rtc_control & RTC_AIE) ? "on" : "off"); +} + +#else +#define mrst_procfs NULL +#endif + +static const struct rtc_class_ops mrst_rtc_ops = { + .ioctl = mrst_rtc_ioctl, + .read_time = mrst_read_time, + .set_time = mrst_set_time, + .read_alarm = mrst_read_alarm, + .set_alarm = mrst_set_alarm, + .proc = mrst_procfs, + .irq_set_state = mrst_irq_set_state, +}; + +static struct mrst_rtc mrst_rtc; + +/* + * When vRTC IRQ is captured by SCU FW, FW will clear the AIE bit in + * Reg B, so no need for this driver to clear it + */ +static irqreturn_t mrst_rtc_irq(int irq, void *p) +{ + u8 irqstat; + + spin_lock(&rtc_lock); + /* This read will clear all IRQ flags inside Reg C */ + irqstat = vrtc_cmos_read(RTC_INTR_FLAGS); + spin_unlock(&rtc_lock); + + irqstat &= RTC_IRQMASK | RTC_IRQF; + if (is_intr(irqstat)) { + rtc_update_irq(p, 1, irqstat); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int __init +vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) +{ + int retval = 0; + unsigned char rtc_control; + + /* There can be only one ... */ + if (mrst_rtc.dev) + return -EBUSY; + + if (!iomem) + return -ENODEV; + + iomem = request_mem_region(iomem->start, + iomem->end + 1 - iomem->start, + driver_name); + if (!iomem) { + dev_dbg(dev, "i/o mem already in use.\n"); + return -EBUSY; + } + + mrst_rtc.irq = rtc_irq; + mrst_rtc.iomem = iomem; + + mrst_rtc.rtc = rtc_device_register(driver_name, dev, + &mrst_rtc_ops, THIS_MODULE); + if (IS_ERR(mrst_rtc.rtc)) { + retval = PTR_ERR(mrst_rtc.rtc); + goto cleanup0; + } + + mrst_rtc.dev = dev; + dev_set_drvdata(dev, &mrst_rtc); + rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); + + spin_lock_irq(&rtc_lock); + mrst_irq_disable(&mrst_rtc, RTC_PIE | RTC_AIE); + rtc_control = vrtc_cmos_read(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) + dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n"); + + if (rtc_irq) { + retval = request_irq(rtc_irq, mrst_rtc_irq, + IRQF_DISABLED, dev_name(&mrst_rtc.rtc->dev), + mrst_rtc.rtc); + if (retval < 0) { + dev_dbg(dev, "IRQ %d is already in use, err %d\n", + rtc_irq, retval); + goto cleanup1; + } + } + dev_dbg(dev, "initialised\n"); + return 0; + +cleanup1: + mrst_rtc.dev = NULL; + rtc_device_unregister(mrst_rtc.rtc); +cleanup0: + release_region(iomem->start, iomem->end + 1 - iomem->start); + dev_err(dev, "rtc-mrst: unable to initialise\n"); + return retval; +} + +static void rtc_mrst_do_shutdown(void) +{ + spin_lock_irq(&rtc_lock); + mrst_irq_disable(&mrst_rtc, RTC_IRQMASK); + spin_unlock_irq(&rtc_lock); +} + +static void __exit rtc_mrst_do_remove(struct device *dev) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + struct resource *iomem; + + rtc_mrst_do_shutdown(); + + if (mrst->irq) + free_irq(mrst->irq, mrst->rtc); + + rtc_device_unregister(mrst->rtc); + mrst->rtc = NULL; + + iomem = mrst->iomem; + release_region(iomem->start, iomem->end + 1 - iomem->start); + mrst->iomem = NULL; + + mrst->dev = NULL; + dev_set_drvdata(dev, NULL); +} + +#ifdef CONFIG_PM +static int mrst_suspend(struct device *dev, pm_message_t mesg) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned char tmp; + + /* Only the alarm might be a wakeup event source */ + spin_lock_irq(&rtc_lock); + mrst->suspend_ctrl = tmp = vrtc_cmos_read(RTC_CONTROL); + if (tmp & (RTC_PIE | RTC_AIE)) { + unsigned char mask; + + if (device_may_wakeup(dev)) + mask = RTC_IRQMASK & ~RTC_AIE; + else + mask = RTC_IRQMASK; + tmp &= ~mask; + vrtc_cmos_write(tmp, RTC_CONTROL); + + mrst_checkintr(mrst, tmp); + } + spin_unlock_irq(&rtc_lock); + + if (tmp & RTC_AIE) { + mrst->enabled_wake = 1; + enable_irq_wake(mrst->irq); + } + + dev_dbg(&mrst_rtc.rtc->dev, "suspend%s, ctrl %02x\n", + (tmp & RTC_AIE) ? ", alarm may wake" : "", + tmp); + + return 0; +} + +/* + * We want RTC alarms to wake us from the deep power saving state + */ +static inline int mrst_poweroff(struct device *dev) +{ + return mrst_suspend(dev, PMSG_HIBERNATE); +} + +static int mrst_resume(struct device *dev) +{ + struct mrst_rtc *mrst = dev_get_drvdata(dev); + unsigned char tmp = mrst->suspend_ctrl; + + /* Re-enable any irqs previously active */ + if (tmp & RTC_IRQMASK) { + unsigned char mask; + + if (mrst->enabled_wake) { + disable_irq_wake(mrst->irq); + mrst->enabled_wake = 0; + } + + spin_lock_irq(&rtc_lock); + do { + vrtc_cmos_write(tmp, RTC_CONTROL); + + mask = vrtc_cmos_read(RTC_INTR_FLAGS); + mask &= (tmp & RTC_IRQMASK) | RTC_IRQF; + if (!is_intr(mask)) + break; + + rtc_update_irq(mrst->rtc, 1, mask); + tmp &= ~RTC_AIE; + } while (mask & RTC_AIE); + spin_unlock_irq(&rtc_lock); + } + + dev_dbg(&mrst_rtc.rtc->dev, "resume, ctrl %02x\n", tmp); + + return 0; +} + +#else +#define mrst_suspend NULL +#define mrst_resume NULL + +static inline int mrst_poweroff(struct device *dev) +{ + return -ENOSYS; +} + +#endif + +static int __init vrtc_mrst_platform_probe(struct platform_device *pdev) +{ + return vrtc_mrst_do_probe(&pdev->dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0), + platform_get_irq(pdev, 0)); +} + +static int __exit vrtc_mrst_platform_remove(struct platform_device *pdev) +{ + rtc_mrst_do_remove(&pdev->dev); + return 0; +} + +static void vrtc_mrst_platform_shutdown(struct platform_device *pdev) +{ + if (system_state == SYSTEM_POWER_OFF && !mrst_poweroff(&pdev->dev)) + return; + + rtc_mrst_do_shutdown(); +} + +MODULE_ALIAS("platform:vrtc_mrst"); + +static struct platform_driver vrtc_mrst_platform_driver = { + .probe = vrtc_mrst_platform_probe, + .remove = __exit_p(vrtc_mrst_platform_remove), + .shutdown = vrtc_mrst_platform_shutdown, + .driver = { + .name = (char *) driver_name, + .suspend = mrst_suspend, + .resume = mrst_resume, + } +}; + +static int __init vrtc_mrst_init(void) +{ + return platform_driver_register(&vrtc_mrst_platform_driver); +} + +static void __exit vrtc_mrst_exit(void) +{ + platform_driver_unregister(&vrtc_mrst_platform_driver); +} + +module_init(vrtc_mrst_init); +module_exit(vrtc_mrst_exit); + +MODULE_AUTHOR("Jacob Pan; Feng Tang"); +MODULE_DESCRIPTION("Driver for Moorestown virtual RTC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 47f01db44b2470d9517848f6b73c75883ef5fda0 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:53 +0000 Subject: vxge: enable rxhash Enable RSS hashing and add ability to pass up the adapter calculated rx hash up the network stack (if feature is available). Add the ability to enable/disable feature via ethtool, which requires that the adapter is not running at the time. Other miscellaneous cleanups and fixes required to get RSS working. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 2 ++ drivers/net/vxge/vxge-config.h | 12 ++++----- drivers/net/vxge/vxge-ethtool.c | 35 ++++++++++++++++++++++++++ drivers/net/vxge/vxge-main.c | 54 ++++++++++++++++++++++++++--------------- drivers/net/vxge/vxge-main.h | 18 +++++++------- drivers/net/vxge/vxge-traffic.h | 28 --------------------- 6 files changed, 86 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 906a3ca3676b..0a35ab1ee2e1 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -3204,6 +3204,8 @@ enum vxge_hw_status vxge_hw_vpath_rts_rth_set( VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY, VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG, 0, &data0, &data1); + if (status != VXGE_HW_OK) + goto exit; data0 &= ~(VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(0xf) | VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(0x3)); diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 5c00861b6c2c..5d7790558f44 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -1413,12 +1413,12 @@ enum vxge_hw_rth_algoritms { * See also: vxge_hw_vpath_rts_rth_set(), vxge_hw_vpath_rts_rth_get(). */ struct vxge_hw_rth_hash_types { - u8 hash_type_tcpipv4_en; - u8 hash_type_ipv4_en; - u8 hash_type_tcpipv6_en; - u8 hash_type_ipv6_en; - u8 hash_type_tcpipv6ex_en; - u8 hash_type_ipv6ex_en; + u8 hash_type_tcpipv4_en:1, + hash_type_ipv4_en:1, + hash_type_tcpipv6_en:1, + hash_type_ipv6_en:1, + hash_type_tcpipv6ex_en:1, + hash_type_ipv6ex_en:1; }; void vxge_hw_device_debug_set( diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index b67746eef923..f8fd8da4f173 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -1119,6 +1119,40 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) } } +static int vxge_set_flags(struct net_device *dev, u32 data) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + enum vxge_hw_status status; + + if (data & ~ETH_FLAG_RXHASH) + return -EOPNOTSUPP; + + if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) + return 0; + + if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING)) + return -EINVAL; + + vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH); + + /* Enabling RTH requires some of the logic in vxge_device_register and a + * vpath reset. Due to these restrictions, only allow modification + * while the interface is down. + */ + status = vxge_reset_all_vpaths(vdev); + if (status != VXGE_HW_OK) { + vdev->devh->config.rth_en = !vdev->devh->config.rth_en; + return -EFAULT; + } + + if (vdev->devh->config.rth_en) + dev->features |= NETIF_F_RXHASH; + else + dev->features &= ~NETIF_F_RXHASH; + + return 0; +} + static const struct ethtool_ops vxge_ethtool_ops = { .get_settings = vxge_ethtool_gset, .set_settings = vxge_ethtool_sset, @@ -1140,6 +1174,7 @@ static const struct ethtool_ops vxge_ethtool_ops = { .phys_id = vxge_ethtool_idnic, .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, + .set_flags = vxge_set_flags, }; void vxge_initialize_ethtool_ops(struct net_device *ndev) diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 813829f3d024..2f26c377e5d9 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -513,6 +513,13 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, else skb_checksum_none_assert(skb); + /* rth_hash_type and rth_it_hit are non-zero regardless of + * whether rss is enabled. Only the rth_value is zero/non-zero + * if rss is disabled/enabled, so key off of that. + */ + if (ext_info.rth_value) + skb->rxhash = ext_info.rth_value; + vxge_rx_complete(ring, skb, ext_info.vlan, pkt_length, &ext_info); @@ -1689,15 +1696,6 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev) mtable[index] = index % vdev->no_of_vpath; } - /* Fill RTH hash types */ - hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4; - hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4; - hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6; - hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6; - hash_types.hash_type_tcpipv6ex_en = - vdev->config.rth_hash_type_tcpipv6ex; - hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex; - /* set indirection table, bucket-to-vpath mapping */ status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles, vdev->no_of_vpath, @@ -1710,12 +1708,21 @@ static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev) return status; } + /* Fill RTH hash types */ + hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4; + hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4; + hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6; + hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6; + hash_types.hash_type_tcpipv6ex_en = + vdev->config.rth_hash_type_tcpipv6ex; + hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex; + /* - * Because the itable_set() method uses the active_table field - * for the target virtual path the RTH config should be updated - * for all VPATHs. The h/w only uses the lowest numbered VPATH - * when steering frames. - */ + * Because the itable_set() method uses the active_table field + * for the target virtual path the RTH config should be updated + * for all VPATHs. The h/w only uses the lowest numbered VPATH + * when steering frames. + */ for (index = 0; index < vdev->no_of_vpath; index++) { status = vxge_hw_vpath_rts_rth_set( vdev->vpaths[index].handle, @@ -2598,6 +2605,8 @@ vxge_open(struct net_device *dev) goto out2; } } + printk(KERN_INFO "%s: Receive Hashing Offload %s\n", dev->name, + hldev->config.rth_en ? "enabled" : "disabled"); for (i = 0; i < vdev->no_of_vpath; i++) { vpath = &vdev->vpaths[i]; @@ -3178,6 +3187,11 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vxge_initialize_ethtool_ops(ndev); + if (vdev->config.rth_steering != NO_STEERING) { + ndev->features |= NETIF_F_RXHASH; + hldev->config.rth_en = VXGE_HW_RTH_ENABLE; + } + /* Allocate memory for vpath */ vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * no_of_vpath, GFP_KERNEL); @@ -4163,12 +4177,12 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; ll_config->addr_learn_en = addr_learn_en; ll_config->rth_algorithm = RTH_ALG_JENKINS; - ll_config->rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4; - ll_config->rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE; - ll_config->rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE; - ll_config->rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE; - ll_config->rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE; - ll_config->rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config->rth_hash_type_tcpipv4 = 1; + ll_config->rth_hash_type_ipv4 = 0; + ll_config->rth_hash_type_tcpipv6 = 0; + ll_config->rth_hash_type_ipv6 = 0; + ll_config->rth_hash_type_tcpipv6ex = 0; + ll_config->rth_hash_type_ipv6ex = 0; ll_config->rth_bkt_sz = RTH_BUCKET_SIZE; ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index de64536cb7d0..a4f6d864fc8e 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -145,15 +145,15 @@ struct vxge_config { int addr_learn_en; - int rth_steering; - int rth_algorithm; - int rth_hash_type_tcpipv4; - int rth_hash_type_ipv4; - int rth_hash_type_tcpipv6; - int rth_hash_type_ipv6; - int rth_hash_type_tcpipv6ex; - int rth_hash_type_ipv6ex; - int rth_bkt_sz; + u32 rth_steering:2, + rth_algorithm:2, + rth_hash_type_tcpipv4:1, + rth_hash_type_ipv4:1, + rth_hash_type_tcpipv6:1, + rth_hash_type_ipv6:1, + rth_hash_type_tcpipv6ex:1, + rth_hash_type_ipv6ex:1, + rth_bkt_sz:8; int rth_jhash_golden_ratio; int tx_steering_type; int fifo_indicate_max_pkts; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 9890d4d596d0..1fceee876228 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -1904,34 +1904,6 @@ enum vxge_hw_ring_tcode { VXGE_HW_RING_T_CODE_MULTI_ERR = 0xF }; -/** - * enum enum vxge_hw_ring_hash_type - RTH hash types - * @VXGE_HW_RING_HASH_TYPE_NONE: No Hash - * @VXGE_HW_RING_HASH_TYPE_TCP_IPV4: TCP IPv4 - * @VXGE_HW_RING_HASH_TYPE_UDP_IPV4: UDP IPv4 - * @VXGE_HW_RING_HASH_TYPE_IPV4: IPv4 - * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6: TCP IPv6 - * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6: UDP IPv6 - * @VXGE_HW_RING_HASH_TYPE_IPV6: IPv6 - * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX: TCP IPv6 extension - * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX: UDP IPv6 extension - * @VXGE_HW_RING_HASH_TYPE_IPV6_EX: IPv6 extension - * - * RTH hash types - */ -enum vxge_hw_ring_hash_type { - VXGE_HW_RING_HASH_TYPE_NONE = 0x0, - VXGE_HW_RING_HASH_TYPE_TCP_IPV4 = 0x1, - VXGE_HW_RING_HASH_TYPE_UDP_IPV4 = 0x2, - VXGE_HW_RING_HASH_TYPE_IPV4 = 0x3, - VXGE_HW_RING_HASH_TYPE_TCP_IPV6 = 0x4, - VXGE_HW_RING_HASH_TYPE_UDP_IPV6 = 0x5, - VXGE_HW_RING_HASH_TYPE_IPV6 = 0x6, - VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX = 0x7, - VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX = 0x8, - VXGE_HW_RING_HASH_TYPE_IPV6_EX = 0x9 -}; - enum vxge_hw_status vxge_hw_ring_rxd_reserve( struct __vxge_hw_ring *ring_handle, void **rxdh); -- cgit v1.2.3 From 4d2a5b406c02b224bd3f50992c8b02450c65a730 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:54 +0000 Subject: vxge: Wait for Rx to become idle before reseting or closing Wait for the receive traffic to become idle before attempting to close or reset the adapter. To enable the processing of packets while Receive Idle, move the clearing of __VXGE_STATE_CARD_UP bit in vxge_close to after it. Also, modify the return value of the ISR when the adapter is down to IRQ_HANDLED. Otherwise there are unhandled interrupts for the device. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 86 ++++++++++++++++++++++++++++++++++++++++-- drivers/net/vxge/vxge-config.h | 7 ++++ drivers/net/vxge/vxge-main.c | 19 +++++++--- drivers/net/vxge/vxge-main.h | 2 + drivers/net/vxge/vxge-reg.h | 1 + 5 files changed, 106 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 0a35ab1ee2e1..212e301bdd68 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -193,6 +193,88 @@ static enum vxge_hw_status __vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath, struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats); +static void +vxge_hw_vpath_set_zero_rx_frm_len(struct vxge_hw_vpath_reg __iomem *vp_reg) +{ + u64 val64; + + val64 = readq(&vp_reg->rxmac_vcfg0); + val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff); + writeq(val64, &vp_reg->rxmac_vcfg0); + val64 = readq(&vp_reg->rxmac_vcfg0); + + return; +} + +/* + * vxge_hw_vpath_wait_receive_idle - Wait for Rx to become idle + */ +int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id) +{ + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct __vxge_hw_virtualpath *vpath; + u64 val64, rxd_count, rxd_spat; + int count = 0, total_count = 0; + + vpath = &hldev->virtual_paths[vp_id]; + vp_reg = vpath->vp_reg; + + vxge_hw_vpath_set_zero_rx_frm_len(vp_reg); + + /* Check that the ring controller for this vpath has enough free RxDs + * to send frames to the host. This is done by reading the + * PRC_RXD_DOORBELL_VPn register and comparing the read value to the + * RXD_SPAT value for the vpath. + */ + val64 = readq(&vp_reg->prc_cfg6); + rxd_spat = VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val64) + 1; + /* Use a factor of 2 when comparing rxd_count against rxd_spat for some + * leg room. + */ + rxd_spat *= 2; + + do { + mdelay(1); + + rxd_count = readq(&vp_reg->prc_rxd_doorbell); + + /* Check that the ring controller for this vpath does + * not have any frame in its pipeline. + */ + val64 = readq(&vp_reg->frm_in_progress_cnt); + if ((rxd_count <= rxd_spat) || (val64 > 0)) + count = 0; + else + count++; + total_count++; + } while ((count < VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT) && + (total_count < VXGE_HW_MAX_POLLING_COUNT)); + + if (total_count >= VXGE_HW_MAX_POLLING_COUNT) + printk(KERN_ALERT "%s: Still Receiving traffic. Abort wait\n", + __func__); + + return total_count; +} + +/* vxge_hw_device_wait_receive_idle - This function waits until all frames + * stored in the frame buffer for each vpath assigned to the given + * function (hldev) have been sent to the host. + */ +void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev) +{ + int i, total_count = 0; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (!(hldev->vpaths_deployed & vxge_mBIT(i))) + continue; + + total_count += vxge_hw_vpath_wait_receive_idle(hldev, i); + if (total_count >= VXGE_HW_MAX_POLLING_COUNT) + break; + } +} + /* * __vxge_hw_channel_allocate - Allocate memory for channel * This function allocates required memory for the channel and various arrays @@ -390,7 +472,7 @@ __vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis) return ret; } - /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset +/* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset * in progress * This routine checks the vpath reset in progress register is turned zero */ @@ -1165,7 +1247,6 @@ exit: * It can be used to set or reset Pause frame generation or reception * support of the NIC. */ - enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev, u32 port, u32 tx, u32 rx) { @@ -1409,7 +1490,6 @@ exit: /* * __vxge_hw_ring_create - Create a Ring * This function creates Ring and initializes it. - * */ static enum vxge_hw_status __vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp, diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 5d7790558f44..95e7021f88d8 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -2051,4 +2051,11 @@ enum vxge_hw_status vxge_hw_vpath_rts_rth_set( enum vxge_hw_status __vxge_hw_device_is_privilaged(u32 host_type, u32 func_id); + +#define VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT 5 +#define VXGE_HW_MAX_POLLING_COUNT 100 + +int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id); + +void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev); #endif diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 2f26c377e5d9..53db6a4b9601 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -90,7 +90,6 @@ static int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac); static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac); static enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath); static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath); -static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); static inline int is_vxge_card_up(struct vxgedev *vdev) { @@ -1299,8 +1298,13 @@ static void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id) static void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id) { struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; + struct __vxge_hw_device *hldev; int msix_id; + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); + + vxge_hw_vpath_wait_receive_idle(hldev, vpath->device_id); + vxge_hw_vpath_intr_disable(vpath->handle); if (vdev->config.intr_type == INTA) @@ -1430,6 +1434,7 @@ static int do_vxge_reset(struct vxgedev *vdev, int event) } if (event == VXGE_LL_FULL_RESET) { + vxge_hw_device_wait_receive_idle(vdev->devh); vxge_hw_device_intr_disable(vdev->devh); switch (vdev->cric_err_event) { @@ -1935,7 +1940,7 @@ static enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath) } /* reset vpaths */ -static enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) +enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) { enum vxge_hw_status status = VXGE_HW_OK; struct vxge_vpath *vpath; @@ -2080,7 +2085,7 @@ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) return IRQ_NONE; if (unlikely(!is_vxge_card_up(vdev))) - return IRQ_NONE; + return IRQ_HANDLED; status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode, &reason); @@ -2787,7 +2792,6 @@ static int do_vxge_close(struct net_device *dev, int do_io) while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) msleep(50); - clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); if (do_io) { /* Put the vpath back in normal mode */ vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id); @@ -2831,6 +2835,11 @@ static int do_vxge_close(struct net_device *dev, int do_io) del_timer_sync(&vdev->vp_reset_timer); + if (do_io) + vxge_hw_device_wait_receive_idle(hldev); + + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + /* Disable napi */ if (vdev->config.intr_type != MSI_X) napi_disable(&vdev->napi); @@ -2847,8 +2856,6 @@ static int do_vxge_close(struct net_device *dev, int do_io) if (do_io) vxge_hw_device_intr_disable(vdev->devh); - mdelay(1000); - vxge_rem_isr(vdev); vxge_napi_del_all(vdev); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index a4f6d864fc8e..54989d07af34 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -397,6 +397,8 @@ struct vxge_tx_priv { } while (0); extern void vxge_initialize_ethtool_ops(struct net_device *ndev); +enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); + /** * #define VXGE_DEBUG_INIT: debug for initialization functions * #define VXGE_DEBUG_TX : debug transmit related functions diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 3dd5c9615ef9..93fd752187bc 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -3998,6 +3998,7 @@ struct vxge_hw_vpath_reg { #define VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN vxge_mBIT(9) #define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9) #define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9) +#define VXGE_HW_PRC_CFG6_GET_RXD_SPAT(val) vxge_bVALn(val, 36, 9) /*0x00a78*/ u64 prc_cfg7; #define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2) #define VXGE_HW_PRC_CFG7_SMART_SCAT_EN vxge_mBIT(11) -- cgit v1.2.3 From ddd62726e0bc1ffe0ab791b647f4178161ab451b Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:55 +0000 Subject: vxge: cleanup debug printing and asserts Remove all of the unnecessary debug printk indirection and temporary variables for vxge_debug_ll and vxge_assert. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.h | 42 +++++++++--------------------------------- drivers/net/vxge/vxge-main.h | 2 -- 2 files changed, 9 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 95e7021f88d8..b395d8db318a 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -20,13 +20,6 @@ #define VXGE_CACHE_LINE_SIZE 128 #endif -#define vxge_os_vaprintf(level, mask, fmt, ...) { \ - char buff[255]; \ - snprintf(buff, 255, fmt, __VA_ARGS__); \ - printk(buff); \ - printk("\n"); \ -} - #ifndef VXGE_ALIGN #define VXGE_ALIGN(adrs, size) \ (((size) - (((u64)adrs) & ((size)-1))) & ((size)-1)) @@ -37,7 +30,6 @@ #define VXGE_HW_DEFAULT_MTU 1500 #ifdef VXGE_DEBUG_ASSERT - /** * vxge_assert * @test: C-condition to check @@ -48,16 +40,13 @@ * compilation * time. */ -#define vxge_assert(test) { \ - if (!(test)) \ - vxge_os_bug("bad cond: "#test" at %s:%d\n", \ - __FILE__, __LINE__); } +#define vxge_assert(test) BUG_ON(!(test)) #else #define vxge_assert(test) #endif /* end of VXGE_DEBUG_ASSERT */ /** - * enum enum vxge_debug_level + * enum vxge_debug_level * @VXGE_NONE: debug disabled * @VXGE_ERR: all errors going to be logged out * @VXGE_TRACE: all errors plus all kind of verbose tracing print outs @@ -2000,7 +1989,7 @@ enum vxge_hw_status vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask); /** - * vxge_debug + * vxge_debug_ll * @level: level of debug verbosity. * @mask: mask for the debug * @buf: Circular buffer for tracing @@ -2012,26 +2001,13 @@ vxge_hw_vpath_strip_fcs_check(struct __vxge_hw_device *hldev, u64 vpath_mask); * may be compiled out if DEBUG macro was never defined. * See also: enum vxge_debug_level{}. */ - -#define vxge_trace_aux(level, mask, fmt, ...) \ -{\ - vxge_os_vaprintf(level, mask, fmt, __VA_ARGS__);\ -} - -#define vxge_debug(module, level, mask, fmt, ...) { \ -if ((level >= VXGE_TRACE && ((module & VXGE_DEBUG_TRACE_MASK) == module)) || \ - (level >= VXGE_ERR && ((module & VXGE_DEBUG_ERR_MASK) == module))) {\ - if ((mask & VXGE_DEBUG_MASK) == mask)\ - vxge_trace_aux(level, mask, fmt, __VA_ARGS__); \ -} \ -} - #if (VXGE_COMPONENT_LL & VXGE_DEBUG_MODULE_MASK) -#define vxge_debug_ll(level, mask, fmt, ...) \ -{\ - vxge_debug(VXGE_COMPONENT_LL, level, mask, fmt, __VA_ARGS__);\ -} - +#define vxge_debug_ll(level, mask, fmt, ...) do { \ + if ((level >= VXGE_ERR && VXGE_COMPONENT_LL & VXGE_DEBUG_ERR_MASK) || \ + (level >= VXGE_TRACE && VXGE_COMPONENT_LL & VXGE_DEBUG_TRACE_MASK))\ + if ((mask & VXGE_DEBUG_MASK) == mask) \ + printk(fmt "\n", __VA_ARGS__); \ +} while (0) #else #define vxge_debug_ll(level, mask, fmt, ...) #endif diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 54989d07af34..3845e628a597 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -387,8 +387,6 @@ struct vxge_tx_priv { static int p = val; \ module_param(p, int, 0) -#define vxge_os_bug(fmt...) { printk(fmt); BUG(); } - #define vxge_os_timer(timer, handle, arg, exp) do { \ init_timer(&timer); \ timer.function = handle; \ -- cgit v1.2.3 From 8424e00dfd5282026a93996a165fc4079d382169 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:56 +0000 Subject: vxge: serialize access to steering control register It is possible for multiple callers to access the firmware interface for the same vpath simultaneously, resulting in uncertain output. Add locks to serialize access. Also, make functions only accessed locally static, thus requiring some movement of code blocks. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 807 +++++++++++++++++------------------------ drivers/net/vxge/vxge-config.h | 1 + 2 files changed, 325 insertions(+), 483 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 212e301bdd68..c822463faf01 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -19,6 +19,7 @@ #include "vxge-traffic.h" #include "vxge-config.h" +#include "vxge-main.h" static enum vxge_hw_status __vxge_hw_fifo_create( @@ -103,12 +104,6 @@ __vxge_hw_device_id_get(struct __vxge_hw_device *hldev); static void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev); -static enum vxge_hw_status -__vxge_hw_vpath_card_info_get( - u32 vp_id, - struct vxge_hw_vpath_reg __iomem *vpath_reg, - struct vxge_hw_device_hw_info *hw_info); - static enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev); @@ -153,17 +148,6 @@ vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vpath_handle); static enum vxge_hw_status __vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg); -static u64 -__vxge_hw_vpath_pci_func_mode_get(u32 vp_id, - struct vxge_hw_vpath_reg __iomem *vpath_reg); - -static u32 -__vxge_hw_vpath_func_id_get(u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg); - -static enum vxge_hw_status -__vxge_hw_vpath_addr_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg, - u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN]); - static enum vxge_hw_status __vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath); @@ -171,9 +155,6 @@ __vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath); static enum vxge_hw_status __vxge_hw_vpath_sw_reset(struct __vxge_hw_device *devh, u32 vp_id); -static enum vxge_hw_status -__vxge_hw_vpath_fw_ver_get(u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg, - struct vxge_hw_device_hw_info *hw_info); static enum vxge_hw_status __vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh, u32 vp_id); @@ -275,6 +256,72 @@ void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev) } } +static enum vxge_hw_status +vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, + u32 fw_memo, u32 offset, u64 *data0, u64 *data1, + u64 *steer_ctrl) +{ + struct vxge_hw_vpath_reg __iomem *vp_reg; + enum vxge_hw_status status; + u64 val64; + u32 retry = 0, max_retry = 100; + + vp_reg = vpath->vp_reg; + + if (vpath->vp_open) { + max_retry = 3; + spin_lock(&vpath->lock); + } + + writeq(*data0, &vp_reg->rts_access_steer_data0); + writeq(*data1, &vp_reg->rts_access_steer_data1); + wmb(); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(fw_memo) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + *steer_ctrl; + + status = __vxge_hw_pio_mem_write64(val64, + &vp_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + /* The __vxge_hw_device_register_poll can udelay for a significant + * amount of time, blocking other proccess from the CPU. If it delays + * for ~5secs, a NMI error can occur. A way around this is to give up + * the processor via msleep, but this is not allowed is under lock. + * So, only allow it to sleep for ~4secs if open. Otherwise, delay for + * 1sec and sleep for 10ms until the firmware operation has completed + * or timed-out. + */ + while ((status != VXGE_HW_OK) && retry++ < max_retry) { + if (!vpath->vp_open) + msleep(20); + status = __vxge_hw_device_register_poll( + &vp_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + } + + if (status != VXGE_HW_OK) + goto out; + + val64 = readq(&vp_reg->rts_access_steer_ctrl); + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + *data0 = readq(&vp_reg->rts_access_steer_data0); + *data1 = readq(&vp_reg->rts_access_steer_data1); + *steer_ctrl = val64; + } else + status = VXGE_HW_FAIL; + +out: + if (vpath->vp_open) + spin_unlock(&vpath->lock); + return status; +} + /* * __vxge_hw_channel_allocate - Allocate memory for channel * This function allocates required memory for the channel and various arrays @@ -649,11 +696,26 @@ __vxge_hw_device_is_privilaged(u32 host_type, u32 func_id) return VXGE_HW_ERR_PRIVILAGED_OPEARATION; } +/* + * __vxge_hw_vpath_func_id_get - Get the function id of the vpath. + * Returns the function number of the vpath. + */ +static u32 +__vxge_hw_vpath_func_id_get(struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg) +{ + u64 val64; + + val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1); + + return + (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64); +} + /* * __vxge_hw_device_host_info_get * This routine returns the host type assignments */ -void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev) +static void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev) { u64 val64; u32 i; @@ -666,16 +728,18 @@ void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev) hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments); for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { - if (!(hldev->vpath_assignments & vxge_mBIT(i))) continue; hldev->func_id = - __vxge_hw_vpath_func_id_get(i, hldev->vpmgmt_reg[i]); + __vxge_hw_vpath_func_id_get(hldev->vpmgmt_reg[i]); hldev->access_rights = __vxge_hw_device_access_rights_get( hldev->host_type, hldev->func_id); + hldev->virtual_paths[i].vp_open = VXGE_HW_VP_NOT_OPEN; + hldev->virtual_paths[i].vp_reg = hldev->vpath_reg[i]; + hldev->first_vp_id = i; break; } @@ -732,6 +796,192 @@ exit: return status; } +/* + * __vxge_hw_vpath_fw_ver_get - Get the fw version + * Returns FW Version + */ +static enum vxge_hw_status +__vxge_hw_vpath_fw_ver_get(struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_device_hw_info *hw_info) +{ + struct vxge_hw_device_version *fw_version = &hw_info->fw_version; + struct vxge_hw_device_date *fw_date = &hw_info->fw_date; + struct vxge_hw_device_version *flash_version = &hw_info->flash_version; + struct vxge_hw_device_date *flash_date = &hw_info->flash_date; + u64 data0, data1 = 0, steer_ctrl = 0; + enum vxge_hw_status status; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + goto exit; + + fw_date->day = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(data0); + fw_date->month = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(data0); + fw_date->year = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(data0); + + snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d", + fw_date->month, fw_date->day, fw_date->year); + + fw_version->major = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0); + fw_version->minor = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0); + fw_version->build = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0); + + snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", + fw_version->major, fw_version->minor, fw_version->build); + + flash_date->day = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data1); + flash_date->month = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data1); + flash_date->year = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data1); + + snprintf(flash_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d", + flash_date->month, flash_date->day, flash_date->year); + + flash_version->major = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data1); + flash_version->minor = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data1); + flash_version->build = + (u32) VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data1); + + snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", + flash_version->major, flash_version->minor, + flash_version->build); + +exit: + return status; +} + +/* + * __vxge_hw_vpath_card_info_get - Get the serial numbers, + * part number and product description. + */ +static enum vxge_hw_status +__vxge_hw_vpath_card_info_get(struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_device_hw_info *hw_info) +{ + enum vxge_hw_status status; + u64 data0, data1 = 0, steer_ctrl = 0; + u8 *serial_number = hw_info->serial_number; + u8 *part_number = hw_info->part_number; + u8 *product_desc = hw_info->product_desc; + u32 i, j = 0; + + data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + return status; + + ((u64 *)serial_number)[0] = be64_to_cpu(data0); + ((u64 *)serial_number)[1] = be64_to_cpu(data1); + + data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER; + data1 = steer_ctrl = 0; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + return status; + + ((u64 *)part_number)[0] = be64_to_cpu(data0); + ((u64 *)part_number)[1] = be64_to_cpu(data1); + + for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0; + i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) { + data0 = i; + data1 = steer_ctrl = 0; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + return status; + + ((u64 *)product_desc)[j++] = be64_to_cpu(data0); + ((u64 *)product_desc)[j++] = be64_to_cpu(data1); + } + + return status; +} + +/* + * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode + * Returns pci function mode + */ +static u64 +__vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath) +{ + u64 data0, data1 = 0, steer_ctrl = 0; + enum vxge_hw_status status; + + data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); + + return data0; +} + +/* + * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath + * from MAC address table. + */ +static enum vxge_hw_status +__vxge_hw_vpath_addr_get(struct __vxge_hw_virtualpath *vpath, + u8 *macaddr, u8 *macaddr_mask) +{ + u64 action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY, + data0 = 0, data1 = 0, steer_ctrl = 0; + enum vxge_hw_status status; + int i; + + do { + status = vxge_hw_vpath_fw_api(vpath, action, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + goto exit; + + data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data0); + data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK( + data1); + + for (i = ETH_ALEN; i > 0; i--) { + macaddr[i - 1] = (u8) (data0 & 0xFF); + data0 >>= 8; + + macaddr_mask[i - 1] = (u8) (data1 & 0xFF); + data1 >>= 8; + } + + action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY; + data0 = 0, data1 = 0, steer_ctrl = 0; + + } while (!is_valid_ether_addr(macaddr)); +exit: + return status; +} + /** * vxge_hw_device_hw_info_get - Get the hw information * Returns the vpath mask that has the bits set for each vpath allocated @@ -747,9 +997,9 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, struct vxge_hw_toc_reg __iomem *toc; struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg; struct vxge_hw_common_reg __iomem *common_reg; - struct vxge_hw_vpath_reg __iomem *vpath_reg; struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg; enum vxge_hw_status status; + struct __vxge_hw_virtualpath vpath; memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info)); @@ -784,7 +1034,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *) (bar0 + val64); - hw_info->func_id = __vxge_hw_vpath_func_id_get(i, vpmgmt_reg); + hw_info->func_id = __vxge_hw_vpath_func_id_get(vpmgmt_reg); if (__vxge_hw_device_access_rights_get(hw_info->host_type, hw_info->func_id) & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) { @@ -800,16 +1050,18 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, val64 = readq(&toc->toc_vpath_pointer[i]); - vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) + (bar0 + val64); + vpath.vp_open = 0; hw_info->function_mode = - __vxge_hw_vpath_pci_func_mode_get(i, vpath_reg); + __vxge_hw_vpath_pci_func_mode_get(&vpath); - status = __vxge_hw_vpath_fw_ver_get(i, vpath_reg, hw_info); + status = __vxge_hw_vpath_fw_ver_get(&vpath, hw_info); if (status != VXGE_HW_OK) goto exit; - status = __vxge_hw_vpath_card_info_get(i, vpath_reg, hw_info); + status = __vxge_hw_vpath_card_info_get(&vpath, hw_info); if (status != VXGE_HW_OK) goto exit; @@ -817,14 +1069,15 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, } for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { - if (!((hw_info->vpath_mask) & vxge_mBIT(i))) continue; val64 = readq(&toc->toc_vpath_pointer[i]); - vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) + (bar0 + val64); + vpath.vp_open = 0; - status = __vxge_hw_vpath_addr_get(i, vpath_reg, + status = __vxge_hw_vpath_addr_get(&vpath, hw_info->mac_addrs[i], hw_info->mac_addr_masks[i]); if (status != VXGE_HW_OK) @@ -896,7 +1149,6 @@ vxge_hw_device_initialize( nblocks++; for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { - if (!(hldev->vpath_assignments & vxge_mBIT(i))) continue; @@ -921,7 +1173,6 @@ vxge_hw_device_initialize( } status = __vxge_hw_device_initialize(hldev); - if (status != VXGE_HW_OK) { vxge_hw_device_terminate(hldev); goto exit; @@ -958,7 +1209,6 @@ vxge_hw_device_stats_get(struct __vxge_hw_device *hldev, enum vxge_hw_status status = VXGE_HW_OK; for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { - if (!(hldev->vpaths_deployed & vxge_mBIT(i)) || (hldev->virtual_paths[i].vp_open == VXGE_HW_VP_NOT_OPEN)) @@ -2755,297 +3005,6 @@ exit: return status; } -/* - * __vxge_hw_vpath_func_id_get - Get the function id of the vpath. - * Returns the function number of the vpath. - */ -static u32 -__vxge_hw_vpath_func_id_get(u32 vp_id, - struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg) -{ - u64 val64; - - val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1); - - return - (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64); -} - -/* - * __vxge_hw_read_rts_ds - Program RTS steering critieria - */ -static inline void -__vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg, - u64 dta_struct_sel) -{ - writeq(0, &vpath_reg->rts_access_steer_ctrl); - wmb(); - writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0); - writeq(0, &vpath_reg->rts_access_steer_data1); - wmb(); -} - - -/* - * __vxge_hw_vpath_card_info_get - Get the serial numbers, - * part number and product description. - */ -static enum vxge_hw_status -__vxge_hw_vpath_card_info_get( - u32 vp_id, - struct vxge_hw_vpath_reg __iomem *vpath_reg, - struct vxge_hw_device_hw_info *hw_info) -{ - u32 i, j; - u64 val64; - u64 data1 = 0ULL; - u64 data2 = 0ULL; - enum vxge_hw_status status = VXGE_HW_OK; - u8 *serial_number = hw_info->serial_number; - u8 *part_number = hw_info->part_number; - u8 *product_desc = hw_info->product_desc; - - __vxge_hw_read_rts_ds(vpath_reg, - VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER); - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - return status; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - data1 = readq(&vpath_reg->rts_access_steer_data0); - ((u64 *)serial_number)[0] = be64_to_cpu(data1); - - data2 = readq(&vpath_reg->rts_access_steer_data1); - ((u64 *)serial_number)[1] = be64_to_cpu(data2); - status = VXGE_HW_OK; - } else - *serial_number = 0; - - __vxge_hw_read_rts_ds(vpath_reg, - VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER); - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - return status; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - - data1 = readq(&vpath_reg->rts_access_steer_data0); - ((u64 *)part_number)[0] = be64_to_cpu(data1); - - data2 = readq(&vpath_reg->rts_access_steer_data1); - ((u64 *)part_number)[1] = be64_to_cpu(data2); - - status = VXGE_HW_OK; - - } else - *part_number = 0; - - j = 0; - - for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0; - i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) { - - __vxge_hw_read_rts_ds(vpath_reg, i); - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - return status; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - - data1 = readq(&vpath_reg->rts_access_steer_data0); - ((u64 *)product_desc)[j++] = be64_to_cpu(data1); - - data2 = readq(&vpath_reg->rts_access_steer_data1); - ((u64 *)product_desc)[j++] = be64_to_cpu(data2); - - status = VXGE_HW_OK; - } else - *product_desc = 0; - } - - return status; -} - -/* - * __vxge_hw_vpath_fw_ver_get - Get the fw version - * Returns FW Version - */ -static enum vxge_hw_status -__vxge_hw_vpath_fw_ver_get( - u32 vp_id, - struct vxge_hw_vpath_reg __iomem *vpath_reg, - struct vxge_hw_device_hw_info *hw_info) -{ - u64 val64; - u64 data1 = 0ULL; - u64 data2 = 0ULL; - struct vxge_hw_device_version *fw_version = &hw_info->fw_version; - struct vxge_hw_device_date *fw_date = &hw_info->fw_date; - struct vxge_hw_device_version *flash_version = &hw_info->flash_version; - struct vxge_hw_device_date *flash_date = &hw_info->flash_date; - enum vxge_hw_status status = VXGE_HW_OK; - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - goto exit; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - - data1 = readq(&vpath_reg->rts_access_steer_data0); - data2 = readq(&vpath_reg->rts_access_steer_data1); - - fw_date->day = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY( - data1); - fw_date->month = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH( - data1); - fw_date->year = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR( - data1); - - snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d", - fw_date->month, fw_date->day, fw_date->year); - - fw_version->major = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data1); - fw_version->minor = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data1); - fw_version->build = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data1); - - snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", - fw_version->major, fw_version->minor, fw_version->build); - - flash_date->day = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data2); - flash_date->month = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data2); - flash_date->year = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data2); - - snprintf(flash_date->date, VXGE_HW_FW_STRLEN, - "%2.2d/%2.2d/%4.4d", - flash_date->month, flash_date->day, flash_date->year); - - flash_version->major = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data2); - flash_version->minor = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data2); - flash_version->build = - (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data2); - - snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", - flash_version->major, flash_version->minor, - flash_version->build); - - status = VXGE_HW_OK; - - } else - status = VXGE_HW_FAIL; -exit: - return status; -} - -/* - * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode - * Returns pci function mode - */ -static u64 -__vxge_hw_vpath_pci_func_mode_get( - u32 vp_id, - struct vxge_hw_vpath_reg __iomem *vpath_reg) -{ - u64 val64; - u64 data1 = 0ULL; - enum vxge_hw_status status = VXGE_HW_OK; - - __vxge_hw_read_rts_ds(vpath_reg, - VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE); - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - goto exit; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - data1 = readq(&vpath_reg->rts_access_steer_data0); - status = VXGE_HW_OK; - } else { - data1 = 0; - status = VXGE_HW_FAIL; - } -exit: - return data1; -} - /** * vxge_hw_device_flick_link_led - Flick (blink) link LED. * @hldev: HW device. @@ -3054,37 +3013,24 @@ exit: * Flicker the link LED. */ enum vxge_hw_status -vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev, - u64 on_off) +vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev, u64 on_off) { - u64 val64; - enum vxge_hw_status status = VXGE_HW_OK; - struct vxge_hw_vpath_reg __iomem *vp_reg; + struct __vxge_hw_virtualpath *vpath; + u64 data0, data1 = 0, steer_ctrl = 0; + enum vxge_hw_status status; if (hldev == NULL) { status = VXGE_HW_ERR_INVALID_DEVICE; goto exit; } - vp_reg = hldev->vpath_reg[hldev->first_vp_id]; + vpath = &hldev->virtual_paths[hldev->first_vp_id]; - writeq(0, &vp_reg->rts_access_steer_ctrl); - wmb(); - writeq(on_off, &vp_reg->rts_access_steer_data0); - writeq(0, &vp_reg->rts_access_steer_data1); - wmb(); - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vp_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); + data0 = on_off; + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + 0, &data0, &data1, &steer_ctrl); exit: return status; } @@ -3093,63 +3039,38 @@ exit: * __vxge_hw_vpath_rts_table_get - Get the entries from RTS access tables */ enum vxge_hw_status -__vxge_hw_vpath_rts_table_get( - struct __vxge_hw_vpath_handle *vp, - u32 action, u32 rts_table, u32 offset, u64 *data1, u64 *data2) +__vxge_hw_vpath_rts_table_get(struct __vxge_hw_vpath_handle *vp, + u32 action, u32 rts_table, u32 offset, + u64 *data0, u64 *data1) { - u64 val64; - struct __vxge_hw_virtualpath *vpath; - struct vxge_hw_vpath_reg __iomem *vp_reg; - - enum vxge_hw_status status = VXGE_HW_OK; + enum vxge_hw_status status; + u64 steer_ctrl = 0; if (vp == NULL) { status = VXGE_HW_ERR_INVALID_HANDLE; goto exit; } - vpath = vp->vpath; - vp_reg = vpath->vp_reg; - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset); - if ((rts_table == - VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) || + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) || (rts_table == - VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) || + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) || (rts_table == - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) || + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) || (rts_table == - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) { - val64 = val64 | VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL; + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) { + steer_ctrl = VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL; } - status = __vxge_hw_pio_mem_write64(val64, - &vp_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - vpath->hldev->config.device_poll_millis); - + status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset, + data0, data1, &steer_ctrl); if (status != VXGE_HW_OK) goto exit; - val64 = readq(&vp_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - - *data1 = readq(&vp_reg->rts_access_steer_data0); - - if ((rts_table == - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) || - (rts_table == - VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) { - *data2 = readq(&vp_reg->rts_access_steer_data1); - } - status = VXGE_HW_OK; - } else - status = VXGE_HW_FAIL; + if ((rts_table != VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) || + (rts_table != + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) + *data1 = 0; exit: return status; } @@ -3158,107 +3079,27 @@ exit: * __vxge_hw_vpath_rts_table_set - Set the entries of RTS access tables */ enum vxge_hw_status -__vxge_hw_vpath_rts_table_set( - struct __vxge_hw_vpath_handle *vp, u32 action, u32 rts_table, - u32 offset, u64 data1, u64 data2) +__vxge_hw_vpath_rts_table_set(struct __vxge_hw_vpath_handle *vp, u32 action, + u32 rts_table, u32 offset, u64 steer_data0, + u64 steer_data1) { - u64 val64; - struct __vxge_hw_virtualpath *vpath; - enum vxge_hw_status status = VXGE_HW_OK; - struct vxge_hw_vpath_reg __iomem *vp_reg; + u64 data0, data1 = 0, steer_ctrl = 0; + enum vxge_hw_status status; if (vp == NULL) { status = VXGE_HW_ERR_INVALID_HANDLE; goto exit; } - vpath = vp->vpath; - vp_reg = vpath->vp_reg; - - writeq(data1, &vp_reg->rts_access_steer_data0); - wmb(); + data0 = steer_data0; if ((rts_table == VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) || (rts_table == - VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) { - writeq(data2, &vp_reg->rts_access_steer_data1); - wmb(); - } + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) + data1 = steer_data1; - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset); - - status = __vxge_hw_pio_mem_write64(val64, - &vp_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - vpath->hldev->config.device_poll_millis); - - if (status != VXGE_HW_OK) - goto exit; - - val64 = readq(&vp_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) - status = VXGE_HW_OK; - else - status = VXGE_HW_FAIL; -exit: - return status; -} - -/* - * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath - * from MAC address table. - */ -static enum vxge_hw_status -__vxge_hw_vpath_addr_get( - u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg, - u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN]) -{ - u32 i; - u64 val64; - u64 data1 = 0ULL; - u64 data2 = 0ULL; - enum vxge_hw_status status = VXGE_HW_OK; - - val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( - VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) | - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | - VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); - - status = __vxge_hw_pio_mem_write64(val64, - &vpath_reg->rts_access_steer_ctrl, - VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, - VXGE_HW_DEF_DEVICE_POLL_MILLIS); - - if (status != VXGE_HW_OK) - goto exit; - - val64 = readq(&vpath_reg->rts_access_steer_ctrl); - - if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { - - data1 = readq(&vpath_reg->rts_access_steer_data0); - data2 = readq(&vpath_reg->rts_access_steer_data1); - - data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1); - data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK( - data2); - - for (i = ETH_ALEN; i > 0; i--) { - macaddr[i-1] = (u8)(data1 & 0xFF); - data1 >>= 8; - - macaddr_mask[i-1] = (u8)(data2 & 0xFF); - data2 >>= 8; - } - status = VXGE_HW_OK; - } else - status = VXGE_HW_FAIL; + status = vxge_hw_vpath_fw_api(vp->vpath, action, rts_table, offset, + &data0, &data1, &steer_ctrl); exit: return status; } @@ -4199,6 +4040,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, vpath = &hldev->virtual_paths[vp_id]; + spin_lock_init(&hldev->virtual_paths[vp_id].lock); vpath->vp_id = vp_id; vpath->vp_open = VXGE_HW_VP_OPEN; vpath->hldev = hldev; @@ -4209,14 +4051,12 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, __vxge_hw_vpath_reset(hldev, vp_id); status = __vxge_hw_vpath_reset_check(vpath); - if (status != VXGE_HW_OK) { memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); goto exit; } status = __vxge_hw_vpath_mgmt_read(hldev, vpath); - if (status != VXGE_HW_OK) { memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); goto exit; @@ -4230,7 +4070,6 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, hldev->tim_int_mask1, vp_id); status = __vxge_hw_vpath_initialize(hldev, vp_id); - if (status != VXGE_HW_OK) __vxge_hw_vp_terminate(hldev, vp_id); exit: @@ -4496,7 +4335,9 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) __vxge_hw_vp_terminate(devh, vp_id); + spin_lock(&vpath->lock); vpath->vp_open = VXGE_HW_VP_NOT_OPEN; + spin_unlock(&vpath->lock); vpath_close_exit: return status; diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index b395d8db318a..6a81014df597 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -641,6 +641,7 @@ struct __vxge_hw_virtualpath { struct vxge_hw_vpath_stats_hw_info *hw_stats; struct vxge_hw_vpath_stats_hw_info *hw_stats_sav; struct vxge_hw_vpath_stats_sw_info *sw_stats; + spinlock_t lock; }; /* -- cgit v1.2.3 From e8ac175615b9458a00193c55617b5b8865e67817 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:57 +0000 Subject: vxge: add support for ethtool firmware flashing Add the ability in the vxge driver to flash firmware via ethtool. Updated to include comments from Ben Hutchings. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 183 +++++++++++++++++++++++++++++++++++++- drivers/net/vxge/vxge-config.h | 71 ++++++++++++++- drivers/net/vxge/vxge-ethtool.c | 20 +++++ drivers/net/vxge/vxge-main.c | 190 ++++++++++++++++++++++++++++++++++++---- drivers/net/vxge/vxge-main.h | 2 + drivers/net/vxge/vxge-reg.h | 29 +++++- drivers/net/vxge/vxge-version.h | 27 ++++++ 7 files changed, 500 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index c822463faf01..7761b9e0ad84 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -155,7 +155,6 @@ __vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath); static enum vxge_hw_status __vxge_hw_vpath_sw_reset(struct __vxge_hw_device *devh, u32 vp_id); - static enum vxge_hw_status __vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh, u32 vp_id); @@ -322,6 +321,188 @@ out: return status; } +enum vxge_hw_status +vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major, + u32 *minor, u32 *build) +{ + u64 data0 = 0, data1 = 0, steer_ctrl = 0; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status; + + vpath = &hldev->virtual_paths[hldev->first_vp_id]; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_FW_UPGRADE_ACTION, + VXGE_HW_FW_UPGRADE_MEMO, + VXGE_HW_FW_UPGRADE_OFFSET_READ, + &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + return status; + + *major = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data0); + *minor = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data0); + *build = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data0); + + return status; +} + +enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev) +{ + u64 data0 = 0, data1 = 0, steer_ctrl = 0; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status; + u32 ret; + + vpath = &hldev->virtual_paths[hldev->first_vp_id]; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_FW_UPGRADE_ACTION, + VXGE_HW_FW_UPGRADE_MEMO, + VXGE_HW_FW_UPGRADE_OFFSET_COMMIT, + &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: FW upgrade failed", __func__); + goto exit; + } + + ret = VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(steer_ctrl) & 0x7F; + if (ret != 1) { + vxge_debug_init(VXGE_ERR, "%s: FW commit failed with error %d", + __func__, ret); + status = VXGE_HW_FAIL; + } + +exit: + return status; +} + +enum vxge_hw_status +vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *fwdata, int size) +{ + u64 data0 = 0, data1 = 0, steer_ctrl = 0; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status; + int ret_code, sec_code; + + vpath = &hldev->virtual_paths[hldev->first_vp_id]; + + /* send upgrade start command */ + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_FW_UPGRADE_ACTION, + VXGE_HW_FW_UPGRADE_MEMO, + VXGE_HW_FW_UPGRADE_OFFSET_START, + &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, " %s: Upgrade start cmd failed", + __func__); + return status; + } + + /* Transfer fw image to adapter 16 bytes at a time */ + for (; size > 0; size -= VXGE_HW_FW_UPGRADE_BLK_SIZE) { + steer_ctrl = 0; + + /* The next 128bits of fwdata to be loaded onto the adapter */ + data0 = *((u64 *)fwdata); + data1 = *((u64 *)fwdata + 1); + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_FW_UPGRADE_ACTION, + VXGE_HW_FW_UPGRADE_MEMO, + VXGE_HW_FW_UPGRADE_OFFSET_SEND, + &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: Upgrade send failed", + __func__); + goto out; + } + + ret_code = VXGE_HW_UPGRADE_GET_RET_ERR_CODE(data0); + switch (ret_code) { + case VXGE_HW_FW_UPGRADE_OK: + /* All OK, send next 16 bytes. */ + break; + case VXGE_FW_UPGRADE_BYTES2SKIP: + /* skip bytes in the stream */ + fwdata += (data0 >> 8) & 0xFFFFFFFF; + break; + case VXGE_HW_FW_UPGRADE_DONE: + goto out; + case VXGE_HW_FW_UPGRADE_ERR: + sec_code = VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(data0); + switch (sec_code) { + case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1: + case VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7: + printk(KERN_ERR + "corrupted data from .ncf file\n"); + break; + case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3: + case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4: + case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5: + case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6: + case VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8: + printk(KERN_ERR "invalid .ncf file\n"); + break; + case VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW: + printk(KERN_ERR "buffer overflow\n"); + break; + case VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH: + printk(KERN_ERR "failed to flash the image\n"); + break; + case VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN: + printk(KERN_ERR + "generic error. Unknown error type\n"); + break; + default: + printk(KERN_ERR "Unknown error of type %d\n", + sec_code); + break; + } + status = VXGE_HW_FAIL; + goto out; + default: + printk(KERN_ERR "Unknown FW error: %d\n", ret_code); + status = VXGE_HW_FAIL; + goto out; + } + /* point to next 16 bytes */ + fwdata += VXGE_HW_FW_UPGRADE_BLK_SIZE; + } +out: + return status; +} + +enum vxge_hw_status +vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev, + struct eprom_image *img) +{ + u64 data0 = 0, data1 = 0, steer_ctrl = 0; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status; + int i; + + vpath = &hldev->virtual_paths[hldev->first_vp_id]; + + for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) { + data0 = VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(i); + data1 = steer_ctrl = 0; + + status = vxge_hw_vpath_fw_api(vpath, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, + VXGE_HW_FW_API_GET_EPROM_REV, + 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + break; + + img[i].is_valid = VXGE_HW_GET_EPROM_IMAGE_VALID(data0); + img[i].index = VXGE_HW_GET_EPROM_IMAGE_INDEX(data0); + img[i].type = VXGE_HW_GET_EPROM_IMAGE_TYPE(data0); + img[i].version = VXGE_HW_GET_EPROM_IMAGE_REV(data0); + } + + return status; +} + /* * __vxge_hw_channel_allocate - Allocate memory for channel * This function allocates required memory for the channel and various arrays diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 6a81014df597..95230bda0653 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -29,6 +29,15 @@ #define VXGE_HW_MAX_MTU 9600 #define VXGE_HW_DEFAULT_MTU 1500 +#define VXGE_HW_MAX_ROM_IMAGES 8 + +struct eprom_image { + u8 is_valid:1; + u8 index; + u8 type; + u16 version; +}; + #ifdef VXGE_DEBUG_ASSERT /** * vxge_assert @@ -147,6 +156,47 @@ enum vxge_hw_device_link_state { VXGE_HW_LINK_UP }; +/** + * enum enum vxge_hw_fw_upgrade_code - FW upgrade return codes. + * @VXGE_HW_FW_UPGRADE_OK: All OK send next 16 bytes + * @VXGE_HW_FW_UPGRADE_DONE: upload completed + * @VXGE_HW_FW_UPGRADE_ERR: upload error + * @VXGE_FW_UPGRADE_BYTES2SKIP: skip bytes in the stream + * + */ +enum vxge_hw_fw_upgrade_code { + VXGE_HW_FW_UPGRADE_OK = 0, + VXGE_HW_FW_UPGRADE_DONE = 1, + VXGE_HW_FW_UPGRADE_ERR = 2, + VXGE_FW_UPGRADE_BYTES2SKIP = 3 +}; + +/** + * enum enum vxge_hw_fw_upgrade_err_code - FW upgrade error codes. + * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1: corrupt data + * @VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW: buffer overflow + * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3: invalid .ncf file + * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4: invalid .ncf file + * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5: invalid .ncf file + * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6: invalid .ncf file + * @VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7: corrupt data + * @VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8: invalid .ncf file + * @VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN: generic error unknown type + * @VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH: failed to flash image check failed + */ +enum vxge_hw_fw_upgrade_err_code { + VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_1 = 1, + VXGE_HW_FW_UPGRADE_ERR_BUFFER_OVERFLOW = 2, + VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_3 = 3, + VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_4 = 4, + VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_5 = 5, + VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_6 = 6, + VXGE_HW_FW_UPGRADE_ERR_CORRUPT_DATA_7 = 7, + VXGE_HW_FW_UPGRADE_ERR_INV_NCF_FILE_8 = 8, + VXGE_HW_FW_UPGRADE_ERR_GENERIC_ERROR_UNKNOWN = 9, + VXGE_HW_FW_UPGRADE_ERR_FAILED_TO_FLASH = 10 +}; + /** * struct vxge_hw_device_date - Date Format * @day: Day @@ -454,7 +504,6 @@ struct vxge_hw_device_config { * See also: vxge_hw_driver_initialize(). */ struct vxge_hw_uld_cbs { - void (*link_up)(struct __vxge_hw_device *devh); void (*link_down)(struct __vxge_hw_device *devh); void (*crit_err)(struct __vxge_hw_device *devh, @@ -721,6 +770,7 @@ struct __vxge_hw_device { u32 debug_level; u32 level_err; u32 level_trace; + u16 eprom_versions[VXGE_HW_MAX_ROM_IMAGES]; }; #define VXGE_HW_INFO_LEN 64 @@ -2032,7 +2082,22 @@ __vxge_hw_device_is_privilaged(u32 host_type, u32 func_id); #define VXGE_HW_MIN_SUCCESSIVE_IDLE_COUNT 5 #define VXGE_HW_MAX_POLLING_COUNT 100 -int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id); +void +vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +vxge_hw_upgrade_read_version(struct __vxge_hw_device *hldev, u32 *major, + u32 *minor, u32 *build); + +enum vxge_hw_status vxge_hw_flash_fw(struct __vxge_hw_device *hldev); -void vxge_hw_device_wait_receive_idle(struct __vxge_hw_device *hldev); +enum vxge_hw_status +vxge_update_fw_image(struct __vxge_hw_device *hldev, const u8 *filebuf, + int size); + +enum vxge_hw_status +vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev, + struct eprom_image *eprom_image_data); + +int vxge_hw_vpath_wait_receive_idle(struct __vxge_hw_device *hldev, u32 vp_id); #endif diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index f8fd8da4f173..3d2cd6acf30a 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -1153,6 +1153,25 @@ static int vxge_set_flags(struct net_device *dev, u32 data) return 0; } +static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + if (vdev->max_vpath_supported != VXGE_HW_MAX_VIRTUAL_PATHS) { + printk(KERN_INFO "Single Function Mode is required to flash the" + " firmware\n"); + return -EINVAL; + } + + if (netif_running(dev)) { + printk(KERN_INFO "Interface %s must be down to flash the " + "firmware\n", dev->name); + return -EBUSY; + } + + return vxge_fw_upgrade(vdev, parms->data, 1); +} + static const struct ethtool_ops vxge_ethtool_ops = { .get_settings = vxge_ethtool_gset, .set_settings = vxge_ethtool_sset, @@ -1175,6 +1194,7 @@ static const struct ethtool_ops vxge_ethtool_ops = { .get_sset_count = vxge_ethtool_get_sset_count, .get_ethtool_stats = vxge_get_ethtool_stats, .set_flags = vxge_set_flags, + .flash_device = vxge_fw_flash, }; void vxge_initialize_ethtool_ops(struct net_device *ndev) diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 53db6a4b9601..10549bd39221 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -50,6 +50,7 @@ #include #include #include +#include #include "vxge-main.h" #include "vxge-reg.h" @@ -3248,6 +3249,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, "%s: Ethernet device registered", ndev->name); + hldev->ndev = ndev; *vdev_out = vdev; /* Resetting the Device stats */ @@ -3935,6 +3937,142 @@ static inline u32 vxge_get_num_vfs(u64 function_mode) return num_functions; } +int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override) +{ + struct __vxge_hw_device *hldev = vdev->devh; + u32 maj, min, bld, cmaj, cmin, cbld; + enum vxge_hw_status status; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, fw_name, &vdev->pdev->dev); + if (ret) { + vxge_debug_init(VXGE_ERR, "%s: Firmware file '%s' not found", + VXGE_DRIVER_NAME, fw_name); + goto out; + } + + /* Load the new firmware onto the adapter */ + status = vxge_update_fw_image(hldev, fw->data, fw->size); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: FW image download to adapter failed '%s'.", + VXGE_DRIVER_NAME, fw_name); + ret = -EIO; + goto out; + } + + /* Read the version of the new firmware */ + status = vxge_hw_upgrade_read_version(hldev, &maj, &min, &bld); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: Upgrade read version failed '%s'.", + VXGE_DRIVER_NAME, fw_name); + ret = -EIO; + goto out; + } + + cmaj = vdev->config.device_hw_info.fw_version.major; + cmin = vdev->config.device_hw_info.fw_version.minor; + cbld = vdev->config.device_hw_info.fw_version.build; + /* It's possible the version in /lib/firmware is not the latest version. + * If so, we could get into a loop of trying to upgrade to the latest + * and flashing the older version. + */ + if (VXGE_FW_VER(maj, min, bld) == VXGE_FW_VER(cmaj, cmin, cbld) && + !override) { + ret = -EINVAL; + goto out; + } + + printk(KERN_NOTICE "Upgrade to firmware version %d.%d.%d commencing\n", + maj, min, bld); + + /* Flash the adapter with the new firmware */ + status = vxge_hw_flash_fw(hldev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: Upgrade commit failed '%s'.", + VXGE_DRIVER_NAME, fw_name); + ret = -EIO; + goto out; + } + + printk(KERN_NOTICE "Upgrade of firmware successful! Adapter must be " + "hard reset before using, thus requiring a system reboot or a " + "hotplug event.\n"); + +out: + return ret; +} + +static int vxge_probe_fw_update(struct vxgedev *vdev) +{ + u32 maj, min, bld; + int ret, gpxe = 0; + char *fw_name; + + maj = vdev->config.device_hw_info.fw_version.major; + min = vdev->config.device_hw_info.fw_version.minor; + bld = vdev->config.device_hw_info.fw_version.build; + + if (VXGE_FW_VER(maj, min, bld) == VXGE_CERT_FW_VER) + return 0; + + /* Ignore the build number when determining if the current firmware is + * "too new" to load the driver + */ + if (VXGE_FW_VER(maj, min, 0) > VXGE_CERT_FW_VER) { + vxge_debug_init(VXGE_ERR, "%s: Firmware newer than last known " + "version, unable to load driver\n", + VXGE_DRIVER_NAME); + return -EINVAL; + } + + /* Firmware 1.4.4 and older cannot be upgraded, and is too ancient to + * work with this driver. + */ + if (VXGE_FW_VER(maj, min, bld) <= VXGE_FW_DEAD_VER) { + vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d cannot be " + "upgraded\n", VXGE_DRIVER_NAME, maj, min, bld); + return -EINVAL; + } + + /* If file not specified, determine gPXE or not */ + if (VXGE_FW_VER(maj, min, bld) >= VXGE_EPROM_FW_VER) { + int i; + for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) + if (vdev->devh->eprom_versions[i]) { + gpxe = 1; + break; + } + } + if (gpxe) + fw_name = "vxge/X3fw-pxe.ncf"; + else + fw_name = "vxge/X3fw.ncf"; + + ret = vxge_fw_upgrade(vdev, fw_name, 0); + /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on + * probe, so ignore them + */ + if (ret != -EINVAL && ret != -ENOENT) + return -EIO; + else + ret = 0; + + if (VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, VXGE_CERT_FW_VER_MINOR, 0) > + VXGE_FW_VER(maj, min, 0)) { + vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d is too old to" + " be used with this driver.\n" + "Please get the latest version from " + "ftp://ftp.s2io.com/pub/X3100-Drivers/FIRMWARE", + VXGE_DRIVER_NAME, maj, min, bld); + return -EINVAL; + } + + return ret; +} + /** * vxge_probe * @pdev : structure containing the PCI related information of the device. @@ -4093,16 +4231,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit3; } - if (ll_config->device_hw_info.fw_version.major != - VXGE_DRIVER_FW_VERSION_MAJOR) { - vxge_debug_init(VXGE_ERR, - "%s: Incorrect firmware version." - "Please upgrade the firmware to version 1.x.x", - VXGE_DRIVER_NAME); - ret = -EINVAL; - goto _exit3; - } - vpath_mask = ll_config->device_hw_info.vpath_mask; if (vpath_mask == 0) { vxge_debug_ll_config(VXGE_TRACE, @@ -4166,6 +4294,32 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) goto _exit3; } + if (VXGE_FW_VER(ll_config->device_hw_info.fw_version.major, + ll_config->device_hw_info.fw_version.minor, + ll_config->device_hw_info.fw_version.build) >= + VXGE_EPROM_FW_VER) { + struct eprom_image img[VXGE_HW_MAX_ROM_IMAGES]; + + status = vxge_hw_vpath_eprom_img_ver_get(hldev, img); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: Reading of EPROM failed", + VXGE_DRIVER_NAME); + /* This is a non-fatal error, continue */ + } + + for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) { + hldev->eprom_versions[i] = img[i].version; + if (!img[i].is_valid) + break; + vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version " + "%d.%d.%d.%d\n", VXGE_DRIVER_NAME, i, + VXGE_EPROM_IMG_MAJOR(img[i].version), + VXGE_EPROM_IMG_MINOR(img[i].version), + VXGE_EPROM_IMG_FIX(img[i].version), + VXGE_EPROM_IMG_BUILD(img[i].version)); + } + } + /* if FCS stripping is not disabled in MAC fail driver load */ if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) { vxge_debug_init(VXGE_ERR, @@ -4194,18 +4348,22 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; - if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath, - &vdev)) { + ret = vxge_device_register(hldev, ll_config, high_dma, no_of_vpath, + &vdev); + if (ret) { ret = -EINVAL; goto _exit4; } + ret = vxge_probe_fw_update(vdev); + if (ret) + goto _exit5; + vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), vxge_hw_device_trace_level_get(hldev)); /* set private HW device info */ - hldev->ndev = vdev->ndev; vdev->mtu = VXGE_HW_DEFAULT_MTU; vdev->bar0 = attr.bar0; vdev->max_vpath_supported = max_vpath_supported; @@ -4307,7 +4465,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) "%s: mac_addr_list : memory allocation failed", vdev->ndev->name); ret = -EPERM; - goto _exit5; + goto _exit6; } macaddr = (u8 *)&entry->macaddr; memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); @@ -4347,10 +4505,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) kfree(ll_config); return 0; -_exit5: +_exit6: for (i = 0; i < vdev->no_of_vpath; i++) vxge_free_mac_add_list(&vdev->vpaths[i]); - +_exit5: vxge_device_unregister(hldev); _exit4: pci_disable_sriov(pdev); diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 3845e628a597..1699d7590b31 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -397,6 +397,8 @@ struct vxge_tx_priv { extern void vxge_initialize_ethtool_ops(struct net_device *ndev); enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); +int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override); + /** * #define VXGE_DEBUG_INIT: debug for initialization functions * #define VXGE_DEBUG_TX : debug transmit related functions diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 93fd752187bc..0df52dbd42a0 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -49,6 +49,30 @@ #define VXGE_HW_TITAN_VPMGMT_REG_SPACES 17 #define VXGE_HW_TITAN_VPATH_REG_SPACES 17 +#define VXGE_HW_FW_API_GET_EPROM_REV 31 + +#define VXGE_EPROM_IMG_MAJOR(val) (u32) vxge_bVALn(val, 48, 4) +#define VXGE_EPROM_IMG_MINOR(val) (u32) vxge_bVALn(val, 52, 4) +#define VXGE_EPROM_IMG_FIX(val) (u32) vxge_bVALn(val, 56, 4) +#define VXGE_EPROM_IMG_BUILD(val) (u32) vxge_bVALn(val, 60, 4) + +#define VXGE_HW_GET_EPROM_IMAGE_INDEX(val) vxge_bVALn(val, 16, 8) +#define VXGE_HW_GET_EPROM_IMAGE_VALID(val) vxge_bVALn(val, 31, 1) +#define VXGE_HW_GET_EPROM_IMAGE_TYPE(val) vxge_bVALn(val, 40, 8) +#define VXGE_HW_GET_EPROM_IMAGE_REV(val) vxge_bVALn(val, 48, 16) +#define VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(val) vxge_vBIT(val, 16, 8) + +#define VXGE_HW_FW_UPGRADE_MEMO 13 +#define VXGE_HW_FW_UPGRADE_ACTION 16 +#define VXGE_HW_FW_UPGRADE_OFFSET_START 2 +#define VXGE_HW_FW_UPGRADE_OFFSET_SEND 3 +#define VXGE_HW_FW_UPGRADE_OFFSET_COMMIT 4 +#define VXGE_HW_FW_UPGRADE_OFFSET_READ 5 + +#define VXGE_HW_FW_UPGRADE_BLK_SIZE 16 +#define VXGE_HW_UPGRADE_GET_RET_ERR_CODE(val) (val & 0xff) +#define VXGE_HW_UPGRADE_GET_SEC_ERR_CODE(val) ((val >> 8) & 0xff) + #define VXGE_HW_ASIC_MODE_RESERVED 0 #define VXGE_HW_ASIC_MODE_NO_IOV 1 #define VXGE_HW_ASIC_MODE_SR_IOV 2 @@ -165,13 +189,13 @@ #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE 2 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN 3 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG 5 -#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6 +#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG 7 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK 8 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY 9 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS 10 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS 11 -#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12 +#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12 #define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO 13 #define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \ @@ -437,6 +461,7 @@ #define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \ vxge_bVALn(bits, 48, 16) #define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_GET_ACTION(bits) vxge_bVALn(bits, 0, 8) #define VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\ vxge_bVALn(bits, 0, 18) diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index 53fefe137368..b4eced19e45d 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -19,4 +19,31 @@ #define VXGE_VERSION_FIX "9" #define VXGE_VERSION_BUILD "20840" #define VXGE_VERSION_FOR "k" + +#define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) + +#define VXGE_DEAD_FW_VER_MAJOR 1 +#define VXGE_DEAD_FW_VER_MINOR 4 +#define VXGE_DEAD_FW_VER_BUILD 4 + +#define VXGE_FW_DEAD_VER VXGE_FW_VER(VXGE_DEAD_FW_VER_MAJOR, \ + VXGE_DEAD_FW_VER_MINOR, \ + VXGE_DEAD_FW_VER_BUILD) + +#define VXGE_EPROM_FW_VER_MAJOR 1 +#define VXGE_EPROM_FW_VER_MINOR 6 +#define VXGE_EPROM_FW_VER_BUILD 1 + +#define VXGE_EPROM_FW_VER VXGE_FW_VER(VXGE_EPROM_FW_VER_MAJOR, \ + VXGE_EPROM_FW_VER_MINOR, \ + VXGE_EPROM_FW_VER_BUILD) + +#define VXGE_CERT_FW_VER_MAJOR 1 +#define VXGE_CERT_FW_VER_MINOR 8 +#define VXGE_CERT_FW_VER_BUILD 1 + +#define VXGE_CERT_FW_VER VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, \ + VXGE_CERT_FW_VER_MINOR, \ + VXGE_CERT_FW_VER_BUILD) + #endif -- cgit v1.2.3 From b81b37338412e3215670641e5025c85146521dea Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:58 +0000 Subject: vxge: add receive hardware timestamping Add support for enable/disabling hardware timestamping on receive packets via ioctl call. When enabled, the hardware timestamp replaces the FCS in the payload. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-main.c | 133 +++++++++++++++++++++++++++++++++++++++++-- drivers/net/vxge/vxge-main.h | 8 ++- 2 files changed, 132 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 10549bd39221..ea303a2af3aa 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "vxge-main.h" #include "vxge-reg.h" @@ -369,7 +370,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, u8 t_code, void *userdata) { struct vxge_ring *ring = (struct vxge_ring *)userdata; - struct net_device *dev = ring->ndev; + struct net_device *dev = ring->ndev; unsigned int dma_sizes; void *first_dtr = NULL; int dtr_cnt = 0; @@ -513,6 +514,16 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, else skb_checksum_none_assert(skb); + + if (ring->rx_hwts) { + struct skb_shared_hwtstamps *skb_hwts; + u32 ns = *(u32 *)(skb->head + pkt_length); + + skb_hwts = skb_hwtstamps(skb); + skb_hwts->hwtstamp = ns_to_ktime(ns); + skb_hwts->syststamp.tv64 = 0; + } + /* rth_hash_type and rth_it_hit are non-zero regardless of * whether rss is enabled. Only the rth_value is zero/non-zero * if rss is disabled/enabled, so key off of that. @@ -2037,6 +2048,7 @@ static int vxge_open_vpaths(struct vxgedev *vdev) vdev->config.fifo_indicate_max_pkts; vpath->ring.rx_vector_no = 0; vpath->ring.rx_csum = vdev->rx_csum; + vpath->ring.rx_hwts = vdev->rx_hwts; vpath->is_open = 1; vdev->vp_handles[i] = vpath->handle; vpath->ring.gro_enable = vdev->config.gro_enable; @@ -2971,6 +2983,101 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) return net_stats; } +static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev, + int enable) +{ + enum vxge_hw_status status; + u64 val64; + + /* Timestamp is passed to the driver via the FCS, therefore we + * must disable the FCS stripping by the adapter. Since this is + * required for the driver to load (due to a hardware bug), + * there is no need to do anything special here. + */ + if (enable) + val64 = VXGE_HW_XMAC_TIMESTAMP_EN | + VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) | + VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0); + else + val64 = 0; + + status = vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + offsetof(struct vxge_hw_mrpcim_reg, + xmac_timestamp), + val64); + vxge_hw_device_flush_io(vdev->devh); + return status; +} + +static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data) +{ + struct hwtstamp_config config; + enum vxge_hw_status status; + int i; + + if (copy_from_user(&config, data, sizeof(config))) + return -EFAULT; + + /* reserved for future extensions */ + if (config.flags) + return -EINVAL; + + /* Transmit HW Timestamp not supported */ + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + break; + case HWTSTAMP_TX_ON: + default: + return -ERANGE; + } + + switch (config.rx_filter) { + case HWTSTAMP_FILTER_NONE: + status = vxge_timestamp_config(vdev, 0); + if (status != VXGE_HW_OK) + return -EFAULT; + + vdev->rx_hwts = 0; + config.rx_filter = HWTSTAMP_FILTER_NONE; + break; + + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + status = vxge_timestamp_config(vdev, 1); + if (status != VXGE_HW_OK) + return -EFAULT; + + vdev->rx_hwts = 1; + config.rx_filter = HWTSTAMP_FILTER_ALL; + break; + + default: + return -ERANGE; + } + + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].ring.rx_hwts = vdev->rx_hwts; + + if (copy_to_user(data, &config, sizeof(config))) + return -EFAULT; + + return 0; +} + /** * vxge_ioctl * @dev: Device pointer. @@ -2983,7 +3090,20 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) */ static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - return -EOPNOTSUPP; + struct vxgedev *vdev = netdev_priv(dev); + int ret; + + switch (cmd) { + case SIOCSHWTSTAMP: + ret = vxge_hwtstamp_ioctl(vdev, rq->ifr_data); + if (ret) + return ret; + break; + default: + return -EOPNOTSUPP; + } + + return 0; } /** @@ -3180,6 +3300,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vdev->pdev = hldev->pdev; memcpy(&vdev->config, config, sizeof(struct vxge_config)); vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ + vdev->rx_hwts = 0; SET_NETDEV_DEV(ndev, &vdev->pdev->dev); @@ -4321,10 +4442,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) } /* if FCS stripping is not disabled in MAC fail driver load */ - if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) { - vxge_debug_init(VXGE_ERR, - "%s: FCS stripping is not disabled in MAC" - " failing driver load", VXGE_DRIVER_NAME); + status = vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, "%s: FCS stripping is enabled in MAC" + " failing driver load", VXGE_DRIVER_NAME); ret = -EINVAL; goto _exit4; } diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 1699d7590b31..6f6e9ce0bf20 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -248,8 +248,9 @@ struct vxge_ring { */ int driver_id; - /* copy of the flag indicating whether rx_csum is to be used */ - u32 rx_csum; + /* copy of the flag indicating whether rx_csum is to be used */ + u32 rx_csum:1, + rx_hwts:1; int pkts_processed; int budget; @@ -327,7 +328,8 @@ struct vxgedev { u16 all_multi_flg; /* A flag indicating whether rx_csum is to be used or not. */ - u32 rx_csum; + u32 rx_csum:1, + rx_hwts:1; struct vxge_msix_entry *vxge_entries; struct msix_entry *entries; -- cgit v1.2.3 From c3150eac9f2e5f770b09d371f7716540219a46f6 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:25:59 +0000 Subject: vxge: Handle errors in vxge_hw_vpath_fw_api Propagate the return code of the call to vxge_hw_vpath_fw_api and __vxge_hw_vpath_pci_func_mode_get. This enables the proper handling of error conditions when querying the function mode of the device during probe. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 7761b9e0ad84..388e6c48696b 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -1107,8 +1107,9 @@ __vxge_hw_vpath_card_info_get(struct __vxge_hw_virtualpath *vpath, * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode * Returns pci function mode */ -static u64 -__vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath) +static enum vxge_hw_status +__vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_device_hw_info *hw_info) { u64 data0, data1 = 0, steer_ctrl = 0; enum vxge_hw_status status; @@ -1119,8 +1120,11 @@ __vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath) VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, 0, &data0, &data1, &steer_ctrl); + if (status != VXGE_HW_OK) + return status; - return data0; + hw_info->function_mode = data0; + return status; } /* @@ -1235,8 +1239,9 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, (bar0 + val64); vpath.vp_open = 0; - hw_info->function_mode = - __vxge_hw_vpath_pci_func_mode_get(&vpath); + status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); + if (status != VXGE_HW_OK) + goto exit; status = __vxge_hw_vpath_fw_ver_get(&vpath, hw_info); if (status != VXGE_HW_OK) -- cgit v1.2.3 From e7935c9669c27c5d530bff634c0c15f7a602d697 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:26:00 +0000 Subject: vxge: Titan1A detection Detect if the adapter is Titan or Titan1A, and tune the driver for this hardware. Also, remove unnecessary function __vxge_hw_device_id_get. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 40 ++++++++------------------------- drivers/net/vxge/vxge-config.h | 6 ----- drivers/net/vxge/vxge-main.c | 45 ++++++++++++++++++++++++++++++++----- drivers/net/vxge/vxge-main.h | 51 +++++++++++++++++++++++++++++++----------- 4 files changed, 87 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 388e6c48696b..5903b2e9a6e9 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -98,9 +98,6 @@ __vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config); static enum vxge_hw_status __vxge_hw_device_config_check(struct vxge_hw_device_config *new_config); -static void -__vxge_hw_device_id_get(struct __vxge_hw_device *hldev); - static void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev); @@ -805,26 +802,6 @@ exit: return status; } -/* - * __vxge_hw_device_id_get - * This routine returns sets the device id and revision numbers into the device - * structure - */ -void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev) -{ - u64 val64; - - val64 = readq(&hldev->common_reg->titan_asic_id); - hldev->device_id = - (u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64); - - hldev->major_revision = - (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64); - - hldev->minor_revision = - (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64); -} - /* * __vxge_hw_device_access_rights_get: Get Access Rights of the driver * This routine returns the Access Rights of the driver @@ -1327,7 +1304,6 @@ vxge_hw_device_initialize( vfree(hldev); goto exit; } - __vxge_hw_device_id_get(hldev); __vxge_hw_device_host_info_get(hldev); @@ -4442,16 +4418,18 @@ vpath_open_exit1: void vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp) { - struct __vxge_hw_virtualpath *vpath = NULL; + struct __vxge_hw_virtualpath *vpath = vp->vpath; + struct __vxge_hw_ring *ring = vpath->ringh; + struct vxgedev *vdev = netdev_priv(vpath->hldev->ndev); u64 new_count, val64, val164; - struct __vxge_hw_ring *ring; - vpath = vp->vpath; - ring = vpath->ringh; + if (vdev->titan1) { + new_count = readq(&vpath->vp_reg->rxdmem_size); + new_count &= 0x1fff; + } else + new_count = ring->config->ring_blocks * VXGE_HW_BLOCK_SIZE / 8; - new_count = readq(&vpath->vp_reg->rxdmem_size); - new_count &= 0x1fff; - val164 = (VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count)); + val164 = VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count); writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val164), &vpath->vp_reg->prc_rxd_doorbell); diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 95230bda0653..5b2c8313426d 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -713,9 +713,6 @@ struct __vxge_hw_vpath_handle{ /** * struct __vxge_hw_device - Hal device object * @magic: Magic Number - * @device_id: PCI Device Id of the adapter - * @major_revision: PCI Device major revision - * @minor_revision: PCI Device minor revision * @bar0: BAR0 virtual address. * @pdev: Physical device handle * @config: Confguration passed by the LL driver at initialization @@ -727,9 +724,6 @@ struct __vxge_hw_device { u32 magic; #define VXGE_HW_DEVICE_MAGIC 0x12345678 #define VXGE_HW_DEVICE_DEAD 0xDEADDEAD - u16 device_id; - u8 major_revision; - u8 minor_revision; void __iomem *bar0; struct pci_dev *pdev; struct net_device *ndev; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index ea303a2af3aa..b8806a15bcaf 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2012,8 +2012,23 @@ static int vxge_open_vpaths(struct vxgedev *vdev) for (i = 0; i < vdev->no_of_vpath; i++) { vpath = &vdev->vpaths[i]; - vxge_assert(vpath->is_configured); + + if (!vdev->titan1) { + struct vxge_hw_vp_config *vcfg; + vcfg = &vdev->devh->config.vp_config[vpath->device_id]; + + vcfg->rti.urange_a = RTI_T1A_RX_URANGE_A; + vcfg->rti.urange_b = RTI_T1A_RX_URANGE_B; + vcfg->rti.urange_c = RTI_T1A_RX_URANGE_C; + vcfg->tti.uec_a = TTI_T1A_TX_UFC_A; + vcfg->tti.uec_b = TTI_T1A_TX_UFC_B; + vcfg->tti.uec_c = TTI_T1A_TX_UFC_C(vdev->mtu); + vcfg->tti.uec_d = TTI_T1A_TX_UFC_D(vdev->mtu); + vcfg->tti.ltimer_val = VXGE_T1A_TTI_LTIMER_VAL; + vcfg->tti.rtimer_val = VXGE_T1A_TTI_RTIMER_VAL; + } + attr.vp_id = vpath->device_id; attr.fifo_attr.callback = vxge_xmit_compl; attr.fifo_attr.txdl_term = vxge_tx_term; @@ -2710,9 +2725,10 @@ vxge_open(struct net_device *dev) vxge_os_timer(vdev->vp_reset_timer, vxge_poll_vp_reset, vdev, (HZ/2)); - if (vdev->vp_lockup_timer.function == NULL) - vxge_os_timer(vdev->vp_lockup_timer, - vxge_poll_vp_lockup, vdev, (HZ/2)); + /* There is no need to check for RxD leak and RxD lookup on Titan1A */ + if (vdev->titan1 && vdev->vp_lockup_timer.function == NULL) + vxge_os_timer(vdev->vp_lockup_timer, vxge_poll_vp_lockup, vdev, + HZ / 2); set_bit(__VXGE_STATE_CARD_UP, &vdev->state); @@ -2844,7 +2860,9 @@ static int do_vxge_close(struct net_device *dev, int do_io) smp_wmb(); } - del_timer_sync(&vdev->vp_lockup_timer); + + if (vdev->titan1) + del_timer_sync(&vdev->vp_lockup_timer); del_timer_sync(&vdev->vp_reset_timer); @@ -3262,6 +3280,19 @@ static const struct net_device_ops vxge_netdev_ops = { #endif }; +static int __devinit vxge_device_revision(struct vxgedev *vdev) +{ + int ret; + u8 revision; + + ret = pci_read_config_byte(vdev->pdev, PCI_REVISION_ID, &revision); + if (ret) + return -EIO; + + vdev->titan1 = (revision == VXGE_HW_TITAN1_PCI_REVISION); + return 0; +} + static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, struct vxge_config *config, int high_dma, int no_of_vpath, @@ -3302,6 +3333,10 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ vdev->rx_hwts = 0; + ret = vxge_device_revision(vdev); + if (ret < 0) + goto _out1; + SET_NETDEV_DEV(ndev, &vdev->pdev->dev); ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h index 6f6e9ce0bf20..953cb0ded3e1 100644 --- a/drivers/net/vxge/vxge-main.h +++ b/drivers/net/vxge/vxge-main.h @@ -29,6 +29,9 @@ #define PCI_DEVICE_ID_TITAN_WIN 0x5733 #define PCI_DEVICE_ID_TITAN_UNI 0x5833 +#define VXGE_HW_TITAN1_PCI_REVISION 1 +#define VXGE_HW_TITAN1A_PCI_REVISION 2 + #define VXGE_USE_DEFAULT 0xffffffff #define VXGE_HW_VPATH_MSIX_ACTIVE 4 #define VXGE_ALARM_MSIX_ID 2 @@ -53,11 +56,13 @@ #define VXGE_TTI_BTIMER_VAL 250000 -#define VXGE_TTI_LTIMER_VAL 1000 -#define VXGE_TTI_RTIMER_VAL 0 -#define VXGE_RTI_BTIMER_VAL 250 -#define VXGE_RTI_LTIMER_VAL 100 -#define VXGE_RTI_RTIMER_VAL 0 +#define VXGE_TTI_LTIMER_VAL 1000 +#define VXGE_T1A_TTI_LTIMER_VAL 80 +#define VXGE_TTI_RTIMER_VAL 0 +#define VXGE_T1A_TTI_RTIMER_VAL 400 +#define VXGE_RTI_BTIMER_VAL 250 +#define VXGE_RTI_LTIMER_VAL 100 +#define VXGE_RTI_RTIMER_VAL 0 #define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH #define VXGE_ISR_POLLING_CNT 8 #define VXGE_MAX_CONFIG_DEV 0xFF @@ -76,14 +81,32 @@ #define TTI_TX_UFC_B 40 #define TTI_TX_UFC_C 60 #define TTI_TX_UFC_D 100 +#define TTI_T1A_TX_UFC_A 30 +#define TTI_T1A_TX_UFC_B 80 +/* Slope - (max_mtu - min_mtu)/(max_mtu_ufc - min_mtu_ufc) */ +/* Slope - 93 */ +/* 60 - 9k Mtu, 140 - 1.5k mtu */ +#define TTI_T1A_TX_UFC_C(mtu) (60 + ((VXGE_HW_MAX_MTU - mtu) / 93)) + +/* Slope - 37 */ +/* 100 - 9k Mtu, 300 - 1.5k mtu */ +#define TTI_T1A_TX_UFC_D(mtu) (100 + ((VXGE_HW_MAX_MTU - mtu) / 37)) + + +#define RTI_RX_URANGE_A 5 +#define RTI_RX_URANGE_B 15 +#define RTI_RX_URANGE_C 40 +#define RTI_T1A_RX_URANGE_A 1 +#define RTI_T1A_RX_URANGE_B 20 +#define RTI_T1A_RX_URANGE_C 50 +#define RTI_RX_UFC_A 1 +#define RTI_RX_UFC_B 5 +#define RTI_RX_UFC_C 10 +#define RTI_RX_UFC_D 15 +#define RTI_T1A_RX_UFC_B 20 +#define RTI_T1A_RX_UFC_C 50 +#define RTI_T1A_RX_UFC_D 60 -#define RTI_RX_URANGE_A 5 -#define RTI_RX_URANGE_B 15 -#define RTI_RX_URANGE_C 40 -#define RTI_RX_UFC_A 1 -#define RTI_RX_UFC_B 5 -#define RTI_RX_UFC_C 10 -#define RTI_RX_UFC_D 15 /* Milli secs timer period */ #define VXGE_TIMER_DELAY 10000 @@ -329,7 +352,8 @@ struct vxgedev { /* A flag indicating whether rx_csum is to be used or not. */ u32 rx_csum:1, - rx_hwts:1; + rx_hwts:1, + titan1:1; struct vxge_msix_entry *vxge_entries; struct msix_entry *entries; @@ -397,6 +421,7 @@ struct vxge_tx_priv { } while (0); extern void vxge_initialize_ethtool_ops(struct net_device *ndev); + enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override); -- cgit v1.2.3 From ca3e3b8fae982400dacbbf19f3112cc84e51d46a Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:26:01 +0000 Subject: vxge: correct multi-function detection The values used to determined if the adapter is running in single or multi-function mode were previously modified to the values necessary when making the VXGE_HW_FW_API_GET_FUNC_MODE firmware call. However, the firmware call was not modified. This had the driver printing out on probe that the adapter was in multi-function mode when in single function mode and vice versa. Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 6 +++--- drivers/net/vxge/vxge-reg.h | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 5903b2e9a6e9..14dc8c8f47ef 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -1091,16 +1091,16 @@ __vxge_hw_vpath_pci_func_mode_get(struct __vxge_hw_virtualpath *vpath, u64 data0, data1 = 0, steer_ctrl = 0; enum vxge_hw_status status; - data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE; + data0 = 0; status = vxge_hw_vpath_fw_api(vpath, - VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY, + VXGE_HW_FW_API_GET_FUNC_MODE, VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO, 0, &data0, &data1, &steer_ctrl); if (status != VXGE_HW_OK) return status; - hw_info->function_mode = data0; + hw_info->function_mode = VXGE_HW_GET_FUNC_MODE_VAL(data0); return status; } diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h index 0df52dbd42a0..3e658b175947 100644 --- a/drivers/net/vxge/vxge-reg.h +++ b/drivers/net/vxge/vxge-reg.h @@ -62,6 +62,9 @@ #define VXGE_HW_GET_EPROM_IMAGE_REV(val) vxge_bVALn(val, 48, 16) #define VXGE_HW_RTS_ACCESS_STEER_ROM_IMAGE_INDEX(val) vxge_vBIT(val, 16, 8) +#define VXGE_HW_FW_API_GET_FUNC_MODE 29 +#define VXGE_HW_GET_FUNC_MODE_VAL(val) (val & 0xFF) + #define VXGE_HW_FW_UPGRADE_MEMO 13 #define VXGE_HW_FW_UPGRADE_ACTION 16 #define VXGE_HW_FW_UPGRADE_OFFSET_START 2 -- cgit v1.2.3 From 1901d042abf10d08a829961a63fd158f9844587e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:26:02 +0000 Subject: vxge: update Kconfig Update Kconfig to reflect Exar's purchase of Neterion (formerly S2IO). Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/Kconfig | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f6668cdaac85..fa62a63db166 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2772,29 +2772,38 @@ config IXGB will be called ixgb. config S2IO - tristate "S2IO 10Gbe XFrame NIC" + tristate "Exar Xframe 10Gb Ethernet Adapter" depends on PCI ---help--- - This driver supports the 10Gbe XFrame NIC of S2IO. + This driver supports Exar Corp's Xframe Series 10Gb Ethernet Adapters. + More specific information on configuring the driver is in . + To compile this driver as a module, choose M here. The module + will be called s2io. + config VXGE - tristate "Neterion X3100 Series 10GbE PCIe Server Adapter" + tristate "Exar X3100 Series 10GbE PCIe Server Adapter" depends on PCI && INET ---help--- - This driver supports Neterion Inc's X3100 Series 10 GbE PCIe + This driver supports Exar Corp's X3100 Series 10 GbE PCIe I/O Virtualized Server Adapter. + More specific information on configuring the driver is in . + To compile this driver as a module, choose M here. The module + will be called vxge. + config VXGE_DEBUG_TRACE_ALL bool "Enabling All Debug trace statments in driver" default n depends on VXGE ---help--- Say Y here if you want to enabling all the debug trace statements in - driver. By default only few debug trace statements are enabled. + the vxge driver. By default only few debug trace statements are + enabled. config MYRI10GE tristate "Myricom Myri-10G Ethernet support" -- cgit v1.2.3 From 2c91308f449c6705b81bd3370a0ec647e370f35c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:26:03 +0000 Subject: vxge: sparse and other clean-ups Correct issues found by running sparse on the vxge driver, as well as other miscellaneous cleanups. Signed-off-by: Jon Mason Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-config.c | 100 +++++++++------------------------------- drivers/net/vxge/vxge-ethtool.c | 35 ++++++-------- drivers/net/vxge/vxge-main.c | 94 ++++++++++++++++--------------------- 3 files changed, 76 insertions(+), 153 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 14dc8c8f47ef..409c2e6053d0 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -21,19 +21,6 @@ #include "vxge-config.h" #include "vxge-main.h" -static enum vxge_hw_status -__vxge_hw_fifo_create( - struct __vxge_hw_vpath_handle *vpath_handle, - struct vxge_hw_fifo_attr *attr); - -static enum vxge_hw_status -__vxge_hw_fifo_abort( - struct __vxge_hw_fifo *fifoh); - -static enum vxge_hw_status -__vxge_hw_fifo_reset( - struct __vxge_hw_fifo *ringh); - static enum vxge_hw_status __vxge_hw_fifo_delete( struct __vxge_hw_vpath_handle *vpath_handle); @@ -72,44 +59,15 @@ __vxge_hw_blockpool_free(struct __vxge_hw_device *hldev, u32 size, struct vxge_hw_mempool_dma *dma_object); - -static struct __vxge_hw_channel* -__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, - enum __vxge_hw_channel_type type, u32 length, - u32 per_dtr_space, void *userdata); - static void __vxge_hw_channel_free( struct __vxge_hw_channel *channel); -static enum vxge_hw_status -__vxge_hw_channel_initialize( - struct __vxge_hw_channel *channel); - -static enum vxge_hw_status -__vxge_hw_channel_reset( - struct __vxge_hw_channel *channel); - static enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp); -static enum vxge_hw_status -__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config); - static enum vxge_hw_status __vxge_hw_device_config_check(struct vxge_hw_device_config *new_config); -static void -__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev); - -static enum vxge_hw_status -__vxge_hw_device_initialize(struct __vxge_hw_device *hldev); - -static void -__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev); - -static enum vxge_hw_status -__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev); - static enum vxge_hw_status __vxge_hw_device_register_poll( void __iomem *reg, @@ -130,9 +88,10 @@ __vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr, static struct vxge_hw_mempool* __vxge_hw_mempool_create(struct __vxge_hw_device *devh, u32 memblock_size, - u32 item_size, u32 private_size, u32 items_initial, - u32 items_max, struct vxge_hw_mempool_cbs *mp_callback, - void *userdata); + u32 item_size, u32 private_size, u32 items_initial, + u32 items_max, struct vxge_hw_mempool_cbs *mp_callback, + void *userdata); + static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool); static enum vxge_hw_status @@ -145,23 +104,9 @@ vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vpath_handle); static enum vxge_hw_status __vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg); -static enum vxge_hw_status -__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath); - - -static enum vxge_hw_status -__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *devh, u32 vp_id); - -static enum vxge_hw_status -__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *devh, u32 vp_id); - static void __vxge_hw_vp_terminate(struct __vxge_hw_device *devh, u32 vp_id); -static enum vxge_hw_status -__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath, - u32 operation, u32 offset, u64 *stat); - static enum vxge_hw_status __vxge_hw_vpath_xmac_tx_stats_get(struct __vxge_hw_virtualpath *vpath, struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats); @@ -505,7 +450,7 @@ vxge_hw_vpath_eprom_img_ver_get(struct __vxge_hw_device *hldev, * This function allocates required memory for the channel and various arrays * in the channel */ -struct __vxge_hw_channel* +static struct __vxge_hw_channel * __vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, enum __vxge_hw_channel_type type, u32 length, u32 per_dtr_space, void *userdata) @@ -576,7 +521,7 @@ exit0: * This function deallocates memory from the channel and various arrays * in the channel */ -void __vxge_hw_channel_free(struct __vxge_hw_channel *channel) +static void __vxge_hw_channel_free(struct __vxge_hw_channel *channel) { kfree(channel->work_arr); kfree(channel->free_arr); @@ -590,7 +535,7 @@ void __vxge_hw_channel_free(struct __vxge_hw_channel *channel) * This function initializes a channel by properly setting the * various references */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_channel_initialize(struct __vxge_hw_channel *channel) { u32 i; @@ -625,7 +570,7 @@ __vxge_hw_channel_initialize(struct __vxge_hw_channel *channel) * __vxge_hw_channel_reset - Resets a channel * This function resets a channel by properly setting the various references */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_channel_reset(struct __vxge_hw_channel *channel) { u32 i; @@ -652,8 +597,7 @@ __vxge_hw_channel_reset(struct __vxge_hw_channel *channel) * Initialize certain PCI/PCI-X configuration registers * with recommended values. Save config space for future hw resets. */ -void -__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev) +static void __vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev) { u16 cmd = 0; @@ -742,7 +686,7 @@ exit: * register location pointers in the device object. It waits until the ric is * completed initializing registers. */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) { u64 val64; @@ -938,7 +882,8 @@ __vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev) * __vxge_hw_device_initialize * Initialize Titan-V hardware. */ -enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev) +static enum vxge_hw_status +__vxge_hw_device_initialize(struct __vxge_hw_device *hldev) { enum vxge_hw_status status = VXGE_HW_OK; @@ -2337,7 +2282,7 @@ static void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) * __vxge_hw_device_fifo_config_check - Check fifo configuration. * Check the fifo configuration */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config) { if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) || @@ -2385,7 +2330,7 @@ __vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config) * __vxge_hw_device_config_check - Check device configuration. * Check the device configuration */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_device_config_check(struct vxge_hw_device_config *new_config) { u32 i; @@ -2945,7 +2890,7 @@ __vxge_hw_fifo_mempool_item_alloc( * __vxge_hw_fifo_create - Create a FIFO * This function creates FIFO and initializes it. */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp, struct vxge_hw_fifo_attr *attr) { @@ -3109,7 +3054,8 @@ static enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo) * __vxge_hw_fifo_delete - Removes the FIFO * This function freeup the memory pool and removes the FIFO */ -enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp) +static enum vxge_hw_status +__vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp) { struct __vxge_hw_fifo *fifo = vp->vpath->fifoh; @@ -4897,7 +4843,7 @@ static void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr, * __vxge_hw_blockpool_create - Create block pool */ -enum vxge_hw_status +static enum vxge_hw_status __vxge_hw_blockpool_create(struct __vxge_hw_device *hldev, struct __vxge_hw_blockpool *blockpool, u32 pool_size, @@ -4997,7 +4943,7 @@ blockpool_create_exit: * __vxge_hw_blockpool_destroy - Deallocates the block pool */ -void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool) +static void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool) { struct __vxge_hw_device *hldev; @@ -5163,7 +5109,7 @@ exit: * Allocates a block of memory of given size, either from block pool * or by calling vxge_os_dma_malloc() */ -void * +static void * __vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size, struct vxge_hw_mempool_dma *dma_object) { @@ -5227,7 +5173,7 @@ exit: * __vxge_hw_blockpool_free - Frees the memory allcoated with __vxge_hw_blockpool_malloc */ -void +static void __vxge_hw_blockpool_free(struct __vxge_hw_device *devh, void *memblock, u32 size, struct vxge_hw_mempool_dma *dma_object) @@ -5279,7 +5225,7 @@ __vxge_hw_blockpool_free(struct __vxge_hw_device *devh, * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool * This function allocates a block from block pool or from the system */ -struct __vxge_hw_blockpool_entry * +static struct __vxge_hw_blockpool_entry * __vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size) { struct __vxge_hw_blockpool_entry *entry = NULL; @@ -5314,7 +5260,7 @@ __vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size) * * This function frees a block from block pool */ -void +static void __vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh, struct __vxge_hw_blockpool_entry *entry) { diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 3d2cd6acf30a..09f721e10517 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -11,7 +11,7 @@ * Virtualized Server Adapter. * Copyright(c) 2002-2010 Exar Corp. ******************************************************************************/ -#include +#include #include #include #include @@ -29,7 +29,6 @@ * Return value: * 0 on success. */ - static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { /* We currently only support 10Gb/FULL */ @@ -79,10 +78,9 @@ static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) * Returns driver specefic information like name, version etc.. to ethtool. */ static void vxge_ethtool_gdrvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) + struct ethtool_drvinfo *info) { - struct vxgedev *vdev; - vdev = (struct vxgedev *)netdev_priv(dev); + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME)); strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION)); strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN); @@ -104,15 +102,14 @@ static void vxge_ethtool_gdrvinfo(struct net_device *dev, * buffer area. */ static void vxge_ethtool_gregs(struct net_device *dev, - struct ethtool_regs *regs, void *space) + struct ethtool_regs *regs, void *space) { int index, offset; enum vxge_hw_status status; u64 reg; - u64 *reg_space = (u64 *) space; + u64 *reg_space = (u64 *)space; struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) - pci_get_drvdata(vdev->pdev); + struct __vxge_hw_device *hldev = vdev->devh; regs->len = sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; regs->version = vdev->pdev->subsystem_device; @@ -148,8 +145,7 @@ static void vxge_ethtool_gregs(struct net_device *dev, static int vxge_ethtool_idnic(struct net_device *dev, u32 data) { struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) - pci_get_drvdata(vdev->pdev); + struct __vxge_hw_device *hldev = vdev->devh; vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME); @@ -168,11 +164,10 @@ static int vxge_ethtool_idnic(struct net_device *dev, u32 data) * void */ static void vxge_ethtool_getpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) - pci_get_drvdata(vdev->pdev); + struct __vxge_hw_device *hldev = vdev->devh; vxge_hw_device_getpause_data(hldev, 0, &ep->tx_pause, &ep->rx_pause); } @@ -188,11 +183,10 @@ static void vxge_ethtool_getpause_data(struct net_device *dev, * int, returns 0 on Success */ static int vxge_ethtool_setpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) - pci_get_drvdata(vdev->pdev); + struct __vxge_hw_device *hldev = vdev->devh; vxge_hw_device_setpause_data(hldev, 0, ep->tx_pause, ep->rx_pause); @@ -209,9 +203,8 @@ static void vxge_get_ethtool_stats(struct net_device *dev, enum vxge_hw_status status; enum vxge_hw_status swstatus; struct vxge_vpath *vpath = NULL; - struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); - struct __vxge_hw_device *hldev = vdev->devh; + struct __vxge_hw_device *hldev = vdev->devh; struct vxge_hw_xmac_stats *xmac_stats; struct vxge_hw_device_stats_sw_info *sw_stats; struct vxge_hw_device_stats_hw_info *hw_stats; @@ -574,8 +567,8 @@ static void vxge_get_ethtool_stats(struct net_device *dev, kfree(hw_stats); } -static void vxge_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 *data) +static void vxge_ethtool_get_strings(struct net_device *dev, u32 stringset, + u8 *data) { int stat_size = 0; int i, j; diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index b8806a15bcaf..3f2d6ed13d3e 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -688,7 +688,7 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) struct vxge_vpath *vpath = NULL; struct __vxge_hw_device *hldev; - hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); mac_address = (u8 *)&mac_addr; memcpy(mac_address, mac_header, ETH_ALEN); @@ -1112,7 +1112,7 @@ static void vxge_set_multicast(struct net_device *dev) /* Delete previous MC's */ for (i = 0; i < mcast_cnt; i++) { list_for_each_safe(entry, next, list_head) { - mac_entry = (struct vxge_mac_addrs *) entry; + mac_entry = (struct vxge_mac_addrs *)entry; /* Copy the mac address to delete */ mac_address = (u8 *)&mac_entry->macaddr; memcpy(mac_info.macaddr, mac_address, ETH_ALEN); @@ -1155,7 +1155,7 @@ _set_all_mcast: /* Delete previous MC's */ for (i = 0; i < mcast_cnt; i++) { list_for_each_safe(entry, next, list_head) { - mac_entry = (struct vxge_mac_addrs *) entry; + mac_entry = (struct vxge_mac_addrs *)entry; /* Copy the mac address to delete */ mac_address = (u8 *)&mac_entry->macaddr; memcpy(mac_info.macaddr, mac_address, ETH_ALEN); @@ -1202,7 +1202,7 @@ static int vxge_set_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; struct vxgedev *vdev; - struct __vxge_hw_device *hldev; + struct __vxge_hw_device *hldev; enum vxge_hw_status status = VXGE_HW_OK; struct macInfo mac_info_new, mac_info_old; int vpath_idx = 0; @@ -1632,7 +1632,7 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget) int budget_org = budget; struct vxge_ring *ring; - struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); for (i = 0; i < vdev->no_of_vpath; i++) { @@ -1669,7 +1669,7 @@ static int vxge_poll_inta(struct napi_struct *napi, int budget) */ static void vxge_netpoll(struct net_device *dev) { - struct __vxge_hw_device *hldev; + struct __vxge_hw_device *hldev; struct vxgedev *vdev; vdev = (struct vxgedev *)netdev_priv(dev); @@ -1821,7 +1821,7 @@ static int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac) { struct list_head *entry, *next; u64 del_mac = 0; - u8 *mac_address = (u8 *) (&del_mac); + u8 *mac_address = (u8 *)(&del_mac); /* Copy the mac address to delete from the list */ memcpy(mac_address, mac->macaddr, ETH_ALEN); @@ -2102,7 +2102,7 @@ static irqreturn_t vxge_isr_napi(int irq, void *dev_id) struct __vxge_hw_device *hldev; u64 reason; enum vxge_hw_status status; - struct vxgedev *vdev = (struct vxgedev *) dev_id;; + struct vxgedev *vdev = (struct vxgedev *)dev_id; vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); @@ -2341,8 +2341,8 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev) static void vxge_rem_isr(struct vxgedev *vdev) { - struct __vxge_hw_device *hldev; - hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + struct __vxge_hw_device *hldev; + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); #ifdef CONFIG_PCI_MSI if (vdev->config.intr_type == MSI_X) { @@ -2583,7 +2583,7 @@ vxge_open(struct net_device *dev) "%s: %s:%d", dev->name, __func__, __LINE__); vdev = (struct vxgedev *)netdev_priv(dev); - hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); function_mode = vdev->config.device_hw_info.function_mode; /* make sure you have link off by default every time Nic is @@ -2811,7 +2811,7 @@ static int do_vxge_close(struct net_device *dev, int do_io) dev->name, __func__, __LINE__); vdev = (struct vxgedev *)netdev_priv(dev); - hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (unlikely(!is_vxge_card_up(vdev))) return 0; @@ -3440,36 +3440,29 @@ _out0: * * This function will unregister and free network device */ -static void -vxge_device_unregister(struct __vxge_hw_device *hldev) +static void vxge_device_unregister(struct __vxge_hw_device *hldev) { struct vxgedev *vdev; struct net_device *dev; char buf[IFNAMSIZ]; -#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ - (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) - u32 level_trace; -#endif dev = hldev->ndev; vdev = netdev_priv(dev); -#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ - (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) - level_trace = vdev->level_trace; -#endif - vxge_debug_entryexit(level_trace, - "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); - memcpy(buf, vdev->ndev->name, IFNAMSIZ); + vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d", vdev->ndev->name, + __func__, __LINE__); + + memcpy(buf, dev->name, IFNAMSIZ); /* in 2.6 will call stop() if device is up */ unregister_netdev(dev); flush_scheduled_work(); - vxge_debug_init(level_trace, "%s: ethernet device unregistered", buf); - vxge_debug_entryexit(level_trace, - "%s: %s:%d Exiting...", buf, __func__, __LINE__); + vxge_debug_init(vdev->level_trace, "%s: ethernet device unregistered", + buf); + vxge_debug_entryexit(vdev->level_trace, "%s: %s:%d Exiting...", buf, + __func__, __LINE__); } /* @@ -3992,8 +3985,8 @@ static int vxge_pm_resume(struct pci_dev *pdev) static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *)pci_get_drvdata(pdev); struct net_device *netdev = hldev->ndev; netif_device_detach(netdev); @@ -4022,8 +4015,8 @@ static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, */ static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev) { - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *)pci_get_drvdata(pdev); struct net_device *netdev = hldev->ndev; struct vxgedev *vdev = netdev_priv(netdev); @@ -4048,8 +4041,8 @@ static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev) */ static void vxge_io_resume(struct pci_dev *pdev) { - struct __vxge_hw_device *hldev = - (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *)pci_get_drvdata(pdev); struct net_device *netdev = hldev->ndev; if (netif_running(netdev)) { @@ -4243,7 +4236,7 @@ static int vxge_probe_fw_update(struct vxgedev *vdev) static int __devinit vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) { - struct __vxge_hw_device *hldev; + struct __vxge_hw_device *hldev; enum vxge_hw_status status; int ret; int high_dma = 0; @@ -4689,34 +4682,25 @@ _exit0: * Description: This function is called by the Pci subsystem to release a * PCI device and free up all resource held up by the device. */ -static void __devexit -vxge_remove(struct pci_dev *pdev) +static void __devexit vxge_remove(struct pci_dev *pdev) { - struct __vxge_hw_device *hldev; + struct __vxge_hw_device *hldev; struct vxgedev *vdev = NULL; struct net_device *dev; int i = 0; -#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ - (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) - u32 level_trace; -#endif - hldev = (struct __vxge_hw_device *) pci_get_drvdata(pdev); + hldev = (struct __vxge_hw_device *)pci_get_drvdata(pdev); if (hldev == NULL) return; + dev = hldev->ndev; vdev = netdev_priv(dev); -#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ - (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) - level_trace = vdev->level_trace; -#endif - vxge_debug_entryexit(level_trace, - "%s:%d", __func__, __LINE__); + vxge_debug_entryexit(vdev->level_trace, "%s:%d", __func__, __LINE__); - vxge_debug_init(level_trace, - "%s : removing PCI device...", __func__); + vxge_debug_init(vdev->level_trace, "%s : removing PCI device...", + __func__); vxge_device_unregister(hldev); for (i = 0; i < vdev->no_of_vpath; i++) { @@ -4734,16 +4718,16 @@ vxge_remove(struct pci_dev *pdev) /* we are safe to free it now */ free_netdev(dev); - vxge_debug_init(level_trace, - "%s:%d Device unregistered", __func__, __LINE__); + vxge_debug_init(vdev->level_trace, "%s:%d Device unregistered", + __func__, __LINE__); vxge_hw_device_terminate(hldev); pci_disable_device(pdev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); - vxge_debug_entryexit(level_trace, - "%s:%d Exiting...", __func__, __LINE__); + vxge_debug_entryexit(vdev->level_trace, "%s:%d Exiting...", __func__, + __LINE__); } static struct pci_error_handlers vxge_err_handler = { -- cgit v1.2.3 From c0c04c2a89cf6363da2940da59afd2e30001b991 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 11 Nov 2010 04:26:04 +0000 Subject: vxge: update driver version Update vxge driver version Signed-off-by: Jon Mason Signed-off-by: Ram Vepa Signed-off-by: David S. Miller --- drivers/net/vxge/vxge-version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h index b4eced19e45d..f05bb2f55e73 100644 --- a/drivers/net/vxge/vxge-version.h +++ b/drivers/net/vxge/vxge-version.h @@ -16,8 +16,8 @@ #define VXGE_VERSION_MAJOR "2" #define VXGE_VERSION_MINOR "0" -#define VXGE_VERSION_FIX "9" -#define VXGE_VERSION_BUILD "20840" +#define VXGE_VERSION_FIX "10" +#define VXGE_VERSION_BUILD "21808" #define VXGE_VERSION_FOR "k" #define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld)) -- cgit v1.2.3 From 72cdd1d971c0deb1619c5c339270570c43647a78 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 11 Nov 2010 07:14:07 +0000 Subject: net: get rid of rtable->idev It seems idev field in struct rtable has no special purpose, but adding extra atomic ops. We hold refcounts on the device itself (using percpu data, so pretty cheap in current kernel). infiniband case is solved using dst.dev instead of idev->dev Removal of this field means routing without route cache is now using shared data, percpu data, and only potential contention is a pair of atomic ops on struct neighbour per forwarded packet. About 5% speedup on routing test. Signed-off-by: Eric Dumazet Cc: Herbert Xu Cc: Roland Dreier Cc: Sean Hefty Cc: Hal Rosenstock Signed-off-by: David S. Miller --- drivers/infiniband/core/addr.c | 8 ++++---- include/net/route.h | 2 -- net/ipv4/route.c | 37 ++++--------------------------------- net/ipv4/xfrm4_policy.c | 24 ------------------------ 4 files changed, 8 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index a5ea1bce9689..c15fd2ea56c1 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -200,7 +200,7 @@ static int addr4_resolve(struct sockaddr_in *src_in, src_in->sin_family = AF_INET; src_in->sin_addr.s_addr = rt->rt_src; - if (rt->idev->dev->flags & IFF_LOOPBACK) { + if (rt->dst.dev->flags & IFF_LOOPBACK) { ret = rdma_translate_ip((struct sockaddr *) dst_in, addr); if (!ret) memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN); @@ -208,12 +208,12 @@ static int addr4_resolve(struct sockaddr_in *src_in, } /* If the device does ARP internally, return 'done' */ - if (rt->idev->dev->flags & IFF_NOARP) { - rdma_copy_addr(addr, rt->idev->dev, NULL); + if (rt->dst.dev->flags & IFF_NOARP) { + rdma_copy_addr(addr, rt->dst.dev, NULL); goto put; } - neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->idev->dev); + neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev); if (!neigh || !(neigh->nud_state & NUD_VALID)) { neigh_event_send(rt->dst.neighbour, NULL); ret = -ENODATA; diff --git a/include/net/route.h b/include/net/route.h index 7e5e73bfa4de..cea533eaa853 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -55,8 +55,6 @@ struct rtable { /* Cache lookup keys */ struct flowi fl; - struct in_device *idev; - int rt_genid; unsigned rt_flags; __u16 rt_type; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 987bf9adb318..5955965c7953 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -140,13 +140,15 @@ static unsigned long expires_ljiffies; static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); static void ipv4_dst_destroy(struct dst_entry *dst); -static void ipv4_dst_ifdown(struct dst_entry *dst, - struct net_device *dev, int how); static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); static int rt_garbage_collect(struct dst_ops *ops); +static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, + int how) +{ +} static struct dst_ops ipv4_dst_ops = { .family = AF_INET, @@ -1433,8 +1435,6 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rt->dst.child = NULL; if (rt->dst.dev) dev_hold(rt->dst.dev); - if (rt->idev) - in_dev_hold(rt->idev); rt->dst.obsolete = -1; rt->dst.lastuse = jiffies; rt->dst.path = &rt->dst; @@ -1728,33 +1728,13 @@ static void ipv4_dst_destroy(struct dst_entry *dst) { struct rtable *rt = (struct rtable *) dst; struct inet_peer *peer = rt->peer; - struct in_device *idev = rt->idev; if (peer) { rt->peer = NULL; inet_putpeer(peer); } - - if (idev) { - rt->idev = NULL; - in_dev_put(idev); - } } -static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, - int how) -{ - struct rtable *rt = (struct rtable *) dst; - struct in_device *idev = rt->idev; - if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) { - struct in_device *loopback_idev = - in_dev_get(dev_net(dev)->loopback_dev); - if (loopback_idev) { - rt->idev = loopback_idev; - in_dev_put(idev); - } - } -} static void ipv4_link_failure(struct sk_buff *skb) { @@ -1910,7 +1890,6 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.iif = dev->ifindex; rth->dst.dev = init_net.loopback_dev; dev_hold(rth->dst.dev); - rth->idev = in_dev_get(rth->dst.dev); rth->fl.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; @@ -2050,7 +2029,6 @@ static int __mkroute_input(struct sk_buff *skb, rth->fl.iif = in_dev->dev->ifindex; rth->dst.dev = (out_dev)->dev; dev_hold(rth->dst.dev); - rth->idev = in_dev_get(rth->dst.dev); rth->fl.oif = 0; rth->rt_spec_dst= spec_dst; @@ -2231,7 +2209,6 @@ local_input: rth->fl.iif = dev->ifindex; rth->dst.dev = net->loopback_dev; dev_hold(rth->dst.dev); - rth->idev = in_dev_get(rth->dst.dev); rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->dst.input= ip_local_deliver; @@ -2417,9 +2394,6 @@ static int __mkroute_output(struct rtable **result, if (!rth) return -ENOBUFS; - in_dev_hold(in_dev); - rth->idev = in_dev; - atomic_set(&rth->dst.__refcnt, 1); rth->dst.flags= DST_HOST; if (IN_DEV_CONF_GET(in_dev, NOXFRM)) @@ -2759,9 +2733,6 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi rt->fl = ort->fl; - rt->idev = ort->idev; - if (rt->idev) - in_dev_hold(rt->idev); rt->rt_genid = rt_genid(net); rt->rt_flags = ort->rt_flags; rt->rt_type = ort->rt_type; diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 4464f3bff6a7..dd1fd8c473fc 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -80,10 +80,6 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, xdst->u.dst.dev = dev; dev_hold(dev); - xdst->u.rt.idev = in_dev_get(dev); - if (!xdst->u.rt.idev) - return -ENODEV; - xdst->u.rt.peer = rt->peer; if (rt->peer) atomic_inc(&rt->peer->refcnt); @@ -189,8 +185,6 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) { struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - if (likely(xdst->u.rt.idev)) - in_dev_put(xdst->u.rt.idev); if (likely(xdst->u.rt.peer)) inet_putpeer(xdst->u.rt.peer); xfrm_dst_destroy(xdst); @@ -199,27 +193,9 @@ static void xfrm4_dst_destroy(struct dst_entry *dst) static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, int unregister) { - struct xfrm_dst *xdst; - if (!unregister) return; - xdst = (struct xfrm_dst *)dst; - if (xdst->u.rt.idev->dev == dev) { - struct in_device *loopback_idev = - in_dev_get(dev_net(dev)->loopback_dev); - BUG_ON(!loopback_idev); - - do { - in_dev_put(xdst->u.rt.idev); - xdst->u.rt.idev = loopback_idev; - in_dev_hold(loopback_idev); - xdst = (struct xfrm_dst *)xdst->u.dst.child; - } while (xdst->u.dst.xfrm); - - __in_dev_put(loopback_idev); - } - xfrm_dst_ifdown(dst, dev); } -- cgit v1.2.3 From e85eb11782259dc39502807f3ec903a7b82b1bab Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Thu, 11 Nov 2010 12:31:21 +0000 Subject: net: Kconfig whitespace cleanup Many lines in Kconfig start withe 8 spaces instead of a TAB, and even sometimes with 7 spaces. Replace 10 or 9 spaces, or TAB + 1 space, by TAB + 2 spaces, and 8 or 7 spaces by TAB. Signed-off-by: Philippe De Muyter Signed-off-by: David S. Miller --- drivers/net/Kconfig | 224 ++++++++++++++++++++++++++-------------------------- 1 file changed, 112 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index fa62a63db166..0a7e6cea0082 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1533,7 +1533,7 @@ config E100 - to identify the adapter. + to identify the adapter. For the latest Intel PRO/100 network driver for Linux, see: @@ -1786,17 +1786,17 @@ config KS8842 tristate "Micrel KSZ8841/42 with generic bus interface" depends on HAS_IOMEM && DMA_ENGINE help - This platform driver is for KSZ8841(1-port) / KS8842(2-port) - ethernet switch chip (managed, VLAN, QoS) from Micrel or - Timberdale(FPGA). + This platform driver is for KSZ8841(1-port) / KS8842(2-port) + ethernet switch chip (managed, VLAN, QoS) from Micrel or + Timberdale(FPGA). config KS8851 - tristate "Micrel KS8851 SPI" - depends on SPI - select MII + tristate "Micrel KS8851 SPI" + depends on SPI + select MII select CRC32 - help - SPI driver for Micrel KS8851 SPI attached network chip. + help + SPI driver for Micrel KS8851 SPI attached network chip. config KS8851_MLL tristate "Micrel KS8851 MLL" @@ -2133,25 +2133,25 @@ config IP1000 will be called ipg. This is recommended. config IGB - tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" - depends on PCI - ---help--- - This driver supports Intel(R) 82575/82576 gigabit ethernet family of - adapters. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide at: + tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports Intel(R) 82575/82576 gigabit ethernet family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: - + - For general information and support, go to the Intel support - website at: + For general information and support, go to the Intel support + website at: - + - More specific information on configuring the driver is in - . + More specific information on configuring the driver is in + . - To compile this driver as a module, choose M here. The module - will be called igb. + To compile this driver as a module, choose M here. The module + will be called igb. config IGB_DCA bool "Direct Cache Access (DCA) Support" @@ -2163,25 +2163,25 @@ config IGB_DCA is used, with the intent of lessening the impact of cache misses. config IGBVF - tristate "Intel(R) 82576 Virtual Function Ethernet support" - depends on PCI - ---help--- - This driver supports Intel(R) 82576 virtual functions. For more - information on how to identify your adapter, go to the Adapter & - Driver ID Guide at: + tristate "Intel(R) 82576 Virtual Function Ethernet support" + depends on PCI + ---help--- + This driver supports Intel(R) 82576 virtual functions. For more + information on how to identify your adapter, go to the Adapter & + Driver ID Guide at: - + - For general information and support, go to the Intel support - website at: + For general information and support, go to the Intel support + website at: - + - More specific information on configuring the driver is in - . + More specific information on configuring the driver is in + . - To compile this driver as a module, choose M here. The module - will be called igbvf. + To compile this driver as a module, choose M here. The module + will be called igbvf. source "drivers/net/ixp2000/Kconfig" @@ -2300,14 +2300,14 @@ config SKGE will be called skge. This is recommended. config SKGE_DEBUG - bool "Debugging interface" - depends on SKGE && DEBUG_FS - help - This option adds the ability to dump driver state for debugging. - The file /sys/kernel/debug/skge/ethX displays the state of the internal - transmit and receive rings. + bool "Debugging interface" + depends on SKGE && DEBUG_FS + help + This option adds the ability to dump driver state for debugging. + The file /sys/kernel/debug/skge/ethX displays the state of the internal + transmit and receive rings. - If unsure, say N. + If unsure, say N. config SKY2 tristate "SysKonnect Yukon2 support" @@ -2326,14 +2326,14 @@ config SKY2 will be called sky2. This is recommended. config SKY2_DEBUG - bool "Debugging interface" - depends on SKY2 && DEBUG_FS - help - This option adds the ability to dump driver state for debugging. - The file /sys/kernel/debug/sky2/ethX displays the state of the internal - transmit and receive rings. + bool "Debugging interface" + depends on SKY2 && DEBUG_FS + help + This option adds the ability to dump driver state for debugging. + The file /sys/kernel/debug/sky2/ethX displays the state of the internal + transmit and receive rings. - If unsure, say N. + If unsure, say N. config VIA_VELOCITY tristate "VIA Velocity support" @@ -2573,32 +2573,32 @@ config MDIO tristate config CHELSIO_T1 - tristate "Chelsio 10Gb Ethernet support" - depends on PCI + tristate "Chelsio 10Gb Ethernet support" + depends on PCI select CRC32 select MDIO - help - This driver supports Chelsio gigabit and 10-gigabit - Ethernet cards. More information about adapter features and + help + This driver supports Chelsio gigabit and 10-gigabit + Ethernet cards. More information about adapter features and performance tuning is in . - For general information about Chelsio and our products, visit - our website at . + For general information about Chelsio and our products, visit + our website at . - For customer support, please visit our customer support page at - . + For customer support, please visit our customer support page at + . - Please send feedback to . + Please send feedback to . - To compile this driver as a module, choose M here: the module - will be called cxgb. + To compile this driver as a module, choose M here: the module + will be called cxgb. config CHELSIO_T1_1G - bool "Chelsio gigabit Ethernet support" - depends on CHELSIO_T1 - help - Enables support for Chelsio's gigabit Ethernet PCI cards. If you - are using only 10G cards say 'N' here. + bool "Chelsio gigabit Ethernet support" + depends on CHELSIO_T1 + help + Enables support for Chelsio's gigabit Ethernet PCI cards. If you + are using only 10G cards say 'N' here. config CHELSIO_T3_DEPENDS tristate @@ -2728,26 +2728,26 @@ config IXGBE_DCB If unsure, say N. config IXGBEVF - tristate "Intel(R) 82599 Virtual Function Ethernet support" - depends on PCI_MSI - ---help--- - This driver supports Intel(R) 82599 virtual functions. For more - information on how to identify your adapter, go to the Adapter & - Driver ID Guide at: + tristate "Intel(R) 82599 Virtual Function Ethernet support" + depends on PCI_MSI + ---help--- + This driver supports Intel(R) 82599 virtual functions. For more + information on how to identify your adapter, go to the Adapter & + Driver ID Guide at: - + - For general information and support, go to the Intel support - website at: + For general information and support, go to the Intel support + website at: - + - More specific information on configuring the driver is in - . + More specific information on configuring the driver is in + . - To compile this driver as a module, choose M here. The module - will be called ixgbevf. MSI-X interrupt support is required - for this driver to work correctly. + To compile this driver as a module, choose M here. The module + will be called ixgbevf. MSI-X interrupt support is required + for this driver to work correctly. config IXGB tristate "Intel(R) PRO/10GbE support" @@ -2915,18 +2915,18 @@ config QLGE will be called qlge. config BNA - tristate "Brocade 1010/1020 10Gb Ethernet Driver support" - depends on PCI - ---help--- - This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet - cards. - To compile this driver as a module, choose M here: the module - will be called bna. + tristate "Brocade 1010/1020 10Gb Ethernet Driver support" + depends on PCI + ---help--- + This driver supports Brocade 1010/1020 10Gb CEE capable Ethernet + cards. + To compile this driver as a module, choose M here: the module + will be called bna. - For general information and support, go to the Brocade support - website at: + For general information and support, go to the Brocade support + website at: - + source "drivers/net/sfc/Kconfig" @@ -3236,18 +3236,18 @@ config PPP_BSDCOMP modules once you have said "make modules". If unsure, say N. config PPP_MPPE - tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" - depends on PPP && EXPERIMENTAL - select CRYPTO - select CRYPTO_SHA1 - select CRYPTO_ARC4 - select CRYPTO_ECB - ---help--- - Support for the MPPE Encryption protocol, as employed by the - Microsoft Point-to-Point Tunneling Protocol. - - See http://pptpclient.sourceforge.net/ for information on - configuring PPTP clients and servers to utilize this method. + tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)" + depends on PPP && EXPERIMENTAL + select CRYPTO + select CRYPTO_SHA1 + select CRYPTO_ARC4 + select CRYPTO_ECB + ---help--- + Support for the MPPE Encryption protocol, as employed by the + Microsoft Point-to-Point Tunneling Protocol. + + See http://pptpclient.sourceforge.net/ for information on + configuring PPTP clients and servers to utilize this method. config PPPOE tristate "PPP over Ethernet (EXPERIMENTAL)" @@ -3406,14 +3406,14 @@ config VIRTIO_NET depends on EXPERIMENTAL && VIRTIO ---help--- This is the virtual network driver for virtio. It can be used with - lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. + lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. config VMXNET3 - tristate "VMware VMXNET3 ethernet driver" - depends on PCI && INET - help - This driver supports VMware's vmxnet3 virtual ethernet NIC. - To compile this driver as a module, choose M here: the - module will be called vmxnet3. + tristate "VMware VMXNET3 ethernet driver" + depends on PCI && INET + help + This driver supports VMware's vmxnet3 virtual ethernet NIC. + To compile this driver as a module, choose M here: the + module will be called vmxnet3. endif # NETDEVICES -- cgit v1.2.3 From 9fbbdde93231ad7f35c217aa6bbbc7995133f483 Mon Sep 17 00:00:00 2001 From: Erik Gilling Date: Thu, 11 Nov 2010 15:44:43 +0100 Subject: video: add fb_edid_add_monspecs for parsing extended edid information Modern monitors/tvs have more extended EDID information blocks which can contain extra detailed modes. This adds a fb_edid_add_monspecs function which drivers can use to parse those additions blocks. Signed-off-by: Erik Gilling Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/fbmon.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fb.h | 2 ++ 2 files changed, 59 insertions(+) (limited to 'drivers') diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 563a98b88e9b..a0b5a93b72d2 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -973,6 +973,63 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK("========================================\n"); } +void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + unsigned char *block; + struct fb_videomode *mode, *m; + int num = 0, i, first = 1; + + if (edid == NULL) + return; + + if (!edid_checksum(edid)) + return; + + if (edid[0] != 0x2) + return; + + mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); + if (mode == NULL) + return; + + block = edid + edid[0x2]; + + DPRINTK(" Extended Detailed Timings\n"); + + for (i = 0; i < (128 - edid[0x2]) / DETAILED_TIMING_DESCRIPTION_SIZE; + i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (!(block[0] == 0x00 && block[1] == 0x00)) { + get_detailed_timing(block, &mode[num]); + if (first) { + mode[num].flag |= FB_MODE_IS_FIRST; + first = 0; + } + num++; + } + } + + /* Yikes, EDID data is totally useless */ + if (!num) { + kfree(mode); + return; + } + + m = kzalloc((specs->modedb_len + num) * + sizeof(struct fb_videomode), GFP_KERNEL); + + if (!m) { + kfree(mode); + return; + } + + memmove(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); + memmove(m + specs->modedb_len, mode, num * sizeof(struct fb_videomode)); + kfree(mode); + kfree(specs->modedb); + specs->modedb = m; + specs->modedb_len = specs->modedb_len + num; +} + /* * VESA Generalized Timing Formula (GTF) */ diff --git a/include/linux/fb.h b/include/linux/fb.h index 7fca3dc4e475..6f0274d96f0c 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -1092,6 +1092,8 @@ extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); extern const unsigned char *fb_firmware_edid(struct device *device); extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); +extern void fb_edid_add_monspecs(unsigned char *edid, + struct fb_monspecs *specs); extern void fb_destroy_modedb(struct fb_videomode *modedb); extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb); extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter); -- cgit v1.2.3 From e4105119aca9b86b163fa07428df1f615034a03d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Nov 2010 15:44:52 +0100 Subject: fbdev: export fb_edid_add_monspecs() for modules, improve algorithm fb_edid_add_monspecs() should also be exported for use in modules, and it requires a dummy version for the case, when CONFIG_FB_MODE_HELPERS is not selected. This patch also improves the algorithm by removing a redundant memory allocation, adds function documentation, adds data verification and replaces memmove() with memcpy(). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/fbmon.c | 58 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index a0b5a93b72d2..b25399abcf49 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -973,58 +973,56 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK("========================================\n"); } +/** + * fb_edid_add_monspecs() - add monitor video modes from E-EDID data + * @edid: 128 byte array with an E-EDID block + * @spacs: monitor specs to be extended + */ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) { unsigned char *block; - struct fb_videomode *mode, *m; - int num = 0, i, first = 1; + struct fb_videomode *m; + int num = 0, i; + u8 edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; - if (edid == NULL) + if (!edid) return; if (!edid_checksum(edid)) return; - if (edid[0] != 0x2) + if (edid[0] != 0x2 || + edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) return; - mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL); - if (mode == NULL) - return; - - block = edid + edid[0x2]; + block = edid + edid[2]; DPRINTK(" Extended Detailed Timings\n"); - for (i = 0; i < (128 - edid[0x2]) / DETAILED_TIMING_DESCRIPTION_SIZE; - i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { - if (!(block[0] == 0x00 && block[1] == 0x00)) { - get_detailed_timing(block, &mode[num]); - if (first) { - mode[num].flag |= FB_MODE_IS_FIRST; - first = 0; - } - num++; - } - } + for (i = 0; i < (128 - edid[2]) / DETAILED_TIMING_DESCRIPTION_SIZE; + i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) + if (PIXEL_CLOCK) + edt[num++] = block - edid; /* Yikes, EDID data is totally useless */ - if (!num) { - kfree(mode); + if (!num) return; - } m = kzalloc((specs->modedb_len + num) * sizeof(struct fb_videomode), GFP_KERNEL); - if (!m) { - kfree(mode); + if (!m) return; + + memcpy(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); + + for (i = specs->modedb_len; i < specs->modedb_len + num; i++) { + get_detailed_timing(edid + edt[i - specs->modedb_len], &m[i]); + if (i == specs->modedb_len) + m[i].flag |= FB_MODE_IS_FIRST; + pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); } - memmove(m, specs->modedb, specs->modedb_len * sizeof(struct fb_videomode)); - memmove(m + specs->modedb_len, mode, num * sizeof(struct fb_videomode)); - kfree(mode); kfree(specs->modedb); specs->modedb = m; specs->modedb_len = specs->modedb_len + num; @@ -1346,6 +1344,9 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { specs = NULL; } +void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ +} void fb_destroy_modedb(struct fb_videomode *modedb) { } @@ -1453,6 +1454,7 @@ EXPORT_SYMBOL(fb_firmware_edid); EXPORT_SYMBOL(fb_parse_edid); EXPORT_SYMBOL(fb_edid_to_monspecs); +EXPORT_SYMBOL(fb_edid_add_monspecs); EXPORT_SYMBOL(fb_get_mode); EXPORT_SYMBOL(fb_validate_mode); EXPORT_SYMBOL(fb_destroy_modedb); -- cgit v1.2.3 From 0ad83f6882c41df1a7fa387086029e162038c1f2 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Nov 2010 15:45:04 +0100 Subject: fbdev: when parsing E-EDID blocks, also use SVD entries Add parsing of E-EDID SVD entries. In this first version only a few CEA/EIA-861E modes are implemented, more can be added as needed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/fbmon.c | 37 +++++++++++++++++++++++++++++++++---- drivers/video/modedb.c | 43 +++++++++++++++++++++++++++++++++++++++++++ include/linux/fb.h | 1 + 3 files changed, 77 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index b25399abcf49..4f57485f8c54 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -983,7 +983,8 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) unsigned char *block; struct fb_videomode *m; int num = 0, i; - u8 edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; + u8 svd[64], edt[(128 - 4) / DETAILED_TIMING_DESCRIPTION_SIZE]; + u8 pos = 4, svd_n = 0; if (!edid) return; @@ -995,6 +996,21 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE) return; + DPRINTK(" Short Video Descriptors\n"); + + while (pos < edid[2]) { + u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7; + pr_debug("Data block %u of %u bytes\n", type, len); + if (type == 2) + for (i = pos; i < pos + len; i++) { + u8 idx = edid[pos + i] & 0x7f; + svd[svd_n++] = idx; + pr_debug("N%sative mode #%d\n", + edid[pos + i] & 0x80 ? "" : "on-n", idx); + } + pos += len + 1; + } + block = edid + edid[2]; DPRINTK(" Extended Detailed Timings\n"); @@ -1005,10 +1021,10 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) edt[num++] = block - edid; /* Yikes, EDID data is totally useless */ - if (!num) + if (!(num + svd_n)) return; - m = kzalloc((specs->modedb_len + num) * + m = kzalloc((specs->modedb_len + num + svd_n) * sizeof(struct fb_videomode), GFP_KERNEL); if (!m) @@ -1023,9 +1039,22 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs) pr_debug("Adding %ux%u@%u\n", m[i].xres, m[i].yres, m[i].refresh); } + for (i = specs->modedb_len + num; i < specs->modedb_len + num + svd_n; i++) { + int idx = svd[i - specs->modedb_len - num]; + if (!idx || idx > 63) { + pr_warning("Reserved SVD code %d\n", idx); + } else if (idx > ARRAY_SIZE(cea_modes) || !cea_modes[idx].xres) { + pr_warning("Unimplemented SVD code %d\n", idx); + } else { + memcpy(&m[i], cea_modes + idx, sizeof(m[i])); + pr_debug("Adding SVD #%d: %ux%u@%u\n", idx, + m[i].xres, m[i].yres, m[i].refresh); + } + } + kfree(specs->modedb); specs->modedb = m; - specs->modedb_len = specs->modedb_len + num; + specs->modedb_len = specs->modedb_len + num + svd_n; } /* diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c index 0a4dbdc1693a..9a0ae6ca5427 100644 --- a/drivers/video/modedb.c +++ b/drivers/video/modedb.c @@ -278,6 +278,49 @@ static const struct fb_videomode modedb[] = { }; #ifdef CONFIG_FB_MODE_HELPERS +const struct fb_videomode cea_modes[64] = { + /* #1: 640x480p@59.94/60Hz */ + [1] = { + NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #3: 720x480p@59.94/60Hz */ + [3] = { + NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #5: 1920x1080i@59.94/60Hz */ + [5] = { + NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5, 0, FB_VMODE_INTERLACED, 0, + }, + /* #7: 720(1440)x480iH@59.94/60Hz */ + [7] = { + NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0, FB_VMODE_INTERLACED, 0, + }, + /* #9: 720(1440)x240pH@59.94/60Hz */ + [9] = { + NULL, 60, 1440, 240, 18554, 114, 38, 16, 4, 124, 3, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #18: 720x576pH@50Hz */ + [18] = { + NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #19: 1280x720p@50Hz */ + [19] = { + NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #20: 1920x1080i@50Hz */ + [20] = { + NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5, 0, FB_VMODE_INTERLACED, 0, + }, + /* #32: 1920x1080p@23.98/24Hz */ + [32] = { + NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5, 0, FB_VMODE_NONINTERLACED, 0, + }, + /* #35: (2880)x480p4x@59.94/60Hz */ + [35] = { + NULL, 50, 2880, 480, 11100, 240, 64, 30, 9, 248, 6, 0, FB_VMODE_NONINTERLACED, 0, + }, +}; + const struct fb_videomode vesa_modes[] = { /* 0 640x350-85 VESA */ { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, diff --git a/include/linux/fb.h b/include/linux/fb.h index 6f0274d96f0c..e154a79b8322 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -1151,6 +1151,7 @@ struct fb_videomode { extern const char *fb_mode_option; extern const struct fb_videomode vesa_modes[]; +extern const struct fb_videomode cea_modes[64]; struct fb_modelist { struct list_head list; -- cgit v1.2.3 From 4232f60791d12a5156c3e1c9b04ae08b873a2920 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 11 Nov 2010 14:45:09 +0000 Subject: fbdev: sh_mobile_hdmi: add support for E-EDID parsing Many HDMI clients implement enhanced EDID blocks, which often contain additional supported video modes. This patch implements parsing of such E-EDID blocks. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 60 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 3b4cf987fb43..76f9fac9020f 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -211,6 +211,9 @@ struct sh_hdmi { enum hotplug_state hp_state; /* hot-plug status */ u8 preprogrammed_vic; /* use a pre-programmed VIC or the external mode */ + u8 edid_block_addr; + u8 edid_segment_nr; + u8 edid_blocks; struct clk *hdmi_clk; struct device *dev; struct fb_info *info; @@ -756,7 +759,38 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, printk(KERN_CONT "\n"); #endif - fb_edid_to_monspecs(edid, &hdmi->monspec); + if (!hdmi->edid_blocks) { + fb_edid_to_monspecs(edid, &hdmi->monspec); + hdmi->edid_blocks = edid[126] + 1; + + dev_dbg(hdmi->dev, "%d main modes, %d extension blocks\n", + hdmi->monspec.modedb_len, hdmi->edid_blocks - 1); + } else { + dev_dbg(hdmi->dev, "Extension %u detected, DTD start %u\n", + edid[0], edid[2]); + fb_edid_add_monspecs(edid, &hdmi->monspec); + } + + if (hdmi->edid_blocks > hdmi->edid_segment_nr * 2 + + (hdmi->edid_block_addr >> 7) + 1) { + /* More blocks to read */ + if (hdmi->edid_block_addr) { + hdmi->edid_block_addr = 0; + hdmi->edid_segment_nr++; + } else { + hdmi->edid_block_addr = 0x80; + } + /* Set EDID word address */ + hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); + /* Enable EDID interrupt */ + hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); + /* Set EDID segment pointer - starts reading EDID */ + hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); + return -EAGAIN; + } + + /* All E-EDID blocks ready */ + dev_dbg(hdmi->dev, "%d main and extended modes\n", hdmi->monspec.modedb_len); fb_get_options("sh_mobile_lcdc", &forced); if (forced && *forced) { @@ -903,32 +937,34 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) /* Check, if hot plug & MSENS pin status are both high */ if ((msens & 0xC0) == 0xC0) { /* Display plug in */ + hdmi->edid_segment_nr = 0; + hdmi->edid_block_addr = 0; + hdmi->edid_blocks = 0; hdmi->hp_state = HDMI_HOTPLUG_CONNECTED; /* Set EDID word address */ hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); - /* Set EDID segment pointer */ - hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); /* Enable EDID interrupt */ hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); + /* Set EDID segment pointer - starts reading EDID */ + hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); } else if (!(status1 & 0x80)) { /* Display unplug, beware multiple interrupts */ - if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) + if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) { + hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; schedule_delayed_work(&hdmi->edid_work, 0); - - hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; + } /* display_off will switch back to mode_a */ } } else if (status1 & 2) { /* EDID error interrupt: retry */ /* Set EDID word address */ - hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); + hdmi_write(hdmi, hdmi->edid_block_addr, HDMI_EDID_WORD_ADDRESS); /* Set EDID segment pointer */ - hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); + hdmi_write(hdmi, hdmi->edid_segment_nr, HDMI_EDID_SEGMENT_POINTER); } else if (status1 & 4) { /* Disable EDID interrupt */ hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1); - hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10)); } @@ -1056,7 +1092,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); - if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { + if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { unsigned long parent_rate = 0, hdmi_rate; /* A device has been plugged in */ @@ -1066,6 +1102,8 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) if (ret < 0) goto out; + hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; + /* Reconfigure the clock */ ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); if (ret < 0) @@ -1119,7 +1157,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) } out: - if (ret < 0) + if (ret < 0 && ret != -EAGAIN) hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; mutex_unlock(&hdmi->mutex); -- cgit v1.2.3 From caedda35c6dba5a283e5d87e77a8d19ee4be3183 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:30:40 +0000 Subject: cxgb4vf: minor comment/symbolic name cleanup. Minor cleanup of comments and symbolic constant names for clarity. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/adapter.h | 2 +- drivers/net/cxgb4vf/cxgb4vf_main.c | 11 ++++------- drivers/net/cxgb4vf/sge.c | 9 ++++++--- drivers/net/cxgb4vf/t4vf_hw.c | 5 +++-- 4 files changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h index 8ea01962e045..4766b4116b41 100644 --- a/drivers/net/cxgb4vf/adapter.h +++ b/drivers/net/cxgb4vf/adapter.h @@ -60,7 +60,7 @@ enum { * MSI-X interrupt index usage. */ MSIX_FW = 0, /* MSI-X index for firmware Q */ - MSIX_NIQFLINT = 1, /* MSI-X index base for Ingress Qs */ + MSIX_IQFLINT = 1, /* MSI-X index base for Ingress Qs */ MSIX_EXTRAS = 1, MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS, diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index c3449bbc585a..62357191d4e7 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -280,9 +280,7 @@ static void name_msix_vecs(struct adapter *adapter) const struct port_info *pi = netdev_priv(dev); int qs, msi; - for (qs = 0, msi = MSIX_NIQFLINT; - qs < pi->nqsets; - qs++, msi++) { + for (qs = 0, msi = MSIX_IQFLINT; qs < pi->nqsets; qs++, msi++) { snprintf(adapter->msix_info[msi].desc, namelen, "%s-%d", dev->name, qs); adapter->msix_info[msi].desc[namelen] = 0; @@ -309,7 +307,7 @@ static int request_msix_queue_irqs(struct adapter *adapter) /* * Ethernet queues. */ - msi = MSIX_NIQFLINT; + msi = MSIX_IQFLINT; for_each_ethrxq(s, rxq) { err = request_irq(adapter->msix_info[msi].vec, t4vf_sge_intr_msix, 0, @@ -337,7 +335,7 @@ static void free_msix_queue_irqs(struct adapter *adapter) int rxq, msi; free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq); - msi = MSIX_NIQFLINT; + msi = MSIX_IQFLINT; for_each_ethrxq(s, rxq) free_irq(adapter->msix_info[msi++].vec, &s->ethrxq[rxq].rspq); @@ -527,7 +525,7 @@ static int setup_sge_queues(struct adapter *adapter) * brought up at which point lots of things get nailed down * permanently ... */ - msix = MSIX_NIQFLINT; + msix = MSIX_IQFLINT; for_each_port(adapter, pidx) { struct net_device *dev = adapter->port[pidx]; struct port_info *pi = netdev_priv(dev); @@ -2470,7 +2468,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, version_printed = 1; } - /* * Initialize generic PCI device state. */ diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index ecf0770bf0ff..e0b3d1bc2fdf 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -1568,6 +1568,9 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp, } else skb_checksum_none_assert(skb); + /* + * Deliver the packet to the stack. + */ if (unlikely(pkt->vlan_ex)) { struct vlan_group *grp = pi->vlan_grp; @@ -2143,7 +2146,7 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq, /* * Calculate the size of the hardware free list ring plus - * status page (which the SGE will place at the end of the + * Status Page (which the SGE will place after the end of the * free list ring) in Egress Queue Units. */ flsz = (fl->size / FL_PER_EQ_UNIT + @@ -2240,8 +2243,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq, struct port_info *pi = netdev_priv(dev); /* - * Calculate the size of the hardware TX Queue (including the - * status age on the end) in units of TX Descriptors. + * Calculate the size of the hardware TX Queue (including the Status + * Page on the end of the TX Queue) in units of TX Descriptors. */ nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc); diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c index e306c20dfaee..f7d7f976064b 100644 --- a/drivers/net/cxgb4vf/t4vf_hw.c +++ b/drivers/net/cxgb4vf/t4vf_hw.c @@ -1276,7 +1276,7 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid) */ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) { - struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl; + const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl; u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi)); switch (opcode) { @@ -1284,7 +1284,8 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl) /* * Link/module state change message. */ - const struct fw_port_cmd *port_cmd = (void *)rpl; + const struct fw_port_cmd *port_cmd = + (const struct fw_port_cmd *)rpl; u32 word; int action, port_id, link_ok, speed, fc, pidx; -- cgit v1.2.3 From f12fe3536bebcbd2ccfa80030ec7d9868c488d30 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:30:41 +0000 Subject: cxgb4vf: add ethtool statistics for GRO. Add ethtool statistics for GRO. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 62357191d4e7..47417d400371 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1346,6 +1346,8 @@ struct queue_port_stats { u64 rx_csum; u64 vlan_ex; u64 vlan_ins; + u64 lro_pkts; + u64 lro_merged; }; /* @@ -1383,6 +1385,8 @@ static const char stats_strings[][ETH_GSTRING_LEN] = { "RxCsumGood ", "VLANextractions ", "VLANinsertions ", + "GROPackets ", + "GROMerged ", }; /* @@ -1432,6 +1436,8 @@ static void collect_sge_port_stats(const struct adapter *adapter, stats->rx_csum += rxq->stats.rx_cso; stats->vlan_ex += rxq->stats.vlan_ex; stats->vlan_ins += txq->vlan_ins; + stats->lro_pkts += rxq->stats.lro_pkts; + stats->lro_merged += rxq->stats.lro_merged; } } -- cgit v1.2.3 From 4204875dd4b3c3e40e0294a8c2619fdf9e5907e1 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:30:42 +0000 Subject: cxgb4vf: fix up "Section Mismatch" compiler warning. Fix up "Section Mismatch" compiler warning and mark another routine as __devinit. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 47417d400371..4cf530ac149d 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2032,7 +2032,7 @@ static int __devinit setup_debugfs(struct adapter *adapter) * Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave * it to our caller to tear down the directory (debugfs_root). */ -static void __devexit cleanup_debugfs(struct adapter *adapter) +static void cleanup_debugfs(struct adapter *adapter) { BUG_ON(adapter->debugfs_root == NULL); @@ -2050,7 +2050,7 @@ static void __devexit cleanup_debugfs(struct adapter *adapter) * adapter parameters we're going to be using and initialize basic adapter * hardware support. */ -static int adap_init0(struct adapter *adapter) +static int __devinit adap_init0(struct adapter *adapter) { struct vf_resources *vfres = &adapter->params.vfres; struct sge_params *sge_params = &adapter->params.sge; -- cgit v1.2.3 From 410989f65151557701ce86875b141e694281dd6c Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 11 Nov 2010 09:30:43 +0000 Subject: cxgb4vf: Advertise NETIF_F_TSO_ECN. Advertise NETIF_F_TSO_ECN. Signed-off-by: Casey Leedom Signed-off-by: David S. Miller --- drivers/net/cxgb4vf/cxgb4vf_main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 4cf530ac149d..9246d2fa6cf9 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -1533,15 +1533,20 @@ static void cxgb4vf_get_wol(struct net_device *dev, memset(&wol->sopass, 0, sizeof(wol->sopass)); } +/* + * TCP Segmentation Offload flags which we support. + */ +#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN) + /* * Set TCP Segmentation Offloading feature capabilities. */ static int cxgb4vf_set_tso(struct net_device *dev, u32 tso) { if (tso) - dev->features |= NETIF_F_TSO | NETIF_F_TSO6; + dev->features |= TSO_FLAGS; else - dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + dev->features &= ~TSO_FLAGS; return 0; } @@ -2610,7 +2615,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, netif_carrier_off(netdev); netdev->irq = pdev->irq; - netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | + netdev->features = (NETIF_F_SG | TSO_FLAGS | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_GRO); -- cgit v1.2.3 From 900fcf091e95fbcc773b72c770afcd2e8eda4da2 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Mon, 1 Nov 2010 09:29:24 +0000 Subject: net: sh_eth: Move off of deprecated I/O routines. sh_eth is the last in-tree user of the ctrl_xxx I/O routines. This simply converts them over to regular MMIO accesors. Signed-off-by: Paul Mundt Signed-off-by: David S. Miller --- drivers/net/sh_eth.c | 244 +++++++++++++++++++++++++-------------------------- 1 file changed, 122 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 50259dfec583..b12660d72338 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -45,9 +45,9 @@ static void sh_eth_set_duplex(struct net_device *ndev) u32 ioaddr = ndev->base_addr; if (mdp->duplex) /* Full */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); else /* Half */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); } static void sh_eth_set_rate(struct net_device *ndev) @@ -57,10 +57,10 @@ static void sh_eth_set_rate(struct net_device *ndev) switch (mdp->speed) { case 10: /* 10BASE */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) & ~ECMR_RTM, ioaddr + ECMR); break; case 100:/* 100BASE */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) | ECMR_RTM, ioaddr + ECMR); break; default: break; @@ -96,9 +96,9 @@ static void sh_eth_set_duplex(struct net_device *ndev) u32 ioaddr = ndev->base_addr; if (mdp->duplex) /* Full */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); else /* Half */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); } static void sh_eth_set_rate(struct net_device *ndev) @@ -108,10 +108,10 @@ static void sh_eth_set_rate(struct net_device *ndev) switch (mdp->speed) { case 10: /* 10BASE */ - ctrl_outl(0, ioaddr + RTRATE); + writel(0, ioaddr + RTRATE); break; case 100:/* 100BASE */ - ctrl_outl(1, ioaddr + RTRATE); + writel(1, ioaddr + RTRATE); break; default: break; @@ -143,7 +143,7 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = { static void sh_eth_chip_reset(struct net_device *ndev) { /* reset device */ - ctrl_outl(ARSTR_ARSTR, ARSTR); + writel(ARSTR_ARSTR, ARSTR); mdelay(1); } @@ -152,10 +152,10 @@ static void sh_eth_reset(struct net_device *ndev) u32 ioaddr = ndev->base_addr; int cnt = 100; - ctrl_outl(EDSR_ENALL, ioaddr + EDSR); - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + writel(EDSR_ENALL, ioaddr + EDSR); + writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); while (cnt > 0) { - if (!(ctrl_inl(ioaddr + EDMR) & 0x3)) + if (!(readl(ioaddr + EDMR) & 0x3)) break; mdelay(1); cnt--; @@ -164,14 +164,14 @@ static void sh_eth_reset(struct net_device *ndev) printk(KERN_ERR "Device reset fail\n"); /* Table Init */ - ctrl_outl(0x0, ioaddr + TDLAR); - ctrl_outl(0x0, ioaddr + TDFAR); - ctrl_outl(0x0, ioaddr + TDFXR); - ctrl_outl(0x0, ioaddr + TDFFR); - ctrl_outl(0x0, ioaddr + RDLAR); - ctrl_outl(0x0, ioaddr + RDFAR); - ctrl_outl(0x0, ioaddr + RDFXR); - ctrl_outl(0x0, ioaddr + RDFFR); + writel(0x0, ioaddr + TDLAR); + writel(0x0, ioaddr + TDFAR); + writel(0x0, ioaddr + TDFXR); + writel(0x0, ioaddr + TDFFR); + writel(0x0, ioaddr + RDLAR); + writel(0x0, ioaddr + RDFAR); + writel(0x0, ioaddr + RDFXR); + writel(0x0, ioaddr + RDFFR); } static void sh_eth_set_duplex(struct net_device *ndev) @@ -180,9 +180,9 @@ static void sh_eth_set_duplex(struct net_device *ndev) u32 ioaddr = ndev->base_addr; if (mdp->duplex) /* Full */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) | ECMR_DM, ioaddr + ECMR); else /* Half */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); + writel(readl(ioaddr + ECMR) & ~ECMR_DM, ioaddr + ECMR); } static void sh_eth_set_rate(struct net_device *ndev) @@ -192,13 +192,13 @@ static void sh_eth_set_rate(struct net_device *ndev) switch (mdp->speed) { case 10: /* 10BASE */ - ctrl_outl(GECMR_10, ioaddr + GECMR); + writel(GECMR_10, ioaddr + GECMR); break; case 100:/* 100BASE */ - ctrl_outl(GECMR_100, ioaddr + GECMR); + writel(GECMR_100, ioaddr + GECMR); break; case 1000: /* 1000BASE */ - ctrl_outl(GECMR_1000, ioaddr + GECMR); + writel(GECMR_1000, ioaddr + GECMR); break; default: break; @@ -283,9 +283,9 @@ static void sh_eth_reset(struct net_device *ndev) { u32 ioaddr = ndev->base_addr; - ctrl_outl(ctrl_inl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); + writel(readl(ioaddr + EDMR) | EDMR_SRST, ioaddr + EDMR); mdelay(3); - ctrl_outl(ctrl_inl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); + writel(readl(ioaddr + EDMR) & ~EDMR_SRST, ioaddr + EDMR); } #endif @@ -336,10 +336,10 @@ static void update_mac_address(struct net_device *ndev) { u32 ioaddr = ndev->base_addr; - ctrl_outl((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | + writel((ndev->dev_addr[0] << 24) | (ndev->dev_addr[1] << 16) | (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]), ioaddr + MAHR); - ctrl_outl((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), + writel((ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]), ioaddr + MALR); } @@ -358,12 +358,12 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac) if (mac[0] || mac[1] || mac[2] || mac[3] || mac[4] || mac[5]) { memcpy(ndev->dev_addr, mac, 6); } else { - ndev->dev_addr[0] = (ctrl_inl(ioaddr + MAHR) >> 24); - ndev->dev_addr[1] = (ctrl_inl(ioaddr + MAHR) >> 16) & 0xFF; - ndev->dev_addr[2] = (ctrl_inl(ioaddr + MAHR) >> 8) & 0xFF; - ndev->dev_addr[3] = (ctrl_inl(ioaddr + MAHR) & 0xFF); - ndev->dev_addr[4] = (ctrl_inl(ioaddr + MALR) >> 8) & 0xFF; - ndev->dev_addr[5] = (ctrl_inl(ioaddr + MALR) & 0xFF); + ndev->dev_addr[0] = (readl(ioaddr + MAHR) >> 24); + ndev->dev_addr[1] = (readl(ioaddr + MAHR) >> 16) & 0xFF; + ndev->dev_addr[2] = (readl(ioaddr + MAHR) >> 8) & 0xFF; + ndev->dev_addr[3] = (readl(ioaddr + MAHR) & 0xFF); + ndev->dev_addr[4] = (readl(ioaddr + MALR) >> 8) & 0xFF; + ndev->dev_addr[5] = (readl(ioaddr + MALR) & 0xFF); } } @@ -379,19 +379,19 @@ struct bb_info { /* PHY bit set */ static void bb_set(u32 addr, u32 msk) { - ctrl_outl(ctrl_inl(addr) | msk, addr); + writel(readl(addr) | msk, addr); } /* PHY bit clear */ static void bb_clr(u32 addr, u32 msk) { - ctrl_outl((ctrl_inl(addr) & ~msk), addr); + writel((readl(addr) & ~msk), addr); } /* PHY bit read */ static int bb_read(u32 addr, u32 msk) { - return (ctrl_inl(addr) & msk) != 0; + return (readl(addr) & msk) != 0; } /* Data I/O pin control */ @@ -506,9 +506,9 @@ static void sh_eth_ring_format(struct net_device *ndev) rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); /* Rx descriptor address set */ if (i == 0) { - ctrl_outl(mdp->rx_desc_dma, ioaddr + RDLAR); + writel(mdp->rx_desc_dma, ioaddr + RDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(mdp->rx_desc_dma, ioaddr + RDFAR); + writel(mdp->rx_desc_dma, ioaddr + RDFAR); #endif } } @@ -528,9 +528,9 @@ static void sh_eth_ring_format(struct net_device *ndev) txdesc->buffer_length = 0; if (i == 0) { /* Tx descriptor address set */ - ctrl_outl(mdp->tx_desc_dma, ioaddr + TDLAR); + writel(mdp->tx_desc_dma, ioaddr + TDLAR); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(mdp->tx_desc_dma, ioaddr + TDFAR); + writel(mdp->tx_desc_dma, ioaddr + TDFAR); #endif } } @@ -623,71 +623,71 @@ static int sh_eth_dev_init(struct net_device *ndev) /* Descriptor format */ sh_eth_ring_format(ndev); if (mdp->cd->rpadir) - ctrl_outl(mdp->cd->rpadir_value, ioaddr + RPADIR); + writel(mdp->cd->rpadir_value, ioaddr + RPADIR); /* all sh_eth int mask */ - ctrl_outl(0, ioaddr + EESIPR); + writel(0, ioaddr + EESIPR); #if defined(__LITTLE_ENDIAN__) if (mdp->cd->hw_swap) - ctrl_outl(EDMR_EL, ioaddr + EDMR); + writel(EDMR_EL, ioaddr + EDMR); else #endif - ctrl_outl(0, ioaddr + EDMR); + writel(0, ioaddr + EDMR); /* FIFO size set */ - ctrl_outl(mdp->cd->fdr_value, ioaddr + FDR); - ctrl_outl(0, ioaddr + TFTR); + writel(mdp->cd->fdr_value, ioaddr + FDR); + writel(0, ioaddr + TFTR); /* Frame recv control */ - ctrl_outl(mdp->cd->rmcr_value, ioaddr + RMCR); + writel(mdp->cd->rmcr_value, ioaddr + RMCR); rx_int_var = mdp->rx_int_var = DESC_I_RINT8 | DESC_I_RINT5; tx_int_var = mdp->tx_int_var = DESC_I_TINT2; - ctrl_outl(rx_int_var | tx_int_var, ioaddr + TRSCER); + writel(rx_int_var | tx_int_var, ioaddr + TRSCER); if (mdp->cd->bculr) - ctrl_outl(0x800, ioaddr + BCULR); /* Burst sycle set */ + writel(0x800, ioaddr + BCULR); /* Burst sycle set */ - ctrl_outl(mdp->cd->fcftr_value, ioaddr + FCFTR); + writel(mdp->cd->fcftr_value, ioaddr + FCFTR); if (!mdp->cd->no_trimd) - ctrl_outl(0, ioaddr + TRIMD); + writel(0, ioaddr + TRIMD); /* Recv frame limit set register */ - ctrl_outl(RFLR_VALUE, ioaddr + RFLR); + writel(RFLR_VALUE, ioaddr + RFLR); - ctrl_outl(ctrl_inl(ioaddr + EESR), ioaddr + EESR); - ctrl_outl(mdp->cd->eesipr_value, ioaddr + EESIPR); + writel(readl(ioaddr + EESR), ioaddr + EESR); + writel(mdp->cd->eesipr_value, ioaddr + EESIPR); /* PAUSE Prohibition */ - val = (ctrl_inl(ioaddr + ECMR) & ECMR_DM) | + val = (readl(ioaddr + ECMR) & ECMR_DM) | ECMR_ZPF | (mdp->duplex ? ECMR_DM : 0) | ECMR_TE | ECMR_RE; - ctrl_outl(val, ioaddr + ECMR); + writel(val, ioaddr + ECMR); if (mdp->cd->set_rate) mdp->cd->set_rate(ndev); /* E-MAC Status Register clear */ - ctrl_outl(mdp->cd->ecsr_value, ioaddr + ECSR); + writel(mdp->cd->ecsr_value, ioaddr + ECSR); /* E-MAC Interrupt Enable register */ - ctrl_outl(mdp->cd->ecsipr_value, ioaddr + ECSIPR); + writel(mdp->cd->ecsipr_value, ioaddr + ECSIPR); /* Set MAC address */ update_mac_address(ndev); /* mask reset */ if (mdp->cd->apr) - ctrl_outl(APR_AP, ioaddr + APR); + writel(APR_AP, ioaddr + APR); if (mdp->cd->mpr) - ctrl_outl(MPR_MP, ioaddr + MPR); + writel(MPR_MP, ioaddr + MPR); if (mdp->cd->tpauser) - ctrl_outl(TPAUSER_UNLIMITED, ioaddr + TPAUSER); + writel(TPAUSER_UNLIMITED, ioaddr + TPAUSER); /* Setting the Rx mode will start the Rx process. */ - ctrl_outl(EDRRR_R, ioaddr + EDRRR); + writel(EDRRR_R, ioaddr + EDRRR); netif_start_queue(ndev); @@ -811,8 +811,8 @@ static int sh_eth_rx(struct net_device *ndev) /* Restart Rx engine if stopped. */ /* If we don't need to check status, don't. -KDU */ - if (!(ctrl_inl(ndev->base_addr + EDRRR) & EDRRR_R)) - ctrl_outl(EDRRR_R, ndev->base_addr + EDRRR); + if (!(readl(ndev->base_addr + EDRRR) & EDRRR_R)) + writel(EDRRR_R, ndev->base_addr + EDRRR); return 0; } @@ -827,8 +827,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) u32 mask; if (intr_status & EESR_ECI) { - felic_stat = ctrl_inl(ioaddr + ECSR); - ctrl_outl(felic_stat, ioaddr + ECSR); /* clear int */ + felic_stat = readl(ioaddr + ECSR); + writel(felic_stat, ioaddr + ECSR); /* clear int */ if (felic_stat & ECSR_ICD) mdp->stats.tx_carrier_errors++; if (felic_stat & ECSR_LCHNG) { @@ -839,25 +839,25 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) else link_stat = PHY_ST_LINK; } else { - link_stat = (ctrl_inl(ioaddr + PSR)); + link_stat = (readl(ioaddr + PSR)); if (mdp->ether_link_active_low) link_stat = ~link_stat; } if (!(link_stat & PHY_ST_LINK)) { /* Link Down : disable tx and rx */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) & + writel(readl(ioaddr + ECMR) & ~(ECMR_RE | ECMR_TE), ioaddr + ECMR); } else { /* Link Up */ - ctrl_outl(ctrl_inl(ioaddr + EESIPR) & + writel(readl(ioaddr + EESIPR) & ~DMAC_M_ECI, ioaddr + EESIPR); /*clear int */ - ctrl_outl(ctrl_inl(ioaddr + ECSR), + writel(readl(ioaddr + ECSR), ioaddr + ECSR); - ctrl_outl(ctrl_inl(ioaddr + EESIPR) | + writel(readl(ioaddr + EESIPR) | DMAC_M_ECI, ioaddr + EESIPR); /* enable tx and rx */ - ctrl_outl(ctrl_inl(ioaddr + ECMR) | + writel(readl(ioaddr + ECMR) | (ECMR_RE | ECMR_TE), ioaddr + ECMR); } } @@ -888,8 +888,8 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* Receive Descriptor Empty int */ mdp->stats.rx_over_errors++; - if (ctrl_inl(ioaddr + EDRRR) ^ EDRRR_R) - ctrl_outl(EDRRR_R, ioaddr + EDRRR); + if (readl(ioaddr + EDRRR) ^ EDRRR_R) + writel(EDRRR_R, ioaddr + EDRRR); dev_err(&ndev->dev, "Receive Descriptor Empty\n"); } if (intr_status & EESR_RFE) { @@ -903,7 +903,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) mask &= ~EESR_ADE; if (intr_status & mask) { /* Tx error */ - u32 edtrr = ctrl_inl(ndev->base_addr + EDTRR); + u32 edtrr = readl(ndev->base_addr + EDTRR); /* dmesg */ dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ", intr_status, mdp->cur_tx); @@ -915,7 +915,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status) /* SH7712 BUG */ if (edtrr ^ EDTRR_TRNS) { /* tx dma start */ - ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + writel(EDTRR_TRNS, ndev->base_addr + EDTRR); } /* wakeup */ netif_wake_queue(ndev); @@ -934,12 +934,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) spin_lock(&mdp->lock); /* Get interrpt stat */ - intr_status = ctrl_inl(ioaddr + EESR); + intr_status = readl(ioaddr + EESR); /* Clear interrupt */ if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF | EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF | cd->tx_check | cd->eesr_err_check)) { - ctrl_outl(intr_status, ioaddr + EESR); + writel(intr_status, ioaddr + EESR); ret = IRQ_HANDLED; } else goto other_irq; @@ -1000,7 +1000,7 @@ static void sh_eth_adjust_link(struct net_device *ndev) mdp->cd->set_rate(ndev); } if (mdp->link == PHY_DOWN) { - ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_TXF) + writel((readl(ioaddr + ECMR) & ~ECMR_TXF) | ECMR_DM, ioaddr + ECMR); new_state = 1; mdp->link = phydev->link; @@ -1125,7 +1125,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev) /* worning message out. */ printk(KERN_WARNING "%s: transmit timed out, status %8.8x," - " resetting...\n", ndev->name, (int)ctrl_inl(ioaddr + EESR)); + " resetting...\n", ndev->name, (int)readl(ioaddr + EESR)); /* tx_errors count up */ mdp->stats.tx_errors++; @@ -1196,8 +1196,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) mdp->cur_tx++; - if (!(ctrl_inl(ndev->base_addr + EDTRR) & EDTRR_TRNS)) - ctrl_outl(EDTRR_TRNS, ndev->base_addr + EDTRR); + if (!(readl(ndev->base_addr + EDTRR) & EDTRR_TRNS)) + writel(EDTRR_TRNS, ndev->base_addr + EDTRR); return NETDEV_TX_OK; } @@ -1212,11 +1212,11 @@ static int sh_eth_close(struct net_device *ndev) netif_stop_queue(ndev); /* Disable interrupts by clearing the interrupt mask. */ - ctrl_outl(0x0000, ioaddr + EESIPR); + writel(0x0000, ioaddr + EESIPR); /* Stop the chip's Tx and Rx processes. */ - ctrl_outl(0, ioaddr + EDTRR); - ctrl_outl(0, ioaddr + EDRRR); + writel(0, ioaddr + EDTRR); + writel(0, ioaddr + EDRRR); /* PHY Disconnect */ if (mdp->phydev) { @@ -1251,20 +1251,20 @@ static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) pm_runtime_get_sync(&mdp->pdev->dev); - mdp->stats.tx_dropped += ctrl_inl(ioaddr + TROCR); - ctrl_outl(0, ioaddr + TROCR); /* (write clear) */ - mdp->stats.collisions += ctrl_inl(ioaddr + CDCR); - ctrl_outl(0, ioaddr + CDCR); /* (write clear) */ - mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + LCCR); - ctrl_outl(0, ioaddr + LCCR); /* (write clear) */ + mdp->stats.tx_dropped += readl(ioaddr + TROCR); + writel(0, ioaddr + TROCR); /* (write clear) */ + mdp->stats.collisions += readl(ioaddr + CDCR); + writel(0, ioaddr + CDCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += readl(ioaddr + LCCR); + writel(0, ioaddr + LCCR); /* (write clear) */ #if defined(CONFIG_CPU_SUBTYPE_SH7763) - mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CERCR);/* CERCR */ - ctrl_outl(0, ioaddr + CERCR); /* (write clear) */ - mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CEECR);/* CEECR */ - ctrl_outl(0, ioaddr + CEECR); /* (write clear) */ + mdp->stats.tx_carrier_errors += readl(ioaddr + CERCR);/* CERCR */ + writel(0, ioaddr + CERCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += readl(ioaddr + CEECR);/* CEECR */ + writel(0, ioaddr + CEECR); /* (write clear) */ #else - mdp->stats.tx_carrier_errors += ctrl_inl(ioaddr + CNDCR); - ctrl_outl(0, ioaddr + CNDCR); /* (write clear) */ + mdp->stats.tx_carrier_errors += readl(ioaddr + CNDCR); + writel(0, ioaddr + CNDCR); /* (write clear) */ #endif pm_runtime_put_sync(&mdp->pdev->dev); @@ -1295,11 +1295,11 @@ static void sh_eth_set_multicast_list(struct net_device *ndev) if (ndev->flags & IFF_PROMISC) { /* Set promiscuous. */ - ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM, + writel((readl(ioaddr + ECMR) & ~ECMR_MCT) | ECMR_PRM, ioaddr + ECMR); } else { /* Normal, unicast/broadcast-only mode. */ - ctrl_outl((ctrl_inl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT, + writel((readl(ioaddr + ECMR) & ~ECMR_PRM) | ECMR_MCT, ioaddr + ECMR); } } @@ -1307,30 +1307,30 @@ static void sh_eth_set_multicast_list(struct net_device *ndev) /* SuperH's TSU register init function */ static void sh_eth_tsu_init(u32 ioaddr) { - ctrl_outl(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */ - ctrl_outl(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */ - ctrl_outl(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */ - ctrl_outl(0xc, ioaddr + TSU_BSYSL0); - ctrl_outl(0xc, ioaddr + TSU_BSYSL1); - ctrl_outl(0, ioaddr + TSU_PRISL0); - ctrl_outl(0, ioaddr + TSU_PRISL1); - ctrl_outl(0, ioaddr + TSU_FWSL0); - ctrl_outl(0, ioaddr + TSU_FWSL1); - ctrl_outl(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC); + writel(0, ioaddr + TSU_FWEN0); /* Disable forward(0->1) */ + writel(0, ioaddr + TSU_FWEN1); /* Disable forward(1->0) */ + writel(0, ioaddr + TSU_FCM); /* forward fifo 3k-3k */ + writel(0xc, ioaddr + TSU_BSYSL0); + writel(0xc, ioaddr + TSU_BSYSL1); + writel(0, ioaddr + TSU_PRISL0); + writel(0, ioaddr + TSU_PRISL1); + writel(0, ioaddr + TSU_FWSL0); + writel(0, ioaddr + TSU_FWSL1); + writel(TSU_FWSLC_POSTENU | TSU_FWSLC_POSTENL, ioaddr + TSU_FWSLC); #if defined(CONFIG_CPU_SUBTYPE_SH7763) - ctrl_outl(0, ioaddr + TSU_QTAG0); /* Disable QTAG(0->1) */ - ctrl_outl(0, ioaddr + TSU_QTAG1); /* Disable QTAG(1->0) */ + writel(0, ioaddr + TSU_QTAG0); /* Disable QTAG(0->1) */ + writel(0, ioaddr + TSU_QTAG1); /* Disable QTAG(1->0) */ #else - ctrl_outl(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */ - ctrl_outl(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */ + writel(0, ioaddr + TSU_QTAGM0); /* Disable QTAG(0->1) */ + writel(0, ioaddr + TSU_QTAGM1); /* Disable QTAG(1->0) */ #endif - ctrl_outl(0, ioaddr + TSU_FWSR); /* all interrupt status clear */ - ctrl_outl(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */ - ctrl_outl(0, ioaddr + TSU_TEN); /* Disable all CAM entry */ - ctrl_outl(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */ - ctrl_outl(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */ - ctrl_outl(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */ - ctrl_outl(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */ + writel(0, ioaddr + TSU_FWSR); /* all interrupt status clear */ + writel(0, ioaddr + TSU_FWINMK); /* Disable all interrupt */ + writel(0, ioaddr + TSU_TEN); /* Disable all CAM entry */ + writel(0, ioaddr + TSU_POST1); /* Disable CAM entry [ 0- 7] */ + writel(0, ioaddr + TSU_POST2); /* Disable CAM entry [ 8-15] */ + writel(0, ioaddr + TSU_POST3); /* Disable CAM entry [16-23] */ + writel(0, ioaddr + TSU_POST4); /* Disable CAM entry [24-31] */ } #endif /* SH_ETH_HAS_TSU */ -- cgit v1.2.3 From 6b7b6cf553f881d45bb37a73f5db956afb290a08 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 20 Oct 2010 02:09:44 +0200 Subject: ath9k_hw: initialize regulatory->max_power_level in set_txpower for AR9003 The same is done for the older chip families as well. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c4182359bee4..92cfef225477 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -2133,6 +2133,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, u8 twiceMaxRegulatoryPower, u8 powerLimit) { + struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); u8 targetPowerValT2[ar9300RateSize]; unsigned int i = 0; @@ -2180,6 +2181,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, i = ALL_TARGET_HT20_0_8_16; /* ht20 */ ah->txpower_limit = targetPowerValT2[i]; + regulatory->max_power_level = ratesArray[i]; ar9003_hw_calibration_apply(ah, chan->channel); } -- cgit v1.2.3 From de40f316c01b1ba9535e6dc99f6a67e7655b07da Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 20 Oct 2010 03:08:53 +0200 Subject: ath9k_hw: extend ath9k_hw_set_txpowerlimit to test channel txpower ath9k_hw_set_txpowerlimit gets an extra boolean parameter that - if set - causes the rate txpower table and the regulatory limit to be calculated and stored, without changing hardware registers. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 20 ++++++--- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 +- drivers/net/wireless/ath/ath9k/eeprom.h | 3 +- drivers/net/wireless/ath/ath9k/eeprom_4k.c | 9 +++- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 27 ++++++----- drivers/net/wireless/ath/ath9k/eeprom_def.c | 62 ++++++++++++++------------ drivers/net/wireless/ath/ath9k/htc_drv_main.c | 2 +- drivers/net/wireless/ath/ath9k/hw.c | 6 +-- drivers/net/wireless/ath/ath9k/hw.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 2 +- 11 files changed, 79 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ea9f4497f58c..777a602176f2 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -873,7 +873,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit)); + (u32) regulatory->power_limit), false); /* Write analog registers */ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 92cfef225477..a88fe0d6142f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -2131,7 +2131,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); @@ -2145,7 +2145,16 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, twiceMaxRegulatoryPower, powerLimit); - while (i < ar9300RateSize) { + regulatory->max_power_level = 0; + for (i = 0; i < ar9300RateSize; i++) { + if (targetPowerValT2[i] > regulatory->max_power_level) + regulatory->max_power_level = targetPowerValT2[i]; + } + + if (test) + return; + + for (i = 0; i < ar9300RateSize; i++) { ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; @@ -2160,9 +2169,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, i++; } - /* Write target power array to registers */ - ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); - /* * This is the TX power we send back to driver core, * and it can use to pass to userspace to display our @@ -2181,8 +2187,10 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, i = ALL_TARGET_HT20_0_8_16; /* ht20 */ ah->txpower_limit = targetPowerValT2[i]; - regulatory->max_power_level = ratesArray[i]; + regulatory->max_power_level = targetPowerValT2[i]; + /* Write target power array to registers */ + ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); ar9003_hw_calibration_apply(ah, chan->channel); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 669b777729b3..06a9c4cd2f44 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -614,7 +614,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit)); + (u32) regulatory->power_limit), false); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index dacb45e1b906..3c99830dab0c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -680,7 +680,8 @@ struct eeprom_ops { void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit); + u8 twiceMaxRegulatoryPower, u8 powerLimit, + bool test); u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 4fa4d8e28c64..c40c534c6662 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -726,7 +726,7 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; @@ -751,15 +751,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); + regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > AR5416_MAX_RATE_POWER) ratesArray[i] = AR5416_MAX_RATE_POWER; + + if (ratesArray[i] > regulatory->max_power_level) + regulatory->max_power_level = ratesArray[i]; } + if (test) + return; /* Update regulatory */ - i = rate6mb; if (IS_CHAN_HT40(chan)) i = rateHt40_0; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 966b9496a9dd..ebf7a89f547c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -853,7 +853,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; @@ -877,12 +877,26 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset); + regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > AR9287_MAX_RATE_POWER) ratesArray[i] = AR9287_MAX_RATE_POWER; + + if (ratesArray[i] > regulatory->max_power_level) + regulatory->max_power_level = ratesArray[i]; } + if (test) + return; + + if (IS_CHAN_2GHZ(chan)) + i = rate1l; + else + i = rate6mb; + + regulatory->max_power_level = ratesArray[i]; + if (AR_SREV_9280_20_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; @@ -971,17 +985,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); } - - if (IS_CHAN_2GHZ(chan)) - i = rate1l; - else - i = rate6mb; - - if (AR_SREV_9280_20_OR_LATER(ah)) - regulatory->max_power_level = - ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2; - else - regulatory->max_power_level = ratesArray[i]; } static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 76b4d65472dd..a819ddc9fdbc 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -1258,7 +1258,7 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, - u8 powerLimit) + u8 powerLimit, bool test) { #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); @@ -1285,12 +1285,44 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); + regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > AR5416_MAX_RATE_POWER) ratesArray[i] = AR5416_MAX_RATE_POWER; + if (ratesArray[i] > regulatory->max_power_level) + regulatory->max_power_level = ratesArray[i]; } + if (!test) { + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + regulatory->max_power_level = ratesArray[i]; + } + + switch(ar5416_get_ntxchains(ah->txchainmask)) { + case 1: + break; + case 2: + regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; + break; + case 3: + regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; + break; + default: + ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM, + "Invalid chainmask configuration\n"); + break; + } + + if (test) + return; + if (AR_SREV_9280_20_OR_LATER(ah)) { for (i = 0; i < Ar5416RateSize; i++) { int8_t pwr_table_offset; @@ -1387,34 +1419,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_POWER_TX_SUB, ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); - - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_20_OR_LATER(ah)) - regulatory->max_power_level = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET_DB * 2; - else - regulatory->max_power_level = ratesArray[i]; - - switch(ar5416_get_ntxchains(ah->txchainmask)) { - case 1: - break; - case 2: - regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; - break; - case 3: - regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; - break; - default: - ath_print(ath9k_hw_common(ah), ATH_DBG_EEPROM, - "Invalid chainmask configuration\n"); - break; - } } static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 9a3be8da755d..26b9a16ce33f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -29,7 +29,7 @@ static void ath_update_txpow(struct ath9k_htc_priv *priv) struct ath_hw *ah = priv->ah; if (priv->curtxpow != priv->txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit); + ath9k_hw_set_txpowerlimit(ah, priv->txpowlimit, false); /* read back in case value is clamped */ priv->curtxpow = ath9k_hw_regulatory(ah)->power_limit; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index d37a8ad03d74..e75d8e8cf4d2 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1166,7 +1166,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit)); + (u32) regulatory->power_limit), false); ath9k_hw_rfbus_done(ah); @@ -2165,7 +2165,7 @@ bool ath9k_hw_disable(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable); -void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; @@ -2178,7 +2178,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit) channel->max_antenna_gain * 2, channel->max_power * 2, min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit)); + (u32) regulatory->power_limit), test); } EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e68204ae899c..366f088dc15d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -860,7 +860,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah); void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits); bool ath9k_hw_phy_disable(struct ath_hw *ah); bool ath9k_hw_disable(struct ath_hw *ah); -void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit); +void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test); void ath9k_hw_setopmode(struct ath_hw *ah); void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1); void ath9k_hw_setbssidmask(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 7185ef3a3bff..92ed5bb71196 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -23,7 +23,7 @@ static void ath_update_txpow(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; if (sc->curtxpow != sc->config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); + ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); /* read back in case value is clamped */ sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; } -- cgit v1.2.3 From babcbc295fee766ca710235e431686fef744d9a6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 20 Oct 2010 02:09:46 +0200 Subject: ath9k: initialize per-channel tx power limits instead of hardcoding them Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/common.c | 15 +++++------- drivers/net/wireless/ath/ath9k/common.h | 5 ++-- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 4 +++- drivers/net/wireless/ath/ath9k/init.c | 33 +++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index f43a2d98421c..48b07c319a7f 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -107,12 +107,10 @@ static u32 ath9k_get_extchanmode(struct ieee80211_channel *chan, /* * Update internal channel flags. */ -void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, - struct ath9k_channel *ichan) +void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) { - struct ieee80211_channel *chan = hw->conf.channel; - struct ieee80211_conf *conf = &hw->conf; - ichan->channel = chan->center_freq; ichan->chan = chan; @@ -124,9 +122,8 @@ void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM; } - if (conf_is_ht(conf)) - ichan->chanmode = ath9k_get_extchanmode(chan, - conf->channel_type); + if (channel_type != NL80211_CHAN_NO_HT) + ichan->chanmode = ath9k_get_extchanmode(chan, channel_type); } EXPORT_SYMBOL(ath9k_cmn_update_ichannel); @@ -142,7 +139,7 @@ struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, chan_idx = curchan->hw_value; channel = &ah->channels[chan_idx]; - ath9k_cmn_update_ichannel(hw, channel); + ath9k_cmn_update_ichannel(channel, curchan, hw->conf.channel_type); return channel; } diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index fea3b3315391..c76c75a77c62 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -62,8 +62,9 @@ enum ath_stomp_type { int ath9k_cmn_padpos(__le16 frame_control); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); -void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw, - struct ath9k_channel *ichan); +void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw, struct ath_hw *ah); int ath9k_cmn_count_streams(unsigned int chainmask, int max); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 26b9a16ce33f..8266ce1f02e3 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1400,7 +1400,9 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n", curchan->center_freq); - ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]); + ath9k_cmn_update_ichannel(&priv->ah->channels[pos], + hw->conf.channel, + hw->conf.channel_type); if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_print(common, ATH_DBG_FATAL, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 12f4fd79c907..1b72720b36e2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -642,6 +642,37 @@ err_hw: return ret; } +static void ath9k_init_band_txpower(struct ath_softc *sc, int band) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + struct ath_hw *ah = sc->sc_ah; + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + int i; + + sband = &sc->sbands[band]; + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + ah->curchan = &ah->channels[chan->hw_value]; + ath9k_cmn_update_ichannel(ah->curchan, chan, NL80211_CHAN_HT20); + ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true); + chan->max_power = reg->max_power_level / 2; + } +} + +static void ath9k_init_txpower_limits(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_channel *curchan = ah->curchan; + + if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) + ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); + if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) + ath9k_init_band_txpower(sc, IEEE80211_BAND_5GHZ); + + ah->curchan = curchan; +} + void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -736,6 +767,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, if (error != 0) goto error_rx; + ath9k_init_txpower_limits(sc); + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) -- cgit v1.2.3 From a3685d119dacb07a7080169fea2847ef385b209f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 06:59:36 -0700 Subject: ath: make ath_hw_keysetmac() static This fixes this sparse warning: CHECK drivers/net/wireless/ath/key.c drivers/net/wireless/ath/key.c:70:6: warning: symbol 'ath_hw_keysetmac' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/key.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index bd21a4d82085..1e9aa326ca08 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -67,7 +67,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry) } EXPORT_SYMBOL(ath_hw_keyreset); -bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) +static bool ath_hw_keysetmac(struct ath_common *common, + u16 entry, const u8 *mac) { u32 macHi, macLo; u32 unicast_flag = AR_KEYTABLE_VALID; -- cgit v1.2.3 From f8c2a0871b8462481a02445b38a7321ad63bfc88 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 06:59:37 -0700 Subject: ath: make ath_hw_set_keycache_entry() static This fixes this sparse warning: CHECK drivers/net/wireless/ath/key.c drivers/net/wireless/ath/key.c:110:6: warning: symbol 'ath_hw_set_keycache_entry' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/key.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 1e9aa326ca08..62e3dac8f92a 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -108,9 +108,9 @@ static bool ath_hw_keysetmac(struct ath_common *common, return true; } -bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, - const struct ath_keyval *k, - const u8 *mac) +static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, + const struct ath_keyval *k, + const u8 *mac) { void *ah = common->ah; u32 key0, key1, key2, key3, key4; -- cgit v1.2.3 From 14fb7c17e97ea0fcc545393fb1f34e6541647b5b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 06:59:38 -0700 Subject: ath5k: make ath5k_update_bssid_mask_and_opmode() static This fixes this sparse warning: CHECK drivers/net/wireless/ath/ath5k/base.c drivers/net/wireless/ath/ath5k/base.c:569:6: warning: symbol 'ath5k_update_bssid_mask_and_opmode' was not declared. Should it be static? Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 484aad5b11b5..b9f93fbd9728 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -566,8 +566,8 @@ static void ath_do_set_opmode(struct ath5k_softc *sc) sc->opmode, ath_opmode_to_string(sc->opmode)); } -void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, - struct ieee80211_vif *vif) +static void ath5k_update_bssid_mask_and_opmode(struct ath5k_softc *sc, + struct ieee80211_vif *vif) { struct ath_common *common = ath5k_hw_common(sc->ah); struct ath_vif_iter_data iter_data; -- cgit v1.2.3 From e081685c1bbe8da37c7f61726fdb783ff277f14f Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 20 Oct 2010 09:59:33 -0500 Subject: ssb: Clear RETRY_TIMEOUT in PCI Configuration for normal devices MMIO log traces obtained using the Broadcom wl hybrid driver show that the RETRY_TIMEOUT register (0x41) in PCI configuration space is cleared if non-zero. Similar code found in other drivers such as ipw2100 show this operation is needed to keep PCI Tx retries from interfering with C3 CPU state. There are no known cases where omission of this code has caused a problem, but this patch is offered just in case such a situation occurs. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/ssb/pcihost_wrapper.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index 6536a041d90d..f6c8c81a0025 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -59,6 +59,7 @@ static int ssb_pcihost_probe(struct pci_dev *dev, struct ssb_bus *ssb; int err = -ENOMEM; const char *name; + u32 val; ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); if (!ssb) @@ -74,6 +75,12 @@ static int ssb_pcihost_probe(struct pci_dev *dev, goto err_pci_disable; pci_set_master(dev); + /* Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + err = ssb_bus_pcibus_register(ssb, dev); if (err) goto err_pci_release_regions; -- cgit v1.2.3 From b87b0128894efd3bbf7272a579f71b3a2bc500d1 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 21 Oct 2010 12:10:11 -0700 Subject: ath: add a ATH_DBG_WARN() To be used to throw out warnings only for developers. This can be used by some corner cases that developers already know can be hit but developers want to address so to avoid spewing out a warning this can only be enabled with CONFIG_ATH_DEBUG enabled. Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/debug.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/debug.h b/drivers/net/wireless/ath/debug.h index 64e4af2c2887..f207007ee391 100644 --- a/drivers/net/wireless/ath/debug.h +++ b/drivers/net/wireless/ath/debug.h @@ -70,11 +70,13 @@ enum ATH_DEBUG { #ifdef CONFIG_ATH_DEBUG void ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) __attribute__ ((format (printf, 3, 4))); +#define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) #else static inline void __attribute__ ((format (printf, 3, 4))) ath_print(struct ath_common *common, int dbg_mask, const char *fmt, ...) { } +#define ATH_DBG_WARN(foo, arg) #endif /* CONFIG_ATH_DEBUG */ /** Returns string describing opmode, or NULL if unknown mode. */ -- cgit v1.2.3 From 78a7685e1e44c6d4b6f79c73687b9322e40b040e Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 20 Oct 2010 16:07:08 -0700 Subject: ath9k: add a debug warning when we cannot stop RX We have seen several DMA races when we race against stopping and starting the PCU. I suspect that when we cannot stop the PCU we may hit some of these same races so warn against them for now but only when debugging (CONFIG_ATH_DEBUG) is enabled. If you run into this warning and are a developer, please fix the cause of the warning. The potential here, although I cannot prove yet, is that the DMA engine can be confused and start writing to a buffer that was already DMA'd before and at least the kernel assumes is not being accessed by hardware anymore. Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index c04a940550bd..87fabf84e6fb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -528,6 +528,8 @@ bool ath_stoprecv(struct ath_softc *sc) sc->rx.rxlink = NULL; spin_unlock_bh(&sc->rx.rxbuflock); + ATH_DBG_WARN(!stopped, "Could not stop RX, we could be " + "confusing the DMA engine when we start RX up\n"); return stopped; } -- cgit v1.2.3 From ff32d9cd2c4107224a28f39d3c72eec66d566e09 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 21 Oct 2010 02:47:23 +0200 Subject: ath9k_hw: fix potential spurious tx error bit interpretation According to documentation, AR_ExcessiveRetries, AR_Filtered and AR_FIFOUnderrun are only valid if AR_FrmXmitOK is clear. Not checking this might result in suboptimal FIFO settings, unnecessary retransmissions, or other connectivity issues. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_mac.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 3b4c52c9181c..f0268e5eab34 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -237,13 +237,15 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, status = ACCESS_ONCE(ads->ds_txstatus1); if (status & AR_FrmXmitOK) ts->ts_status |= ATH9K_TX_ACKED; - if (status & AR_ExcessiveRetries) - ts->ts_status |= ATH9K_TXERR_XRETRY; - if (status & AR_Filtered) - ts->ts_status |= ATH9K_TXERR_FILT; - if (status & AR_FIFOUnderrun) { - ts->ts_status |= ATH9K_TXERR_FIFO; - ath9k_hw_updatetxtriglevel(ah, true); + else { + if (status & AR_ExcessiveRetries) + ts->ts_status |= ATH9K_TXERR_XRETRY; + if (status & AR_Filtered) + ts->ts_status |= ATH9K_TXERR_FILT; + if (status & AR_FIFOUnderrun) { + ts->ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } } if (status & AR_TxTimerExpired) ts->ts_status |= ATH9K_TXERR_TIMER_EXPIRED; -- cgit v1.2.3 From 4beeba7dc59cc10d6a47346c857d1a64a9ec9642 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 25 Oct 2010 10:34:50 +0200 Subject: iwlwifi: warn when send tx power settings during scan Add WARN_ONCE when scanning is pending. Use STATUS_SCAN_HW bit since we can have scan canceled or completed but STATUS_SCANNING bit still set. v1 -> v2: replace EIO to EAGAIN Signed-off-by: Stanislaw Gruszka Acked-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-4965.c | 8 ++------ drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 176e52577673..4d7130c9b72c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -1451,6 +1451,10 @@ static int iwl3945_send_tx_power(struct iwl_priv *priv) }; u16 chan; + if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), + "TX Power requested while scanning!\n")) + return -EAGAIN; + chan = le16_to_cpu(priv->contexts[IWL_RXON_CTX_BSS].active.channel); txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index b207e3e9299f..ee9c582c8cf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1377,13 +1377,9 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) u8 ctrl_chan_high = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - if (test_bit(STATUS_SCANNING, &priv->status)) { - /* If this gets hit a lot, switch it to a BUG() and catch - * the stack trace to find out who is calling this during - * a scan. */ - IWL_WARN(priv, "TX Power requested while scanning!\n"); + if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), + "TX Power requested while scanning!\n")) return -EAGAIN; - } band = priv->band == IEEE80211_BAND_2GHZ; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index b555edd53354..5e3d799ea3b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -496,6 +496,10 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) struct iwlagn_tx_power_dbm_cmd tx_power_cmd; u8 tx_ant_cfg_cmd; + if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), + "TX Power requested while scanning!\n")) + return -EAGAIN; + /* half dBm need to multiply */ tx_power_cmd.global_lmt = (s8)(2 * priv->tx_power_user_lmt); -- cgit v1.2.3 From 4cbf1b12491cd43032846acc6c6924d9090fa19f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:25 +0200 Subject: iwlwifi: send tx_power_cmd synchronously On 5xxx and 6xxx change to send tx_power_cmd command synchronously, to do not start other commands when setting tx power is pending. We currently do the same for 4956 and 3945. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 5e3d799ea3b5..c38daf2d9cfd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -526,9 +526,8 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) else tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; - return iwl_send_cmd_pdu_async(priv, tx_ant_cfg_cmd, - sizeof(tx_power_cmd), &tx_power_cmd, - NULL); + return iwl_send_cmd_pdu(priv, tx_ant_cfg_cmd, sizeof(tx_power_cmd), + &tx_power_cmd); } void iwlagn_temperature(struct iwl_priv *priv) -- cgit v1.2.3 From a25a66ac94db88190653d5725c563e3f8faeee61 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:26 +0200 Subject: iwlwifi: fix set_tx_power vs scan According to comment in iwl_bg_scan_completed, setting tx power should be deferred during pending scan, but we are not doing this. This patch change code to really defer setting tx power after scan complete. Additionally refactor iwl_set_tx_power code and call lib->send_tx_power() directly from iwlagn_commit_rxon. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 10 +++--- drivers/net/wireless/iwlwifi/iwl-core.c | 54 ++++++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-dev.h | 1 + drivers/net/wireless/iwlwifi/iwl-scan.c | 10 +++--- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 5 files changed, 42 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c2636a7ab9ee..d3435c430273 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -245,13 +245,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) /* 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 */ - ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); - if (ret) { + ret = priv->cfg->ops->lib->send_tx_power(priv); + if (ret) IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } - - return 0; + return ret; } void iwl_update_chain_flags(struct iwl_priv *priv) @@ -4179,6 +4176,7 @@ static int iwl_init_drv(struct iwl_priv *priv) * this value will get overwritten by channel max power avg * from eeprom */ priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; + priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; ret = iwl_init_channel_map(priv); if (ret) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 25fb3912342c..8bbd152617fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1206,8 +1206,16 @@ EXPORT_SYMBOL(iwl_apm_init); int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) { - int ret = 0; - s8 prev_tx_power = priv->tx_power_user_lmt; + int ret; + s8 prev_tx_power; + + lockdep_assert_held(&priv->mutex); + + if (priv->tx_power_user_lmt == tx_power && !force) + return 0; + + if (!priv->cfg->ops->lib->send_tx_power) + return -EOPNOTSUPP; if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) { IWL_WARN(priv, @@ -1224,30 +1232,26 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (priv->tx_power_user_lmt != tx_power) - force = true; + if (!iwl_is_ready_rf(priv)) + return -EIO; - /* if nic is not up don't send command */ - if (iwl_is_ready_rf(priv)) { - priv->tx_power_user_lmt = tx_power; - if (force && priv->cfg->ops->lib->send_tx_power) - ret = priv->cfg->ops->lib->send_tx_power(priv); - else if (!priv->cfg->ops->lib->send_tx_power) - ret = -EOPNOTSUPP; - /* - * if fail to set tx_power, restore the orig. tx power - */ - if (ret) - priv->tx_power_user_lmt = prev_tx_power; + /* scan complete use tx_power_next, need to be updated */ + priv->tx_power_next = tx_power; + if (test_bit(STATUS_SCANNING, &priv->status) && !force) { + IWL_DEBUG_INFO(priv, "Deferring tx power set while scanning\n"); + return 0; } - /* - * Even this is an async host command, the command - * will always report success from uCode - * So once driver can placing the command into the queue - * successfully, driver can use priv->tx_power_user_lmt - * to reflect the current tx power - */ + prev_tx_power = priv->tx_power_user_lmt; + priv->tx_power_user_lmt = tx_power; + + ret = priv->cfg->ops->lib->send_tx_power(priv); + + /* if fail to set tx_power, restore the orig. tx power */ + if (ret) { + priv->tx_power_user_lmt = prev_tx_power; + priv->tx_power_next = prev_tx_power; + } return ret; } EXPORT_SYMBOL(iwl_set_tx_power); @@ -2016,7 +2020,9 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", priv->tx_power_user_lmt, conf->power_level); - iwl_set_tx_power(priv, conf->power_level, false); + ret = iwl_set_tx_power(priv, conf->power_level, false); + if (ret) + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); } if (!iwl_is_ready(priv)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 70e07fa48405..cd6daed99931 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1517,6 +1517,7 @@ struct iwl_priv { s8 tx_power_user_lmt; s8 tx_power_device_lmt; s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */ + s8 tx_power_next; #ifdef CONFIG_IWLWIFI_DEBUG diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 67da31295781..d63e30e1106a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -603,13 +603,15 @@ out_settings: if (!iwl_is_ready_rf(priv)) goto out; - /* Since setting the TXPOWER may have been deferred while - * performing the scan, fire one off */ - iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + /* + * We do not commit power settings while scan is pending, + * do it now if the settings changed. + */ + iwl_set_tx_power(priv, priv->tx_power_next, false); priv->cfg->ops->utils->post_scan(priv); - out: +out: mutex_unlock(&priv->mutex); } diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 8f8c4b73f8b9..a75429171c46 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3866,6 +3866,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF; priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; + priv->tx_power_next = IWL_DEFAULT_TX_POWER; if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n", -- cgit v1.2.3 From 749ff4efa14df904c22b28e2f7b10a02119a4d5e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:27 +0200 Subject: iwlwifi: avoid commit rxon during scan in iwlagn_configure_filter Almost anywhere in the code we avoid committing rxon while performing scan, and make rxon commit when scan complete. However in some places in the code we do not follow that rule. This patch fix that problem in iwlagn_configure_filter(). Since we do not commit directly in iwl3945_configure_filter, we can also do the same for agn, so I just remove iwlcore_commit_rxon() function and add a comment. Also change comment for iwl3945. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d3435c430273..0ba8083ee4cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3983,7 +3983,11 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, for_each_context(priv, ctx) { ctx->staging.filter_flags &= ~filter_nand; ctx->staging.filter_flags |= filter_or; - iwlcore_commit_rxon(priv, ctx); + + /* + * Not committing directly because hardware can perform a scan, + * but we'll eventually commit the filter flags change anyway. + */ } mutex_unlock(&priv->mutex); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index a75429171c46..3b8bf8686276 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3407,9 +3407,9 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, ctx->staging.filter_flags |= filter_or; /* - * Committing directly here breaks for some reason, - * but we'll eventually commit the filter flags - * change anyway. + * Not committing directly because hardware can perform a scan, + * but even if hw is ready, committing here breaks for some reason, + * we'll eventually commit the filter flags change anyway. */ mutex_unlock(&priv->mutex); -- cgit v1.2.3 From 5eda74a40587139b1d66cd8197cac92ba36e79f4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:28 +0200 Subject: iwlwifi: avoid commit rxon during scan in iwlagn_bt_traffic_change_work Avoid sending commands to firmware (including commit_rxon) when scan is pending and we are calling iwlagn_bt_traffic_change_work simultaneously. Also comment some innocent race conditions. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index c38daf2d9cfd..b01d81a3550b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1887,6 +1887,11 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) struct iwl_rxon_context *ctx; int smps_request = -1; + /* + * Note: bt_traffic_load can be overridden by scan complete and + * coex profile notifications. Ignore that since only bad consequence + * can be not matching debug print with actual state. + */ IWL_DEBUG_INFO(priv, "BT traffic load changes: %d\n", priv->bt_traffic_load); @@ -1909,6 +1914,16 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) mutex_lock(&priv->mutex); + /* + * We can not send command to firmware while scanning. When the scan + * complete we will schedule this work again. We do check with mutex + * locked to prevent new scan request to arrive. We do not check + * STATUS_SCANNING to avoid race when queue_work two times from + * different notifications, but quit and not perform any work at all. + */ + if (test_bit(STATUS_SCAN_HW, &priv->status)) + goto out; + if (priv->cfg->ops->lib->update_chain_flags) priv->cfg->ops->lib->update_chain_flags(priv); @@ -1918,7 +1933,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) ieee80211_request_smps(ctx->vif, smps_request); } } - +out: mutex_unlock(&priv->mutex); } -- cgit v1.2.3 From ac4f5457c7617999967e9740f8903b922714bab4 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:29 +0200 Subject: iwlwifi: defer update power mode while scan Do not set power mode when scanning, and defer that when scan finish. We still set power mode in force case i.e. when device is overheated. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-power.c | 95 ++++++++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-power.h | 3 + drivers/net/wireless/iwlwifi/iwl-scan.c | 1 + 3 files changed, 64 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 49d7788937a9..b7abd86676fd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -263,70 +263,95 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) sizeof(struct iwl_powertable_cmd), cmd); } -/* priv->mutex must be held */ -int iwl_power_update_mode(struct iwl_priv *priv, bool force) +static void iwl_power_build_cmd(struct iwl_priv *priv, + struct iwl_powertable_cmd *cmd) { - int ret = 0; bool enabled = priv->hw->conf.flags & IEEE80211_CONF_PS; - bool update_chains; - struct iwl_powertable_cmd cmd; int dtimper; - /* Don't update the RX chain when chain noise calibration is running */ - update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || - priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; - dtimper = priv->hw->conf.ps_dtim_period ?: 1; if (priv->cfg->base_params->broken_powersave) - iwl_power_sleep_cam_cmd(priv, &cmd); + iwl_power_sleep_cam_cmd(priv, cmd); else if (priv->cfg->base_params->supports_idle && priv->hw->conf.flags & IEEE80211_CONF_IDLE) - iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_5, 20); + iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (priv->cfg->ops->lib->tt_ops.lower_power_detection && priv->cfg->ops->lib->tt_ops.tt_power_mode && priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) { /* in thermal throttling low power state */ - iwl_static_sleep_cmd(priv, &cmd, + iwl_static_sleep_cmd(priv, cmd, priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper); } else if (!enabled) - iwl_power_sleep_cam_cmd(priv, &cmd); + iwl_power_sleep_cam_cmd(priv, cmd); else if (priv->power_data.debug_sleep_level_override >= 0) - iwl_static_sleep_cmd(priv, &cmd, + iwl_static_sleep_cmd(priv, cmd, priv->power_data.debug_sleep_level_override, dtimper); else if (no_sleep_autoadjust) - iwl_static_sleep_cmd(priv, &cmd, IWL_POWER_INDEX_1, dtimper); + iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper); else - iwl_power_fill_sleep_cmd(priv, &cmd, + iwl_power_fill_sleep_cmd(priv, cmd, priv->hw->conf.dynamic_ps_timeout, priv->hw->conf.max_sleep_period); +} + +int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, + bool force) +{ + int ret; + bool update_chains; + + lockdep_assert_held(&priv->mutex); + + /* Don't update the RX chain when chain noise calibration is running */ + update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || + priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; + + if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) + return 0; + + if (!iwl_is_ready_rf(priv)) + return -EIO; + + /* scan complete use sleep_power_next, need to be updated */ + memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); + if (test_bit(STATUS_SCANNING, &priv->status) && !force) { + IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n"); + return 0; + } + + if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) + set_bit(STATUS_POWER_PMI, &priv->status); - if (iwl_is_ready_rf(priv) && - (memcmp(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)) || force)) { - if (cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) - set_bit(STATUS_POWER_PMI, &priv->status); - - ret = iwl_set_power(priv, &cmd); - if (!ret) { - if (!(cmd.flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) - clear_bit(STATUS_POWER_PMI, &priv->status); - - if (priv->cfg->ops->lib->update_chain_flags && - update_chains) - priv->cfg->ops->lib->update_chain_flags(priv); - else if (priv->cfg->ops->lib->update_chain_flags) - IWL_DEBUG_POWER(priv, + ret = iwl_set_power(priv, cmd); + if (!ret) { + if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) + clear_bit(STATUS_POWER_PMI, &priv->status); + + if (priv->cfg->ops->lib->update_chain_flags && update_chains) + priv->cfg->ops->lib->update_chain_flags(priv); + else if (priv->cfg->ops->lib->update_chain_flags) + IWL_DEBUG_POWER(priv, "Cannot update the power, chain noise " "calibration running: %d\n", priv->chain_noise_data.state); - memcpy(&priv->power_data.sleep_cmd, &cmd, sizeof(cmd)); - } else - IWL_ERR(priv, "set power fail, ret = %d", ret); - } + + memcpy(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)); + } else + IWL_ERR(priv, "set power fail, ret = %d", ret); return ret; } +EXPORT_SYMBOL(iwl_power_set_mode); + +int iwl_power_update_mode(struct iwl_priv *priv, bool force) +{ + struct iwl_powertable_cmd cmd; + + iwl_power_build_cmd(priv, &cmd); + return iwl_power_set_mode(priv, &cmd, force); +} EXPORT_SYMBOL(iwl_power_update_mode); /* initialize to default */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df81565a7cc4..fe012032c28c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -41,10 +41,13 @@ enum iwl_power_level { struct iwl_power_mgr { struct iwl_powertable_cmd sleep_cmd; + struct iwl_powertable_cmd sleep_cmd_next; int debug_sleep_level_override; bool pci_pm; }; +int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, + bool force); int iwl_power_update_mode(struct iwl_priv *priv, bool force); void iwl_power_initialize(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index d63e30e1106a..e1aa0e1daa5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -607,6 +607,7 @@ out_settings: * We do not commit power settings while scan is pending, * do it now if the settings changed. */ + iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false); iwl_set_tx_power(priv, priv->tx_power_next, false); priv->cfg->ops->utils->post_scan(priv); -- cgit v1.2.3 From 3eb9616af24d6a1910ae6ae5c2d51719eba960cf Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 22 Oct 2010 17:04:30 +0200 Subject: iwlwifi: avoid commit rxon during scan in iwl_set_no_assoc Currently we are canceling scan when changing BSSID. Behave the same when changing association and beacon enablement, to avoid committing rxon during scan in iwl_set_no_assoc(). Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 8bbd152617fc..87c18001d2c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1590,6 +1590,19 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + if (changes & (BSS_CHANGED_BSSID | BSS_CHANGED_ASSOC | + BSS_CHANGED_BEACON_ENABLED)) { + /* + * If there is currently a HW scan going on in the + * background then we need to cancel it else the RXON + * below in post_associate or set_no_assoc can fail. + */ + if (iwl_scan_cancel_timeout(priv, 200)) { + IWL_WARN(priv, "Can not cancel scan\n"); + goto out; + } + } + if (changes & BSS_CHANGED_QOS) { unsigned long flags; @@ -1622,18 +1635,6 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_BSSID) { IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); - /* - * If there is currently a HW scan going on in the - * background then we need to cancel it else the RXON - * below/in post_associate will fail. - */ - 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"); - mutex_unlock(&priv->mutex); - return; - } - /* mac80211 only sets assoc when in STATION mode */ if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { memcpy(ctx->staging.bssid_addr, @@ -1752,6 +1753,7 @@ void iwl_bss_info_changed(struct ieee80211_hw *hw, IWL_ERR(priv, "failed to update PAN params\n"); } +out: mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); -- cgit v1.2.3 From c0b102c20972cfa3e10a0cf4a2a563edb70961b1 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 22 Oct 2010 17:43:46 +0200 Subject: b43: N-PHY: fix 2055 radio init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/radio_2055.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c index 1b5316586cbf..0d6771515bce 100644 --- a/drivers/net/wireless/b43/radio_2055.c +++ b/drivers/net/wireless/b43/radio_2055.c @@ -244,7 +244,7 @@ static const struct b2055_inittab_entry b2055_inittab [] = { [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCE] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, @@ -256,7 +256,7 @@ static const struct b2055_inittab_entry b2055_inittab [] = { [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, - [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDA] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, @@ -1299,7 +1299,7 @@ void b2055_upload_inittab(struct b43_wldev *dev, bool ghz5, bool ignore_uploadflag) { const struct b2055_inittab_entry *e; - unsigned int i; + unsigned int i, writes = 0; u16 value; for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) { @@ -1312,6 +1312,8 @@ void b2055_upload_inittab(struct b43_wldev *dev, else value = e->ghz2; b43_radio_write16(dev, i, value); + if (++writes % 4 == 0) + b43_read32(dev, B43_MMIO_MACCTL); /* flush */ } } } -- cgit v1.2.3 From 7e6da2bfc05c2b96197c12484f3d071fe0c6d0fb Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 22 Oct 2010 17:43:47 +0200 Subject: b43: define known SPROM boardflags2 bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/b43.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 72821c456b02..9aad2ca3c112 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -153,6 +153,19 @@ #define B43_BFH_FEM_BT 0x0040 /* has FEM and switch to share antenna * with bluetooth */ +/* SPROM boardflags2_lo values */ +#define B43_BFL2_RXBB_INT_REG_DIS 0x0001 /* external RX BB regulator present */ +#define B43_BFL2_APLL_WAR 0x0002 /* alternative A-band PLL settings implemented */ +#define B43_BFL2_TXPWRCTRL_EN 0x0004 /* permits enabling TX Power Control */ +#define B43_BFL2_2X4_DIV 0x0008 /* 2x4 diversity switch */ +#define B43_BFL2_5G_PWRGAIN 0x0010 /* supports 5G band power gain */ +#define B43_BFL2_PCIEWAR_OVR 0x0020 /* overrides ASPM and Clkreq settings */ +#define B43_BFL2_CAESERS_BRD 0x0040 /* is Caesers board (unused) */ +#define B43_BFL2_BTC3WIRE 0x0080 /* used 3-wire bluetooth coexist */ +#define B43_BFL2_SKWRKFEM_BRD 0x0100 /* 4321mcm93 uses Skyworks FEM */ +#define B43_BFL2_SPUR_WAR 0x0200 /* has a workaround for clock-harmonic spurs */ +#define B43_BFL2_GPLL_WAR 0x0400 /* altenative G-band PLL settings implemented */ + /* GPIO register offset, in both ChipCommon and PCI core. */ #define B43_GPIO_CONTROL 0x6c -- cgit v1.2.3 From 7a4db8f5c37d1acf1213b835b3cdd8f7c051eb9b Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 22 Oct 2010 17:43:48 +0200 Subject: b43: N-PHY: determine usage of radio regulatory workaround correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index e0f2d122e124..c22dbfb987de 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -191,7 +191,8 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) binfo->type != 0x46D || binfo->rev < 0x41); else - workaround = ((sprom->boardflags_hi & B43_BFH_NOPA) == 0); + workaround = + !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS); b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); if (workaround) { -- cgit v1.2.3 From a2d9bc6fdc0c8693b5641c69bce7eaf5b47f0593 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Fri, 22 Oct 2010 17:43:49 +0200 Subject: b43: N-PHY: improve 2055 radio initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1) Upload 5 GHz values when needed. 2) Do not upload all values on first init. Follow wl. Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/phy_n.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index c22dbfb987de..6facb8ab05d1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -241,10 +241,13 @@ static void b43_radio_init2055_post(struct b43_wldev *dev) static void b43_radio_init2055(struct b43_wldev *dev) { b43_radio_init2055_pre(dev); - if (b43_status(dev) < B43_STAT_INITIALIZED) - b2055_upload_inittab(dev, 0, 1); - else - b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0); + if (b43_status(dev) < B43_STAT_INITIALIZED) { + /* Follow wl, not specs. Do not force uploading all regs */ + b2055_upload_inittab(dev, 0, 0); + } else { + bool ghz5 = b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ; + b2055_upload_inittab(dev, ghz5, 0); + } b43_radio_init2055_post(dev); } -- cgit v1.2.3 From 8e7ce8930165c785ec1c754ef3e3092a3bdffe02 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 23 Oct 2010 19:51:32 +0200 Subject: carl9170: fix typos Signed-off-by: Hauke Mehrtens Acked-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/carl9170.h | 2 +- drivers/net/wireless/ath/carl9170/main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 6cf0c9ef47aa..b69d31972c77 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -48,7 +48,7 @@ #include #ifdef CONFIG_CARL9170_LEDS #include -#endif /* CONFIG_CARL170_LEDS */ +#endif /* CONFIG_CARL9170_LEDS */ #ifdef CONFIG_CARL9170_WPC #include #endif /* CONFIG_CARL9170_WPC */ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 980ae70ea424..d521bc2b0496 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1828,7 +1828,7 @@ int carl9170_register(struct ar9170 *ar) err = carl9170_led_register(ar); if (err) goto err_unreg; -#endif /* CONFIG_CAR9L170_LEDS */ +#endif /* CONFIG_CARL9170_LEDS */ #ifdef CONFIG_CARL9170_WPC err = carl9170_register_wps_button(ar); -- cgit v1.2.3 From 26f94dc264a7ebddcc08d3908e99880703d871e5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 25 Oct 2010 10:24:09 -0400 Subject: b43: remove extraneous code in free_ringmemory This code seems to have been cut-n-pasted from alloc_ringmemory? Anyway, it is useless. Signed-off-by: John W. Linville --- drivers/net/wireless/b43/dma.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 10d0aaf754c5..3d5566e7af0a 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -415,11 +415,6 @@ static int alloc_ringmemory(struct b43_dmaring *ring) static void free_ringmemory(struct b43_dmaring *ring) { - gfp_t flags = GFP_KERNEL; - - if (ring->type == B43_DMA_64BIT) - flags |= GFP_DMA; - dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE, ring->descbase, ring->dmabase); } -- cgit v1.2.3 From b9237578f8d685bb86901ba9ff0d379218e5a3c5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 25 Oct 2010 10:33:07 -0400 Subject: rt2x00pci: do not use GFP_DMA Signed-off-by: John W. Linville Acked-by: Ivo van Doorn --- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 2449d785cf8d..868ca19b13ea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -105,7 +105,7 @@ static int rt2x00pci_alloc_queue_dma(struct rt2x00_dev *rt2x00dev, */ addr = dma_alloc_coherent(rt2x00dev->dev, queue->limit * queue->desc_size, - &dma, GFP_KERNEL | GFP_DMA); + &dma, GFP_KERNEL); if (!addr) return -ENOMEM; -- cgit v1.2.3 From f60dc0138aa19769bf8bab9f93b043235428b66f Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 25 Oct 2010 16:12:37 -0400 Subject: iwlwifi: Convert to new PCI PM framework Use the new PCI PM and let the PCI core code handle the PCI-specific details of power transitions. Based on similarly titled ath9k patch posted by Rafael J. Wysocki. Signed-off-by: John W. Linville Acked-by: Rafael J. Wysocki Acked-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +---- drivers/net/wireless/iwlwifi/iwl-core.c | 26 ++++++++++++++------------ drivers/net/wireless/iwlwifi/iwl-core.h | 14 +++++++++++--- drivers/net/wireless/iwlwifi/iwl3945-base.c | 5 +---- 4 files changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0ba8083ee4cd..0027bb8299a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4838,10 +4838,7 @@ static struct pci_driver iwl_driver = { .id_table = iwl_hw_card_ids, .probe = iwl_pci_probe, .remove = __devexit_p(iwl_pci_remove), -#ifdef CONFIG_PM - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, -#endif + .driver.pm = IWL_PM_OPS, }; static int __init iwl_init(void) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 87c18001d2c0..2a4d40e5b9f4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -2592,8 +2592,9 @@ EXPORT_SYMBOL(iwl_add_beacon_time); #ifdef CONFIG_PM -int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +int iwl_pci_suspend(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct iwl_priv *priv = pci_get_drvdata(pdev); /* @@ -2605,18 +2606,14 @@ int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) */ iwl_apm_stop(priv); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; } EXPORT_SYMBOL(iwl_pci_suspend); -int iwl_pci_resume(struct pci_dev *pdev) +int iwl_pci_resume(struct device *device) { + struct pci_dev *pdev = to_pci_dev(device); struct iwl_priv *priv = pci_get_drvdata(pdev); - int ret; bool hw_rfkill = false; /* @@ -2625,11 +2622,6 @@ int iwl_pci_resume(struct pci_dev *pdev) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_restore_state(pdev); iwl_enable_interrupts(priv); if (!(iwl_read32(priv, CSR_GP_CNTRL) & @@ -2647,4 +2639,14 @@ int iwl_pci_resume(struct pci_dev *pdev) } EXPORT_SYMBOL(iwl_pci_resume); +const struct dev_pm_ops iwl_pm_ops = { + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, + .freeze = iwl_pci_suspend, + .thaw = iwl_pci_resume, + .poweroff = iwl_pci_suspend, + .restore = iwl_pci_resume, +}; +EXPORT_SYMBOL(iwl_pm_ops); + #endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 64527def059f..b17de8214eb5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -615,9 +615,17 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, u32 addon, u32 beacon_interval); #ifdef CONFIG_PM -int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state); -int iwl_pci_resume(struct pci_dev *pdev); -#endif /* CONFIG_PM */ +int iwl_pci_suspend(struct device *device); +int iwl_pci_resume(struct device *device); +extern const struct dev_pm_ops iwl_pm_ops; + +#define IWL_PM_OPS (&iwl_pm_ops) + +#else /* !CONFIG_PM */ + +#define IWL_PM_OPS NULL + +#endif /* !CONFIG_PM */ /***************************************************** * Error Handling Debugging diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 3b8bf8686276..9b71921dc2b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4275,10 +4275,7 @@ static struct pci_driver iwl3945_driver = { .id_table = iwl3945_hw_card_ids, .probe = iwl3945_pci_probe, .remove = __devexit_p(iwl3945_pci_remove), -#ifdef CONFIG_PM - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, -#endif + .driver.pm = IWL_PM_OPS, }; static int __init iwl3945_init(void) -- cgit v1.2.3 From 446fad5a5b6be765c8ec39bfdbbc6c7aa63fbcbb Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 26 Oct 2010 20:11:29 +0530 Subject: ath9k_htc: Handle monitor mode properly for HTC devices No need to inform about monitor interface changes to firmware. Set the HW mode to monitor type based on mac80211 indication flag is sufficient. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 64 +++------------------------ 1 file changed, 5 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 8266ce1f02e3..e9761c2c8700 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -184,47 +184,6 @@ err: return ret; } -static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_htc_target_vif hvif; - int ret = 0; - u8 cmd_rsp; - - if (priv->nvifs > 0) - return -ENOBUFS; - - memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); - memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); - - hvif.opmode = cpu_to_be32(HTC_M_MONITOR); - priv->ah->opmode = NL80211_IFTYPE_MONITOR; - hvif.index = priv->nvifs; - - WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif); - if (ret) - return ret; - - priv->nvifs++; - return 0; -} - -static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - struct ath9k_htc_target_vif hvif; - int ret = 0; - u8 cmd_rsp; - - memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif)); - memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); - hvif.index = 0; /* Should do for now */ - WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); - priv->nvifs--; - - return ret; -} - static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -1240,16 +1199,6 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) WMI_CMD(WMI_STOP_RECV_CMDID); skb_queue_purge(&priv->tx_queue); - /* Remove monitor interface here */ - if (ah->opmode == NL80211_IFTYPE_MONITOR) { - if (ath9k_htc_remove_monitor_interface(priv)) - ath_print(common, ATH_DBG_FATAL, - "Unable to remove monitor interface\n"); - else - ath_print(common, ATH_DBG_CONFIG, - "Monitor interface removed\n"); - } - if (ah->btcoex_hw.enabled) { ath9k_hw_btcoex_disable(ah); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) @@ -1423,16 +1372,13 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) } } - if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + if (changed & IEEE80211_CONF_CHANGE_MONITOR) if (conf->flags & IEEE80211_CONF_MONITOR) { - if (ath9k_htc_add_monitor_interface(priv)) - ath_print(common, ATH_DBG_FATAL, - "Failed to set monitor mode\n"); - else - ath_print(common, ATH_DBG_CONFIG, - "HW opmode set to Monitor mode\n"); + ath_print(common, ATH_DBG_CONFIG, + "HW opmode set to Monitor mode\n"); + priv->ah->opmode = NL80211_IFTYPE_MONITOR; } - } + if (changed & IEEE80211_CONF_CHANGE_IDLE) { mutex_lock(&priv->htc_pm_lock); -- cgit v1.2.3 From 5d4c428254f73bae272be9d296724b1ee09d76ec Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Tue, 26 Oct 2010 21:28:57 +0530 Subject: ath9k: Properly assign boolean types This takes care that boolean types are properly assigned Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 1095e18b3627..85c8e9310cae 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1425,12 +1425,12 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, ath_rc_priv->neg_ht_rates.rs_nrates = j; } - is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + is_cw40 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); if (is_cw40) - is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40); else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20) - is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20); /* Choose rate table first */ @@ -1449,10 +1449,8 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, struct ath_rate_priv *ath_rc_priv = priv_sta; const struct ath_rate_table *rate_table = NULL; bool oper_cw40 = false, oper_sgi; - bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? - true : false; - bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? - true : false; + bool local_cw40 = !!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); + bool local_sgi = !!(ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG); /* FIXME: Handle AP mode later when we support CWM */ -- cgit v1.2.3 From 9d94674ab754be0e275120a183670ead435f9c0d Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 26 Oct 2010 15:27:23 -0700 Subject: ath9k: simplify hw reset locking The new PCU lock is better placed so we can just contend against that when trying to reset hardware. This is part of a series of patches which fix stopping TX DMA completley when requested on the driver. For more details about this issue refer to this thread: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Tested-by: Ben Greear Cc: Kyungwan Nam Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/init.c | 1 - drivers/net/wireless/ath/ath9k/main.c | 22 ++++++---------------- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 4 files changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 81fed83add7a..cb9194a5b561 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -599,7 +599,6 @@ struct ath_softc { struct ath_hw *sc_ah; void __iomem *mem; int irq; - spinlock_t sc_resetlock; spinlock_t sc_serial_rw; spinlock_t sc_pm_lock; struct mutex mutex; diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1b72720b36e2..adff0da01f4c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -580,7 +580,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, spin_lock_init(&common->cc_lock); spin_lock_init(&sc->wiphy_lock); - spin_lock_init(&sc->sc_resetlock); spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 92ed5bb71196..341d587b686b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -262,19 +262,15 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, channel->center_freq, conf_is_ht40(conf), fastcc); - spin_lock_bh(&sc->sc_resetlock); - r = ath9k_hw_reset(ah, hchan, caldata, fastcc); if (r) { ath_print(common, ATH_DBG_FATAL, "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); - spin_unlock_bh(&sc->sc_resetlock); spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } - spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) { ath_print(common, ATH_DBG_FATAL, @@ -886,7 +882,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ah->curchan = ath_get_curchannel(sc, sc->hw); spin_lock_bh(&sc->rx.pcu_lock); - spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { ath_print(common, ATH_DBG_FATAL, @@ -894,7 +889,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) "reset status %d\n", channel->center_freq, r); } - spin_unlock_bh(&sc->sc_resetlock); ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { @@ -951,7 +945,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) if (!ah->curchan) ah->curchan = ath_get_curchannel(sc, hw); - spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, @@ -959,7 +952,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) "reset status %d\n", channel->center_freq, r); } - spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); @@ -990,12 +982,10 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_stoprecv(sc); ath_flushrecv(sc); - spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); if (r) ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); - spin_unlock_bh(&sc->sc_resetlock); if (ath_startrecv(sc) != 0) ath_print(common, ATH_DBG_FATAL, @@ -1166,18 +1156,15 @@ static int ath9k_start(struct ieee80211_hw *hw) * and then setup of the interrupt mask. */ spin_lock_bh(&sc->rx.pcu_lock); - spin_lock_bh(&sc->sc_resetlock); r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); - spin_unlock_bh(&sc->sc_resetlock); spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } - spin_unlock_bh(&sc->sc_resetlock); /* * This is needed only to setup initial state @@ -1398,14 +1385,17 @@ static void ath9k_stop(struct ieee80211_hw *hw) * before setting the invalid flag. */ ath9k_hw_disable_interrupts(ah); - spin_lock_bh(&sc->rx.pcu_lock); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); + spin_lock_bh(&sc->rx.pcu_lock); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); - } else + spin_unlock_bh(&sc->rx.pcu_lock); + } else { + spin_lock_bh(&sc->rx.pcu_lock); sc->rx.rxlink = NULL; - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->rx.pcu_lock); + } /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f2ade2402ce2..e662ecade398 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1148,13 +1148,13 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA. Resetting hardware!\n"); - spin_lock_bh(&sc->sc_resetlock); + spin_lock_bh(&sc->rx.pcu_lock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); if (r) ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); - spin_unlock_bh(&sc->sc_resetlock); + spin_unlock_bh(&sc->rx.pcu_lock); } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -- cgit v1.2.3 From 4bdd1e978ede034c1211957eb17eaf50de00d234 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 26 Oct 2010 15:27:24 -0700 Subject: ath9k: move the PCU lock to the sc structure The PCU lock should be used to contend TX DMA as well, this will be done next. This is part of a series of patches which fix stopping TX DMA completley when requested on the driver. For more details about this issue refer to this thread: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Tested-by: Ben Greear Cc: Kyungwan Nam Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 42 +++++++++++++++++----------------- drivers/net/wireless/ath/ath9k/recv.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 4 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index cb9194a5b561..61d450750acb 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -309,7 +309,6 @@ struct ath_rx { u8 rxotherant; u32 *rxlink; unsigned int rxfilter; - spinlock_t pcu_lock; spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; @@ -601,6 +600,7 @@ struct ath_softc { int irq; spinlock_t sc_serial_rw; spinlock_t sc_pm_lock; + spinlock_t sc_pcu_lock; struct mutex mutex; struct work_struct paprd_work; struct work_struct hw_check_work; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 341d587b686b..463ac1229f53 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -242,7 +242,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); stopped = ath_stoprecv(sc); @@ -268,7 +268,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); goto ps_restore; } @@ -276,11 +276,11 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); goto ps_restore; } - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -615,7 +615,7 @@ void ath9k_tasklet(unsigned long data) rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); if (status & rxmask) { - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && @@ -623,7 +623,7 @@ void ath9k_tasklet(unsigned long data) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); } if (status & ATH9K_INT_TX) { @@ -881,7 +881,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (!ah->curchan) ah->curchan = ath_get_curchannel(sc, sc->hw); - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { ath_print(common, ATH_DBG_FATAL, @@ -894,10 +894,10 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) if (ath_startrecv(sc) != 0) { ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); return; } - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -937,7 +937,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_drain_all_txq(sc, false); /* clear pending tx frames */ - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ @@ -955,7 +955,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_phy_disable(ah); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_hw_configpcipowersave(ah, 1, 1); ath9k_ps_restore(sc); @@ -977,7 +977,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, retry_tx); - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); ath_stoprecv(sc); ath_flushrecv(sc); @@ -991,7 +991,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); /* * We may be doing a reset in response to a request @@ -1155,14 +1155,14 @@ static int ath9k_start(struct ieee80211_hw *hw) * be followed by initialization of the appropriate bits * and then setup of the interrupt mask. */ - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d " "(freq %u MHz)\n", r, curchan->center_freq); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); goto mutex_unlock; } @@ -1183,10 +1183,10 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); goto mutex_unlock; } - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | @@ -1387,14 +1387,14 @@ static void ath9k_stop(struct ieee80211_hw *hw) if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); } else { - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); sc->rx.rxlink = NULL; - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); } /* disable HAL and put h/w to sleep */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 87fabf84e6fb..60300b225b6d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -317,7 +317,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) struct ath_buf *bf; int error = 0; - spin_lock_init(&sc->rx.pcu_lock); + spin_lock_init(&sc->sc_pcu_lock); sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e662ecade398..d97b7a336b5b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1148,13 +1148,13 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA. Resetting hardware!\n"); - spin_lock_bh(&sc->rx.pcu_lock); + spin_lock_bh(&sc->sc_pcu_lock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); if (r) ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); - spin_unlock_bh(&sc->rx.pcu_lock); + spin_unlock_bh(&sc->sc_pcu_lock); } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -- cgit v1.2.3 From 6a6733f256f18cbcf4875e13f59eedb593b755a8 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 26 Oct 2010 15:27:25 -0700 Subject: ath9k: content DMA start / stop through the PCU lock This helps align resets / RX enable & disable / TX stop / start. Locking around the PCU is important to ensure the hardware doesn't get stale data when working with DMA'able data. This is part of a series of patches which fix stopping TX DMA completley when requested on the driver. For more details about this issue refer to this thread: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Tested-by: Ben Greear Cc: Kyungwan Nam Cc: stable@kernel.org Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 52 +++++++++++++++++------------------ drivers/net/wireless/ath/ath9k/xmit.c | 2 -- 2 files changed, 26 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 463ac1229f53..d522112cf736 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -230,6 +230,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + /* * This is only performed if the channel settings have * actually changed. @@ -242,8 +244,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); - spin_lock_bh(&sc->sc_pcu_lock); - stopped = ath_stoprecv(sc); /* XXX: do not flush receive queue here. We don't want @@ -268,7 +268,6 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, "Unable to reset channel (%u MHz), " "reset status %d\n", channel->center_freq, r); - spin_unlock_bh(&sc->sc_pcu_lock); goto ps_restore; } @@ -276,12 +275,9 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); goto ps_restore; } - spin_unlock_bh(&sc->sc_pcu_lock); - ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -292,6 +288,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, } ps_restore: + spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); return r; } @@ -605,6 +603,8 @@ void ath9k_tasklet(unsigned long data) return; } + spin_lock_bh(&sc->sc_pcu_lock); + if (!ath9k_hw_check_alive(ah)) ieee80211_queue_work(sc->hw, &sc->hw_check_work); @@ -615,15 +615,12 @@ void ath9k_tasklet(unsigned long data) rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); if (status & rxmask) { - spin_lock_bh(&sc->sc_pcu_lock); - /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && (status & ATH9K_INT_RXHP)) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); - spin_unlock_bh(&sc->sc_pcu_lock); } if (status & ATH9K_INT_TX) { @@ -649,6 +646,8 @@ void ath9k_tasklet(unsigned long data) /* re-enable hardware interrupt */ ath9k_hw_enable_interrupts(ah); + + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); } @@ -876,12 +875,13 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) int r; ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + ath9k_hw_configpcipowersave(ah, 0, 0); if (!ah->curchan) ah->curchan = ath_get_curchannel(sc, sc->hw); - spin_lock_bh(&sc->sc_pcu_lock); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { ath_print(common, ATH_DBG_FATAL, @@ -897,8 +897,6 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); return; } - spin_unlock_bh(&sc->sc_pcu_lock); - if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -911,6 +909,8 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_set_gpio(ah, ah->led_pin, 0); ieee80211_wake_queues(hw); + spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); } @@ -921,6 +921,8 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) int r; ath9k_ps_wakeup(sc); + spin_lock_bh(&sc->sc_pcu_lock); + ieee80211_stop_queues(hw); /* @@ -937,8 +939,6 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath_drain_all_txq(sc, false); /* clear pending tx frames */ - spin_lock_bh(&sc->sc_pcu_lock); - ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ @@ -955,10 +955,11 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_phy_disable(ah); - spin_unlock_bh(&sc->sc_pcu_lock); - ath9k_hw_configpcipowersave(ah, 1, 1); + + spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); + ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); } @@ -972,13 +973,13 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) /* Stop ANI */ del_timer_sync(&common->ani.timer); + spin_lock_bh(&sc->sc_pcu_lock); + ieee80211_stop_queues(hw); ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, retry_tx); - spin_lock_bh(&sc->sc_pcu_lock); - ath_stoprecv(sc); ath_flushrecv(sc); @@ -991,8 +992,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); - spin_unlock_bh(&sc->sc_pcu_lock); - /* * We may be doing a reset in response to a request * that changes the channel so update any state that @@ -1017,6 +1016,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } ieee80211_wake_queues(hw); + spin_unlock_bh(&sc->sc_pcu_lock); /* Start ANI */ ath_start_ani(common); @@ -1381,25 +1381,25 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_btcoex_timer_pause(sc); } + spin_lock_bh(&sc->sc_pcu_lock); + /* make sure h/w will not generate any interrupt * before setting the invalid flag. */ ath9k_hw_disable_interrupts(ah); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); - spin_lock_bh(&sc->sc_pcu_lock); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); - spin_unlock_bh(&sc->sc_pcu_lock); - } else { - spin_lock_bh(&sc->sc_pcu_lock); + } else sc->rx.rxlink = NULL; - spin_unlock_bh(&sc->sc_pcu_lock); - } /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); ath9k_hw_configpcipowersave(ah, 1, 1); + + spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); /* Finally, put the chip in FULL SLEEP mode */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d97b7a336b5b..2bc422eb80c7 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1148,13 +1148,11 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) ath_print(common, ATH_DBG_FATAL, "Failed to stop TX DMA. Resetting hardware!\n"); - spin_lock_bh(&sc->sc_pcu_lock); r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); if (r) ath_print(common, ATH_DBG_FATAL, "Unable to reset hardware; reset status %d\n", r); - spin_unlock_bh(&sc->sc_pcu_lock); } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -- cgit v1.2.3 From dc21b5453249e7e9b8878fab356fd60b731cf04d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Oct 2010 09:15:39 -0700 Subject: iwlwifi: make mac80211 ops a device config In the future, 4965 and modern AGN devices will need to have different mac80211 callbacks since they have different capabilities. Prepare for that by making the mac80211 operations a device config. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-1000.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-3945.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ drivers/net/wireless/iwlwifi/iwl-6000.c | 4 ++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 6 +++--- drivers/net/wireless/iwlwifi/iwl-agn.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-core.c | 10 +++++----- drivers/net/wireless/iwlwifi/iwl-core.h | 4 ++-- drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++-- 11 files changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index db540910b110..4266c855a767 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -243,6 +243,7 @@ static const struct iwl_ops iwl1000_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl1000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 4d7130c9b72c..95fed1158452 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2753,6 +2753,7 @@ static const struct iwl_ops iwl3945_ops = { .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, .led = &iwl3945_led_ops, + .ieee80211_ops = &iwl3945_hw_ops, }; static struct iwl_base_params iwl3945_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 09391f0ee61f..b27f07cbf355 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -282,6 +282,8 @@ extern int iwl3945_commit_rxon(struct iwl_priv *priv, */ extern u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *bssid); +extern struct ieee80211_ops iwl3945_hw_ops; + /* * Forward declare iwl-3945.c functions for iwl-base.c */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index ee9c582c8cf2..7921a910b34a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2305,6 +2305,7 @@ static const struct iwl_ops iwl4965_ops = { .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl4965_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index fd9fbc93ea1b..5f0327721692 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -485,6 +485,7 @@ static const struct iwl_ops iwl5000_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl5150_ops = { @@ -492,6 +493,7 @@ static const struct iwl_ops iwl5150_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl5000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 11e6532fc573..85bde701351e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -439,6 +439,7 @@ static const struct iwl_ops iwl6000_ops = { .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6050_ops = { @@ -447,6 +448,7 @@ static const struct iwl_ops iwl6050_ops = { .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, .nic = &iwl6050_nic_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6050g2_ops = { @@ -455,6 +457,7 @@ static const struct iwl_ops iwl6050g2_ops = { .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, .nic = &iwl6050g2_nic_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static const struct iwl_ops iwl6000g2b_ops = { @@ -462,6 +465,7 @@ static const struct iwl_ops iwl6000g2b_ops = { .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, .led = &iwlagn_led_ops, + .ieee80211_ops = &iwlagn_hw_ops, }; static struct iwl_base_params iwl6000_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 0027bb8299a8..e3533a89ec9c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4211,7 +4211,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kfree(priv->scan_cmd); } -static struct ieee80211_ops iwl_hw_ops = { +struct ieee80211_ops iwlagn_hw_ops = { .tx = iwl_mac_tx, .start = iwl_mac_start, .stop = iwl_mac_stop, @@ -4300,10 +4300,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (cfg->mod_params->disable_hw_scan) { dev_printk(KERN_DEBUG, &(pdev->dev), "sw scan support is deprecated\n"); - iwl_hw_ops.hw_scan = NULL; + iwlagn_hw_ops.hw_scan = NULL; } - hw = iwl_alloc_all(cfg, &iwl_hw_ops); + hw = iwl_alloc_all(cfg); if (!hw) { err = -ENOMEM; goto out; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index f525d55f2c0f..ba88e78e6116 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -102,6 +102,8 @@ extern struct iwl_hcmd_ops iwlagn_hcmd; extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; +extern struct ieee80211_ops iwlagn_hw_ops; + int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); int iwl_alloc_isr_ict(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 2a4d40e5b9f4..c93368083e1a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -77,15 +77,15 @@ EXPORT_SYMBOL(iwl_bcast_addr); /* This function both allocates and initializes hw and priv. */ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, - struct ieee80211_ops *hw_ops) +struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) { struct iwl_priv *priv; - /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ - struct ieee80211_hw *hw = - ieee80211_alloc_hw(sizeof(struct iwl_priv), hw_ops); + struct ieee80211_hw *hw; + + hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), + cfg->ops->ieee80211_ops); if (hw == NULL) { pr_err("%s: Can not allocate network device\n", cfg->name); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index b17de8214eb5..917d42eae55a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -241,6 +241,7 @@ struct iwl_ops { const struct iwl_hcmd_utils_ops *utils; const struct iwl_led_ops *led; const struct iwl_nic_ops *nic; + const struct ieee80211_ops *ieee80211_ops; }; struct iwl_mod_params { @@ -396,8 +397,7 @@ struct iwl_cfg { * L i b * ***************************/ -struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, - struct ieee80211_ops *hw_ops); +struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg); int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 9b71921dc2b6..d42bb22e5ed5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3824,7 +3824,7 @@ static struct attribute_group iwl3945_attribute_group = { .attrs = iwl3945_sysfs_entries, }; -static struct ieee80211_ops iwl3945_hw_ops = { +struct ieee80211_ops iwl3945_hw_ops = { .tx = iwl3945_mac_tx, .start = iwl3945_mac_start, .stop = iwl3945_mac_stop, @@ -3966,7 +3966,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ - hw = iwl_alloc_all(cfg, &iwl3945_hw_ops); + hw = iwl_alloc_all(cfg); if (hw == NULL) { pr_err("Can not allocate network device\n"); err = -ENOMEM; -- cgit v1.2.3 From 2d4e43c3c6783f956163c11568303b0390725e28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Oct 2010 09:15:40 -0700 Subject: iwlagn: don't resend RXON timing Resending RXON timing here caused issues with dual-mode under certain circumstances, so avoid doing it here right now. This effectively reverts b01efe434bd6ea807eb72b and partially 2491fa42d9bdf26075765. The next patch will make all this cleaner for just the devices that need it. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index e3533a89ec9c..3d1f6831cc20 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -105,7 +105,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) int ret; bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); - bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK); if (!iwl_is_alive(priv)) return -EBUSY; @@ -186,19 +185,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); - if (!old_assoc) { - /* - * First of all, before setting associated, we need to - * send RXON timing so the device knows about the DTIM - * period and other timing values - */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Error setting RXON timing!\n"); - return ret; - } - } - if (priv->cfg->ops->hcmd->set_pan_params) { ret = priv->cfg->ops->hcmd->set_pan_params(priv); if (ret) -- cgit v1.2.3 From 2295c66b68ae160dde2e6e2dc4f3061105153bfc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Oct 2010 09:15:41 -0700 Subject: iwlagn: new RXON processing for modern devices In order to simplify the flow, and make new enhancements easier, separate out the RXON processing for modern AGN (5000 and newer) from RXON processing for the older 3945 and 4965 devices. Avoid changing these old ones to avoid regressions and move their code to a new file (iwl-legacy.c). 4965 gets the commit_rxon that used to be common for all AGN devices, but with removed PAN support. The new RXON processing is more central and does more work in committing, so that it is easier to follow. To make it more evident what is split out for legacy, split the necessary operations for that into a new struct iwl_legacy_ops. Those parts that still exist in the new AGN code don't need to be parametrized. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 3 + drivers/net/wireless/iwlwifi/iwl-1000.c | 4 - drivers/net/wireless/iwlwifi/iwl-3945.c | 10 +- drivers/net/wireless/iwlwifi/iwl-3945.h | 6 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 318 +++++++++++++++- drivers/net/wireless/iwlwifi/iwl-5000.c | 8 - drivers/net/wireless/iwlwifi/iwl-6000.c | 8 - drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 562 ++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn.c | 385 +++---------------- drivers/net/wireless/iwlwifi/iwl-agn.h | 34 ++ drivers/net/wireless/iwlwifi/iwl-core.c | 531 -------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 30 +- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 + drivers/net/wireless/iwlwifi/iwl-led.c | 2 + drivers/net/wireless/iwlwifi/iwl-legacy.c | 560 +++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-legacy.h | 74 ++++ drivers/net/wireless/iwlwifi/iwl3945-base.c | 30 +- 17 files changed, 1631 insertions(+), 936 deletions(-) create mode 100644 drivers/net/wireless/iwlwifi/iwl-agn-rxon.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-legacy.c create mode 100644 drivers/net/wireless/iwlwifi/iwl-legacy.h (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 63edbe2e557f..ce05c260870e 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -2,6 +2,8 @@ obj-$(CONFIG_IWLWIFI) += iwlcore.o iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwlcore-objs += iwl-scan.o iwl-led.o +iwlcore-$(CONFIG_IWL3945) += iwl-legacy.o +iwlcore-$(CONFIG_IWL4965) += iwl-legacy.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o @@ -16,6 +18,7 @@ iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o +iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 4266c855a767..baedea8e4d04 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -211,14 +211,10 @@ static struct iwl_lib_ops iwl1000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .post_associate = iwl_post_associate, .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 95fed1158452..d9e676480269 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2726,10 +2726,7 @@ static struct iwl_lib_ops iwl3945_lib = { }, .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, - .post_associate = iwl3945_post_associate, .isr = iwl_isr_legacy, - .config_ap = iwl3945_config_ap, - .manage_ibss_station = iwl3945_manage_ibss_station, .recover_from_tx_stall = iwl_bg_monitor_recover, .check_plcp_health = iwl3945_good_plcp_health, @@ -2740,6 +2737,12 @@ static struct iwl_lib_ops iwl3945_lib = { }, }; +static const struct iwl_legacy_ops iwl3945_legacy_ops = { + .post_associate = iwl3945_post_associate, + .config_ap = iwl3945_config_ap, + .manage_ibss_station = iwl3945_manage_ibss_station, +}; + static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, @@ -2753,6 +2756,7 @@ static const struct iwl_ops iwl3945_ops = { .hcmd = &iwl3945_hcmd, .utils = &iwl3945_hcmd_utils, .led = &iwl3945_led_ops, + .legacy = &iwl3945_legacy_ops, .ieee80211_ops = &iwl3945_hw_ops, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index b27f07cbf355..3eef1eb74a78 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -264,10 +264,8 @@ void iwl3945_reply_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); extern void iwl3945_disable_events(struct iwl_priv *priv); extern int iwl4965_get_temperature(const struct iwl_priv *priv); -extern void iwl3945_post_associate(struct iwl_priv *priv, - struct ieee80211_vif *vif); -extern void iwl3945_config_ap(struct iwl_priv *priv, - struct ieee80211_vif *vif); +extern void iwl3945_post_associate(struct iwl_priv *priv); +extern void iwl3945_config_ap(struct iwl_priv *priv); extern int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 7921a910b34a..8f07964e4305 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -48,6 +48,7 @@ #include "iwl-agn-led.h" #include "iwl-agn.h" #include "iwl-agn-debugfs.h" +#include "iwl-legacy.h" static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(struct iwl_priv *priv); @@ -1443,6 +1444,142 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv, return ret; } +static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active; + int ret; + bool new_assoc = + !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); + + if (!iwl_is_alive(priv)) + return -EBUSY; + + if (!ctx->is_active) + return 0; + + /* always get timestamp with Rx frame */ + ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; + + ret = iwl_check_rxon_cmd(priv, ctx); + if (ret) { + IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* + * receive commit_rxon request + * abort any previous channel switch if still in process + */ + if (priv->switch_rxon.switch_in_progress && + (priv->switch_rxon.channel != ctx->staging.channel)) { + IWL_DEBUG_11H(priv, "abort channel switch on %d\n", + le16_to_cpu(priv->switch_rxon.channel)); + iwl_chswitch_done(priv, false); + } + + /* If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. */ + if (!iwl_full_rxon_required(priv, ctx)) { + ret = iwl_send_rxon_assoc(priv, ctx); + if (ret) { + IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); + return ret; + } + + memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); + iwl_print_rx_config_cmd(priv, ctx); + return 0; + } + + /* If we are currently associated and the new config requires + * an RXON_ASSOC and the new config wants the associated mask enabled, + * we must clear the associated from the active configuration + * before we apply the new config */ + if (iwl_is_associated_ctx(ctx) && new_assoc) { + IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); + active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), + active_rxon); + + /* If the mask clearing failed then we set + * active_rxon back to what it was previously */ + if (ret) { + active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; + IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); + return ret; + } + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + } + + IWL_DEBUG_INFO(priv, "Sending RXON\n" + "* with%s RXON_FILTER_ASSOC_MSK\n" + "* channel = %d\n" + "* bssid = %pM\n", + (new_assoc ? "" : "out"), + le16_to_cpu(ctx->staging.channel), + ctx->staging.bssid_addr); + + iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + + /* Apply the new configuration + * RXON unassoc clears the station table in uCode so restoration of + * stations is needed after it (the RXON command) completes + */ + if (!new_assoc) { + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n"); + memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + } + if (new_assoc) { + priv->start_calib = 0; + /* Apply the new configuration + * RXON assoc doesn't clear the station table in uCode, + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); + } + iwl_print_rx_config_cmd(priv, ctx); + + iwl_init_sensitivity(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 */ + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + + return 0; +} + static int iwl4965_hw_channel_switch(struct iwl_priv *priv, struct ieee80211_channel_switch *ch_switch) { @@ -2212,7 +2349,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv) static struct iwl_hcmd_ops iwl4965_hcmd = { .rxon_assoc = iwl4965_send_rxon_assoc, - .commit_rxon = iwlagn_commit_rxon, + .commit_rxon = iwl4965_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .send_bt_config = iwl_send_bt_config, }; @@ -2229,6 +2366,149 @@ static void iwl4965_post_scan(struct iwl_priv *priv) iwlcore_commit_rxon(priv, ctx); } +static void iwl4965_post_associate(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct ieee80211_vif *vif = ctx->vif; + struct ieee80211_conf *conf = NULL; + int ret = 0; + + if (!vif || !priv->is_open) + return; + + if (vif->type == NL80211_IFTYPE_AP) { + IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__); + return; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + iwl_scan_cancel_timeout(priv, 200); + + conf = ieee80211_get_hw_conf(priv->hw); + + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv, ctx); + + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) + IWL_WARN(priv, "RXON timing - " + "Attempting to continue.\n"); + + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; + + iwl_set_rxon_ht(priv, &priv->current_ht_config); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + + ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + + IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", + vif->bss_conf.aid, vif->bss_conf.beacon_int); + + if (vif->bss_conf.use_short_preamble) + ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { + if (vif->bss_conf.use_short_slot) + ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + } + + iwlcore_commit_rxon(priv, ctx); + + IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", + vif->bss_conf.aid, ctx->active.bssid_addr); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_ADHOC: + iwlagn_send_beacon_cmd(priv); + break; + default: + IWL_ERR(priv, "%s Should not be called in %d mode\n", + __func__, vif->type); + break; + } + + /* the chain noise calibration will enabled PM upon completion + * If chain noise has already been run, then we need to enable + * power management here */ + if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) + iwl_power_update_mode(priv, false); + + /* Enable Rx differential gain and sensitivity calibrations */ + iwl_chain_noise_reset(priv); + priv->start_calib = 1; +} + +static void iwl4965_config_ap(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct ieee80211_vif *vif = ctx->vif; + int ret = 0; + + lockdep_assert_held(&priv->mutex); + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + /* The following should be done only at AP bring up */ + if (!iwl_is_associated_ctx(ctx)) { + + /* RXON - unassoc (to set timing command) */ + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv, ctx); + + /* RXON Timing */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) + IWL_WARN(priv, "RXON timing failed - " + "Attempting to continue.\n"); + + /* AP has all antennas */ + priv->chain_noise_data.active_chains = + priv->hw_params.valid_rx_ant; + iwl_set_rxon_ht(priv, &priv->current_ht_config); + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + + ctx->staging.assoc_id = 0; + + if (vif->bss_conf.use_short_preamble) + ctx->staging.flags |= + RXON_FLG_SHORT_PREAMBLE_MSK; + else + ctx->staging.flags &= + ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { + if (vif->bss_conf.use_short_slot) + ctx->staging.flags |= + RXON_FLG_SHORT_SLOT_MSK; + else + ctx->staging.flags &= + ~RXON_FLG_SHORT_SLOT_MSK; + } + /* need to send beacon cmd before committing assoc RXON! */ + iwlagn_send_beacon_cmd(priv); + /* restore RXON assoc */ + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv, ctx); + } + iwlagn_send_beacon_cmd(priv); + + /* FIXME - we need to add code here to detect a totally new + * configuration, reset the AP, unassoc, rxon timing, assoc, + * clear sta table, add BCAST sta... */ +} + static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .get_hcmd_size = iwl4965_get_hcmd_size, .build_addsta_hcmd = iwl4965_build_addsta_hcmd, @@ -2281,14 +2561,10 @@ static struct iwl_lib_ops iwl4965_lib = { }, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .post_associate = iwl_post_associate, - .config_ap = iwl_config_ap, .isr = iwl_isr_legacy, .temp_ops = { .temperature = iwl4965_temperature_calib, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, @@ -2300,12 +2576,42 @@ static struct iwl_lib_ops iwl4965_lib = { .check_plcp_health = iwl_good_plcp_health, }; +static const struct iwl_legacy_ops iwl4965_legacy_ops = { + .post_associate = iwl4965_post_associate, + .config_ap = iwl4965_config_ap, + .manage_ibss_station = iwlagn_manage_ibss_station, + .update_bcast_stations = iwl_update_bcast_stations, +}; + +struct ieee80211_ops iwl4965_hw_ops = { + .tx = iwlagn_mac_tx, + .start = iwlagn_mac_start, + .stop = iwlagn_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_legacy_mac_config, + .configure_filter = iwlagn_configure_filter, + .set_key = iwlagn_mac_set_key, + .update_tkip_key = iwlagn_mac_update_tkip_key, + .conf_tx = iwl_mac_conf_tx, + .reset_tsf = iwl_legacy_mac_reset_tsf, + .bss_info_changed = iwl_legacy_mac_bss_info_changed, + .ampdu_action = iwlagn_mac_ampdu_action, + .hw_scan = iwl_mac_hw_scan, + .sta_add = iwlagn_mac_sta_add, + .sta_remove = iwl_mac_sta_remove, + .channel_switch = iwlagn_mac_channel_switch, + .flush = iwlagn_mac_flush, + .tx_last_beacon = iwl_mac_tx_last_beacon, +}; + static const struct iwl_ops iwl4965_ops = { .lib = &iwl4965_lib, .hcmd = &iwl4965_hcmd, .utils = &iwl4965_hcmd_utils, .led = &iwlagn_led_ops, - .ieee80211_ops = &iwlagn_hw_ops, + .legacy = &iwl4965_legacy_ops, + .ieee80211_ops = &iwl4965_hw_ops, }; static struct iwl_base_params iwl4965_base_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5f0327721692..e1f412f915ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -385,14 +385,10 @@ static struct iwl_lib_ops iwl5000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .post_associate = iwl_post_associate, .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, @@ -453,14 +449,10 @@ static struct iwl_lib_ops iwl5150_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .post_associate = iwl_post_associate, .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwl5150_temperature, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 85bde701351e..eacbce0d88b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -328,14 +328,10 @@ static struct iwl_lib_ops iwl6000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .post_associate = iwl_post_associate, .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, @@ -399,14 +395,10 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .post_associate = iwl_post_associate, .isr = iwl_isr_ict, - .config_ap = iwl_config_ap, .temp_ops = { .temperature = iwlagn_temperature, }, - .manage_ibss_station = iwlagn_manage_ibss_station, - .update_bcast_stations = iwl_update_bcast_stations, .debugfs_ops = { .rx_stats_read = iwl_ucode_rx_stats_read, .tx_stats_read = iwl_ucode_tx_stats_read, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c new file mode 100644 index 000000000000..58602457e415 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -0,0 +1,562 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include "iwl-dev.h" +#include "iwl-agn.h" +#include "iwl-sta.h" +#include "iwl-core.h" +#include "iwl-agn-calib.h" + +static int iwlagn_disable_bss(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct iwl_rxon_cmd *send) +{ + __le32 old_filter = send->filter_flags; + int ret; + + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send); + + send->filter_flags = old_filter; + + if (ret) + IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret); + + return ret; +} + +static int iwlagn_disable_pan(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct iwl_rxon_cmd *send) +{ + __le32 old_filter = send->filter_flags; + u8 old_dev_type = send->dev_type; + int ret; + + send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; + send->dev_type = RXON_DEV_TYPE_P2P; + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send); + + send->filter_flags = old_filter; + send->dev_type = old_dev_type; + + if (ret) + IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); + + /* FIXME: WAIT FOR PAN DISABLE */ + msleep(300); + + return ret; +} + +/** + * iwlagn_commit_rxon - commit staging_rxon to hardware + * + * The RXON command in staging_rxon is committed to the hardware and + * the active_rxon structure is updated with the new data. This + * function correctly transitions out of the RXON_ASSOC_MSK state if + * a HW tune is required based on the RXON structure changes. + */ +int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + /* cast away the const for active_rxon in this function */ + struct iwl_rxon_cmd *active = (void *)&ctx->active; + bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK); + bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); + int ret; + + lockdep_assert_held(&priv->mutex); + + if (!iwl_is_alive(priv)) + return -EBUSY; + + /* This function hardcodes a bunch of dual-mode assumptions */ + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + + if (!ctx->is_active) + return 0; + + /* always get timestamp with Rx frame */ + ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; + + if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) || + !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK)) + ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + + ret = iwl_check_rxon_cmd(priv, ctx); + if (ret) { + IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); + return -EINVAL; + } + + /* + * receive commit_rxon request + * abort any previous channel switch if still in process + */ + if (priv->switch_rxon.switch_in_progress && + (priv->switch_rxon.channel != ctx->staging.channel)) { + IWL_DEBUG_11H(priv, "abort channel switch on %d\n", + le16_to_cpu(priv->switch_rxon.channel)); + iwl_chswitch_done(priv, false); + } + + /* + * If we don't need to send a full RXON, we can use + * iwl_rxon_assoc_cmd which is used to reconfigure filter + * and other flags for the current radio configuration. + */ + if (!iwl_full_rxon_required(priv, ctx)) { + ret = iwl_send_rxon_assoc(priv, ctx); + if (ret) { + IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); + iwl_print_rx_config_cmd(priv, ctx); + return 0; + } + + if (priv->cfg->ops->hcmd->set_pan_params) { + ret = priv->cfg->ops->hcmd->set_pan_params(priv); + if (ret) + return ret; + } + + iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + + IWL_DEBUG_INFO(priv, + "Going to commit RXON\n" + " * with%s RXON_FILTER_ASSOC_MSK\n" + " * channel = %d\n" + " * bssid = %pM\n", + (new_assoc ? "" : "out"), + le16_to_cpu(ctx->staging.channel), + ctx->staging.bssid_addr); + + /* + * If we are currently associated and the new config is also + * going to be associated, OR if the new config is simply not + * associated, clear associated. + */ + if ((old_assoc && new_assoc) || !new_assoc) { + struct iwl_rxon_cmd *send = active; + + if (!new_assoc) + send = &ctx->staging; + + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, send); + else + ret = iwlagn_disable_pan(priv, ctx, send); + if (ret) + return ret; + + if (send != active) + memcpy(active, send, sizeof(*active)); + + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + } + + /* RXON timing must be before associated RXON */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + + if (new_assoc) { + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP || + ctx->vif->type == NL80211_IFTYPE_ADHOC)) { + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = ieee80211_beacon_get(priv->hw, + ctx->vif); + iwlagn_send_beacon_cmd(priv); + } + + priv->start_calib = 0; + /* + * Apply the new configuration. + * + * Associated RXON doesn't clear the station table in uCode, + * so we don't need to restore stations etc. after this. + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active, &ctx->staging, sizeof(*active)); + } + + iwl_print_rx_config_cmd(priv, ctx); + + iwl_init_sensitivity(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. + * + * FIXME: which RXON requires a tune? Can we optimise this out in + * some cases? + */ + ret = iwl_set_tx_power(priv, priv->tx_power_user_lmt, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + + return 0; +} + +int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_channel *channel = conf->channel; + const struct iwl_channel_info *ch_info; + int ret = 0; + + IWL_DEBUG_MAC80211(priv, "changed %#x", changed); + + mutex_lock(&priv->mutex); + + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { + IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + goto out; + } + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + goto out; + } + + if (changed & (IEEE80211_CONF_CHANGE_SMPS | + IEEE80211_CONF_CHANGE_CHANNEL)) { + /* mac80211 uses static for non-HT which is what we want */ + priv->current_ht_config.smps = conf->smps_mode; + + /* + * Recalculate chain counts. + * + * If monitor mode is enabled then mac80211 will + * set up the SM PS mode to OFF if an HT channel is + * configured. + */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + for_each_context(priv, ctx) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + } + + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + unsigned long flags; + + ch_info = iwl_get_channel_info(priv, channel->band, + channel->hw_value); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&priv->lock, flags); + + for_each_context(priv, ctx) { + /* Configure HT40 channels */ + ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled) { + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } + } else + ctx->ht.is_40mhz = false; + + /* + * Default to no protection. Protection mode will + * later be set from BSS config in iwl_ht_conf + */ + ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; + + /* if we are switching from ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if (le16_to_cpu(ctx->staging.channel) != + channel->hw_value) + ctx->staging.flags = 0; + + iwl_set_rxon_channel(priv, channel, ctx); + iwl_set_rxon_ht(priv, &priv->current_ht_config); + + iwl_set_flags_for_band(priv, ctx, channel->band, + ctx->vif); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_update_bcast_stations(priv); + + /* + * The list of supported rates and rate mask can be different + * for each band; since the band may have changed, reset + * the rate mask to what mac80211 lists. + */ + iwl_set_rate(priv); + } + + if (changed & (IEEE80211_CONF_CHANGE_PS | + IEEE80211_CONF_CHANGE_IDLE)) { + ret = iwl_power_update_mode(priv, false); + if (ret) + IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + } + + for_each_context(priv, ctx) { + if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + continue; + iwlagn_commit_rxon(priv, ctx); + } + out: + mutex_unlock(&priv->mutex); + return ret; +} + +static void iwlagn_update_qos(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + + if (!ctx->is_active) + return; + + ctx->qos_data.def_qos_parm.qos_flags = 0; + + if (ctx->qos_data.qos_active) + ctx->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (ctx->ht.enabled) + ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + ctx->qos_data.qos_active, + ctx->qos_data.def_qos_parm.qos_flags); + + ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, + sizeof(struct iwl_qosparam_cmd), + &ctx->qos_data.def_qos_parm); + if (ret) + IWL_ERR(priv, "Failed to update QoS\n"); +} + +static void iwlagn_check_needed_chains(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct ieee80211_bss_conf *bss_conf) +{ + struct ieee80211_vif *vif = ctx->vif; + struct iwl_rxon_context *tmp; + struct ieee80211_sta *sta; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + bool need_multiple; + + lockdep_assert_held(&priv->mutex); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (sta) { + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int maxstreams; + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if ((ht_cap->mcs.rx_mask[1] == 0) && + (ht_cap->mcs.rx_mask[2] == 0)) + need_multiple = false; + if (maxstreams <= 1) + need_multiple = true; + } else { + /* + * If at all, this can only happen through a race + * when the AP disconnects us while we're still + * setting up the connection, in that case mac80211 + * will soon tell us about that. + */ + need_multiple = false; + } + rcu_read_unlock(); + break; + case NL80211_IFTYPE_ADHOC: + /* currently */ + need_multiple = false; + break; + default: + /* only AP really */ + need_multiple = true; + break; + } + + ctx->ht_need_multiple_chains = need_multiple; + + if (!need_multiple) { + /* check all contexts */ + for_each_context(priv, tmp) { + if (!tmp->vif) + continue; + if (tmp->ht_need_multiple_chains) { + need_multiple = true; + break; + } + } + } + + ht_conf->single_chain_sufficient = !need_multiple; +} + +void iwlagn_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + int ret; + bool force = false; + + mutex_lock(&priv->mutex); + + if (changes & BSS_CHANGED_BEACON_INT) + force = true; + + if (changes & BSS_CHANGED_QOS) { + ctx->qos_data.qos_active = bss_conf->qos; + iwlagn_update_qos(priv, ctx); + } + + ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + if (vif->bss_conf.use_short_preamble) + ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + + if (changes & BSS_CHANGED_ASSOC) { + if (bss_conf->assoc) { + iwl_led_associate(priv); + priv->timestamp = bss_conf->timestamp; + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; + } else { + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl_led_disassociate(priv); + } + } + + if (ctx->ht.enabled) { + ctx->ht.protection = bss_conf->ht_operation_mode & + IEEE80211_HT_OP_MODE_PROTECTION; + ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode & + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + iwlagn_check_needed_chains(priv, ctx, bss_conf); + } + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + + if (bss_conf->use_cts_prot) + ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; + else + ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; + + memcpy(ctx->staging.bssid_addr, bss_conf->bssid, ETH_ALEN); + + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_ADHOC) { + if (vif->bss_conf.enable_beacon) { + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; + priv->beacon_ctx = ctx; + } else { + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + priv->beacon_ctx = NULL; + } + } + + if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + iwlagn_commit_rxon(priv, ctx); + + if (changes & BSS_CHANGED_IBSS) { + ret = iwlagn_manage_ibss_station(priv, vif, + bss_conf->ibss_joined); + if (ret) + IWL_ERR(priv, "failed to %s IBSS station %pM\n", + bss_conf->ibss_joined ? "add" : "remove", + bss_conf->bssid); + } + + mutex_unlock(&priv->mutex); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3d1f6831cc20..1050f31d90a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -90,153 +90,6 @@ MODULE_ALIAS("iwl4965"); static int iwlagn_ant_coupling; static bool iwlagn_bt_ch_announce = 1; -/** - * iwlagn_commit_rxon - commit staging_rxon to hardware - * - * The RXON command in staging_rxon is committed to the hardware and - * the active_rxon structure is updated with the new data. This - * function correctly transitions out of the RXON_ASSOC_MSK state if - * a HW tune is required based on the RXON structure changes. - */ -int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&ctx->active; - int ret; - bool new_assoc = - !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); - - if (!iwl_is_alive(priv)) - return -EBUSY; - - if (!ctx->is_active) - return 0; - - /* always get timestamp with Rx frame */ - ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; - - ret = iwl_check_rxon_cmd(priv, ctx); - if (ret) { - IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); - return -EINVAL; - } - - /* - * receive commit_rxon request - * abort any previous channel switch if still in process - */ - if (priv->switch_rxon.switch_in_progress && - (priv->switch_rxon.channel != ctx->staging.channel)) { - IWL_DEBUG_11H(priv, "abort channel switch on %d\n", - le16_to_cpu(priv->switch_rxon.channel)); - iwl_chswitch_done(priv, false); - } - - /* If we don't need to send a full RXON, we can use - * iwl_rxon_assoc_cmd which is used to reconfigure filter - * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); - if (ret) { - IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); - return ret; - } - - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - iwl_print_rx_config_cmd(priv, ctx); - return 0; - } - - /* If we are currently associated and the new config requires - * an RXON_ASSOC and the new config wants the associated mask enabled, - * we must clear the associated from the active configuration - * before we apply the new config */ - if (iwl_is_associated_ctx(ctx) && new_assoc) { - IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n"); - active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), - active_rxon); - - /* If the mask clearing failed then we set - * active_rxon back to what it was previously */ - if (ret) { - active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK; - IWL_ERR(priv, "Error clearing ASSOC_MSK (%d)\n", ret); - return ret; - } - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - - IWL_DEBUG_INFO(priv, "Sending RXON\n" - "* with%s RXON_FILTER_ASSOC_MSK\n" - "* channel = %d\n" - "* bssid = %pM\n", - (new_assoc ? "" : "out"), - le16_to_cpu(ctx->staging.channel), - ctx->staging.bssid_addr); - - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); - - if (priv->cfg->ops->hcmd->set_pan_params) { - ret = priv->cfg->ops->hcmd->set_pan_params(priv); - if (ret) - return ret; - } - - /* Apply the new configuration - * RXON unassoc clears the station table in uCode so restoration of - * stations is needed after it (the RXON command) completes - */ - if (!new_assoc) { - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - IWL_DEBUG_INFO(priv, "Return from !new_assoc RXON.\n"); - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - if (new_assoc) { - priv->start_calib = 0; - /* Apply the new configuration - * RXON assoc doesn't clear the station table in uCode, - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); - } - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(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 */ - ret = priv->cfg->ops->lib->send_tx_power(priv); - if (ret) - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; -} - void iwl_update_chain_flags(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; @@ -394,7 +247,8 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, return sizeof(*tx_beacon_cmd) + frame_size; } -static int iwl_send_beacon_cmd(struct iwl_priv *priv) + +int iwlagn_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_frame *frame; unsigned int frame_size; @@ -644,7 +498,7 @@ static void iwl_bg_beacon_update(struct work_struct *work) priv->beacon_skb = beacon; - iwl_send_beacon_cmd(priv); + iwlagn_send_beacon_cmd(priv); out: mutex_unlock(&priv->mutex); } @@ -3292,92 +3146,6 @@ static void iwl_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } -#define IWL_DELAY_NEXT_SCAN (HZ*2) - -void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) -{ - struct iwl_rxon_context *ctx; - struct ieee80211_conf *conf = NULL; - int ret = 0; - - if (!vif || !priv->is_open) - return; - - ctx = iwl_rxon_ctx_from_vif(vif); - - if (vif->type == NL80211_IFTYPE_AP) { - IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__); - return; - } - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - iwl_scan_cancel_timeout(priv, 200); - - conf = ieee80211_get_hw_conf(priv->hw); - - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) - IWL_WARN(priv, "RXON timing - " - "Attempting to continue.\n"); - - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - - iwl_set_rxon_ht(priv, &priv->current_ht_config); - - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - - ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); - - IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", - vif->bss_conf.aid, vif->bss_conf.beacon_int); - - if (vif->bss_conf.use_short_preamble) - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) - ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - } - - iwlcore_commit_rxon(priv, ctx); - - IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", - vif->bss_conf.aid, ctx->active.bssid_addr); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_ADHOC: - iwl_send_beacon_cmd(priv); - break; - default: - IWL_ERR(priv, "%s Should not be called in %d mode\n", - __func__, vif->type); - break; - } - - /* the chain noise calibration will enabled PM upon completion - * If chain noise has already been run, then we need to enable - * power management here */ - if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) - iwl_power_update_mode(priv, false); - - /* Enable Rx differential gain and sensitivity calibrations */ - iwl_chain_noise_reset(priv); - priv->start_calib = 1; - -} - /***************************************************************************** * * mac80211 entry point functions @@ -3457,7 +3225,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, } -static int iwl_mac_start(struct ieee80211_hw *hw) +int iwlagn_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -3498,7 +3266,7 @@ out: return 0; } -static void iwl_mac_stop(struct ieee80211_hw *hw) +void iwlagn_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -3520,7 +3288,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "leave\n"); } -static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -3536,73 +3304,12 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif) -{ - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - int ret = 0; - - lockdep_assert_held(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - /* The following should be done only at AP bring up */ - if (!iwl_is_associated_ctx(ctx)) { - - /* RXON - unassoc (to set timing command) */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - /* RXON Timing */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) - IWL_WARN(priv, "RXON timing failed - " - "Attempting to continue.\n"); - - /* AP has all antennas */ - priv->chain_noise_data.active_chains = - priv->hw_params.valid_rx_ant; - iwl_set_rxon_ht(priv, &priv->current_ht_config); - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - - ctx->staging.assoc_id = 0; - - if (vif->bss_conf.use_short_preamble) - ctx->staging.flags |= - RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_PREAMBLE_MSK; - - if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) - ctx->staging.flags |= - RXON_FLG_SHORT_SLOT_MSK; - else - ctx->staging.flags &= - ~RXON_FLG_SHORT_SLOT_MSK; - } - /* need to send beacon cmd before committing assoc RXON! */ - iwl_send_beacon_cmd(priv); - /* restore RXON assoc */ - ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - } - iwl_send_beacon_cmd(priv); - - /* FIXME - we need to add code here to detect a totally new - * configuration, reset the AP, unassoc, rxon timing, assoc, - * clear sta table, add BCAST sta... */ -} - -static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_key_conf *keyconf, - struct ieee80211_sta *sta, - u32 iv32, u16 *phase1key) +void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3614,10 +3321,9 @@ static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } -static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -3684,10 +3390,10 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn) +int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; int ret = -EINVAL; @@ -3768,10 +3474,10 @@ static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -static void iwl_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) +static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3798,9 +3504,9 @@ static void iwl_mac_sta_notify(struct ieee80211_hw *hw, } } -static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct iwl_priv *priv = hw->priv; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; @@ -3841,8 +3547,8 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, return 0; } -static void iwl_mac_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_channel_switch *ch_switch) +void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; @@ -3939,10 +3645,10 @@ out_exit: IWL_DEBUG_MAC80211(priv, "leave\n"); } -static void iwlagn_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) { struct iwl_priv *priv = hw->priv; __le32 filter_or = 0, filter_nand = 0; @@ -3988,7 +3694,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwl_mac_flush(struct ieee80211_hw *hw, bool drop) +void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; @@ -4198,25 +3904,24 @@ static void iwl_uninit_drv(struct iwl_priv *priv) } struct ieee80211_ops iwlagn_hw_ops = { - .tx = iwl_mac_tx, - .start = iwl_mac_start, - .stop = iwl_mac_stop, + .tx = iwlagn_mac_tx, + .start = iwlagn_mac_start, + .stop = iwlagn_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, - .config = iwl_mac_config, + .config = iwlagn_mac_config, .configure_filter = iwlagn_configure_filter, - .set_key = iwl_mac_set_key, - .update_tkip_key = iwl_mac_update_tkip_key, + .set_key = iwlagn_mac_set_key, + .update_tkip_key = iwlagn_mac_update_tkip_key, .conf_tx = iwl_mac_conf_tx, - .reset_tsf = iwl_mac_reset_tsf, - .bss_info_changed = iwl_bss_info_changed, - .ampdu_action = iwl_mac_ampdu_action, + .bss_info_changed = iwlagn_bss_info_changed, + .ampdu_action = iwlagn_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan, - .sta_notify = iwl_mac_sta_notify, + .sta_notify = iwlagn_mac_sta_notify, .sta_add = iwlagn_mac_sta_add, .sta_remove = iwl_mac_sta_remove, - .channel_switch = iwl_mac_channel_switch, - .flush = iwl_mac_flush, + .channel_switch = iwlagn_mac_channel_switch, + .flush = iwlagn_mac_flush, .tx_last_beacon = iwl_mac_tx_last_beacon, }; @@ -4287,6 +3992,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_printk(KERN_DEBUG, &(pdev->dev), "sw scan support is deprecated\n"); iwlagn_hw_ops.hw_scan = NULL; +#ifdef CONFIG_IWL4965 + iwl4965_hw_ops.hw_scan = NULL; +#endif } hw = iwl_alloc_all(cfg); @@ -4321,6 +4029,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) BIT(NL80211_IFTYPE_ADHOC); priv->contexts[IWL_RXON_CTX_BSS].interface_modes = BIT(NL80211_IFTYPE_STATION); + priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index ba88e78e6116..aca93f4477a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -103,6 +103,7 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd; extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils; extern struct ieee80211_ops iwlagn_hw_ops; +extern struct ieee80211_ops iwl4965_hw_ops; int iwl_reset_ict(struct iwl_priv *priv); void iwl_disable_ict(struct iwl_priv *priv); @@ -134,6 +135,11 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv, /* RXON */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed); +void iwlagn_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); /* uCode */ int iwlagn_load_ucode(struct iwl_priv *priv); @@ -251,6 +257,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, int iwlagn_send_rxon_assoc(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); +int iwlagn_send_beacon_cmd(struct iwl_priv *priv); /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); @@ -320,4 +327,31 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); +/* mac80211 handlers (for 4965) */ +int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); +int iwlagn_mac_start(struct ieee80211_hw *hw); +void iwlagn_mac_stop(struct ieee80211_hw *hw); +void iwlagn_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast); +int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *keyconf, + struct ieee80211_sta *sta, + u32 iv32, u16 *phase1key); +int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn); +int iwlagn_mac_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch); +void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop); + #endif /* __iwl_agn_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c93368083e1a..776713c6a7ff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -100,35 +100,6 @@ out: } EXPORT_SYMBOL(iwl_alloc_all); -/* - * QoS support -*/ -static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!ctx->is_active) - return; - - ctx->qos_data.def_qos_parm.qos_flags = 0; - - if (ctx->qos_data.qos_active) - ctx->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (ctx->ht.enabled) - ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", - ctx->qos_data.qos_active, - ctx->qos_data.def_qos_parm.qos_flags); - - iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, - sizeof(struct iwl_qosparam_cmd), - &ctx->qos_data.def_qos_parm, NULL); -} - #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, @@ -1456,310 +1427,6 @@ int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); -static void iwl_ht_conf(struct iwl_priv *priv, - struct ieee80211_vif *vif) -{ - struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct ieee80211_sta *sta; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - IWL_DEBUG_MAC80211(priv, "enter:\n"); - - if (!ctx->ht.enabled) - return; - - ctx->ht.protection = - bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; - ctx->ht.non_gf_sta_present = - !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); - - ht_conf->single_chain_sufficient = false; - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { - struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; - int maxstreams; - - maxstreams = (ht_cap->mcs.tx_params & - IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) - >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; - maxstreams += 1; - - if ((ht_cap->mcs.rx_mask[1] == 0) && - (ht_cap->mcs.rx_mask[2] == 0)) - ht_conf->single_chain_sufficient = true; - if (maxstreams <= 1) - ht_conf->single_chain_sufficient = true; - } else { - /* - * If at all, this can only happen through a race - * when the AP disconnects us while we're still - * setting up the connection, in that case mac80211 - * will soon tell us about that. - */ - ht_conf->single_chain_sufficient = true; - } - rcu_read_unlock(); - break; - case NL80211_IFTYPE_ADHOC: - ht_conf->single_chain_sufficient = true; - break; - default: - break; - } - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} - -static inline void iwl_set_no_assoc(struct iwl_priv *priv, - struct ieee80211_vif *vif) -{ - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - - iwl_led_disassociate(priv); - /* - * inform the ucode that there is no longer an - * association and that no more packets should be - * sent - */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - ctx->staging.assoc_id = 0; - iwlcore_commit_rxon(priv, ctx); -} - -static void iwlcore_beacon_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - __le64 timestamp; - struct sk_buff *skb = ieee80211_beacon_get(hw, vif); - - if (!skb) - return; - - IWL_DEBUG_ASSOC(priv, "enter\n"); - - lockdep_assert_held(&priv->mutex); - - if (!priv->beacon_ctx) { - IWL_ERR(priv, "update beacon but no beacon context!\n"); - dev_kfree_skb(skb); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - priv->beacon_skb = skb; - - timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - priv->timestamp = le64_to_cpu(timestamp); - - IWL_DEBUG_ASSOC(priv, "leave\n"); - - spin_unlock_irqrestore(&priv->lock, flags); - - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); - return; - } - - priv->cfg->ops->lib->post_associate(priv, priv->beacon_ctx->vif); -} - -void iwl_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - int ret; - - IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - - if (!iwl_is_alive(priv)) - return; - - mutex_lock(&priv->mutex); - - if (changes & (BSS_CHANGED_BSSID | BSS_CHANGED_ASSOC | - BSS_CHANGED_BEACON_ENABLED)) { - /* - * If there is currently a HW scan going on in the - * background then we need to cancel it else the RXON - * below in post_associate or set_no_assoc can fail. - */ - if (iwl_scan_cancel_timeout(priv, 200)) { - IWL_WARN(priv, "Can not cancel scan\n"); - goto out; - } - } - - if (changes & BSS_CHANGED_QOS) { - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - ctx->qos_data.qos_active = bss_conf->qos; - iwl_update_qos(priv, ctx); - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (changes & BSS_CHANGED_BEACON_ENABLED) { - /* - * the add_interface code must make sure we only ever - * have a single interface that could be beaconing at - * any time. - */ - if (vif->bss_conf.enable_beacon) - priv->beacon_ctx = ctx; - else - priv->beacon_ctx = NULL; - } - - if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) { - dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = ieee80211_beacon_get(hw, vif); - } - - if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP) - iwl_send_rxon_timing(priv, ctx); - - if (changes & BSS_CHANGED_BSSID) { - IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); - - /* mac80211 only sets assoc when in STATION mode */ - if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { - memcpy(ctx->staging.bssid_addr, - bss_conf->bssid, ETH_ALEN); - - /* currently needed in a few places */ - memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); - } else { - ctx->staging.filter_flags &= - ~RXON_FILTER_ASSOC_MSK; - } - - } - - /* - * This needs to be after setting the BSSID in case - * mac80211 decides to do both changes at once because - * it will invoke post_associate. - */ - if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON) - iwlcore_beacon_update(hw, vif); - - if (changes & BSS_CHANGED_ERP_PREAMBLE) { - IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", - bss_conf->use_short_preamble); - if (bss_conf->use_short_preamble) - ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; - else - ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; - } - - if (changes & BSS_CHANGED_ERP_CTS_PROT) { - IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); - if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) - ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; - else - ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; - if (bss_conf->use_cts_prot) - ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; - else - ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; - } - - if (changes & BSS_CHANGED_BASIC_RATES) { - /* XXX use this information - * - * To do that, remove code from iwl_set_rate() and put something - * like this here: - * - if (A-band) - ctx->staging.ofdm_basic_rates = - bss_conf->basic_rates; - else - ctx->staging.ofdm_basic_rates = - bss_conf->basic_rates >> 4; - ctx->staging.cck_basic_rates = - bss_conf->basic_rates & 0xF; - */ - } - - if (changes & BSS_CHANGED_HT) { - iwl_ht_conf(priv, vif); - - if (priv->cfg->ops->hcmd->set_rxon_chain) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - } - - if (changes & BSS_CHANGED_ASSOC) { - IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); - if (bss_conf->assoc) { - priv->timestamp = bss_conf->timestamp; - - iwl_led_associate(priv); - - if (!iwl_is_rfkill(priv)) - priv->cfg->ops->lib->post_associate(priv, vif); - } else - iwl_set_no_assoc(priv, vif); - } - - if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) { - IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n", - changes); - ret = iwl_send_rxon_assoc(priv, ctx); - if (!ret) { - /* Sync active_rxon with latest change. */ - memcpy((void *)&ctx->active, - &ctx->staging, - sizeof(struct iwl_rxon_cmd)); - } - } - - if (changes & BSS_CHANGED_BEACON_ENABLED) { - if (vif->bss_conf.enable_beacon) { - memcpy(ctx->staging.bssid_addr, - bss_conf->bssid, ETH_ALEN); - memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); - iwl_led_associate(priv); - iwlcore_config_ap(priv, vif); - } else - iwl_set_no_assoc(priv, vif); - } - - if (changes & BSS_CHANGED_IBSS) { - ret = priv->cfg->ops->lib->manage_ibss_station(priv, vif, - bss_conf->ibss_joined); - if (ret) - IWL_ERR(priv, "failed to %s IBSS station %pM\n", - bss_conf->ibss_joined ? "add" : "remove", - bss_conf->bssid); - } - - if (changes & BSS_CHANGED_IDLE && - priv->cfg->ops->hcmd->set_pan_params) { - if (priv->cfg->ops->hcmd->set_pan_params(priv)) - IWL_ERR(priv, "failed to update PAN params\n"); - } - -out: - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} -EXPORT_SYMBOL(iwl_bss_info_changed); - static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) { struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); @@ -1899,204 +1566,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL(iwl_mac_remove_interface); -/** - * iwl_mac_config - mac80211 config callback - */ -int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) -{ - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; - struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_channel *channel = conf->channel; - struct iwl_ht_config *ht_conf = &priv->current_ht_config; - struct iwl_rxon_context *ctx; - unsigned long flags = 0; - int ret = 0; - u16 ch; - int scan_active = 0; - - mutex_lock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", - channel->hw_value, changed); - - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { - scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); - } - - if (changed & (IEEE80211_CONF_CHANGE_SMPS | - IEEE80211_CONF_CHANGE_CHANNEL)) { - /* mac80211 uses static for non-HT which is what we want */ - priv->current_ht_config.smps = conf->smps_mode; - - /* - * Recalculate chain counts. - * - * If monitor mode is enabled then mac80211 will - * set up the SM PS mode to OFF if an HT channel is - * configured. - */ - if (priv->cfg->ops->hcmd->set_rxon_chain) - for_each_context(priv, ctx) - priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); - } - - /* during scanning mac80211 will delay channel setting until - * scan finish with changed = 0 - */ - if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { - if (scan_active) - goto set_ch_out; - - ch = channel->hw_value; - ch_info = iwl_get_channel_info(priv, channel->band, ch); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); - ret = -EINVAL; - goto set_ch_out; - } - - spin_lock_irqsave(&priv->lock, flags); - - for_each_context(priv, ctx) { - /* Configure HT40 channels */ - ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else - ctx->ht.is_40mhz = false; - - /* - * Default to no protection. Protection mode will - * later be set from BSS config in iwl_ht_conf - */ - ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; - - /* if we are switching from ht to 2.4 clear flags - * from any ht related info since 2.4 does not - * support ht */ - if ((le16_to_cpu(ctx->staging.channel) != ch)) - ctx->staging.flags = 0; - - iwl_set_rxon_channel(priv, channel, ctx); - iwl_set_rxon_ht(priv, ht_conf); - - iwl_set_flags_for_band(priv, ctx, channel->band, - ctx->vif); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->cfg->ops->lib->update_bcast_stations) - ret = priv->cfg->ops->lib->update_bcast_stations(priv); - - set_ch_out: - /* The list of supported rates and rate mask can be different - * for each band; since the band may have changed, reset - * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); - } - - if (changed & (IEEE80211_CONF_CHANGE_PS | - IEEE80211_CONF_CHANGE_IDLE)) { - ret = iwl_power_update_mode(priv, false); - if (ret) - IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); - } - - if (changed & IEEE80211_CONF_CHANGE_POWER) { - IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", - priv->tx_power_user_lmt, conf->power_level); - - ret = iwl_set_tx_power(priv, conf->power_level, false); - if (ret) - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - } - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - goto out; - } - - if (scan_active) - goto out; - - for_each_context(priv, ctx) { - if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) - iwlcore_commit_rxon(priv, ctx); - else - IWL_DEBUG_INFO(priv, - "Not re-sending same RXON configuration.\n"); - } - -out: - IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); - return ret; -} -EXPORT_SYMBOL(iwl_mac_config); - -void iwl_mac_reset_tsf(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - unsigned long flags; - /* IBSS can only be the IWL_RXON_CTX_BSS context */ - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - - mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); - spin_unlock_irqrestore(&priv->lock, flags); - - spin_lock_irqsave(&priv->lock, flags); - - /* new association get rid of ibss beacon skb */ - if (priv->beacon_skb) - dev_kfree_skb(priv->beacon_skb); - - priv->beacon_skb = NULL; - - priv->timestamp = 0; - - spin_unlock_irqrestore(&priv->lock, flags); - - iwl_scan_cancel_timeout(priv, 100); - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - - /* we are restarting association process - * clear RXON_FILTER_ASSOC_MSK bit - */ - ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwlcore_commit_rxon(priv, ctx); - - iwl_set_rate(priv); - - mutex_unlock(&priv->mutex); - - IWL_DEBUG_MAC80211(priv, "leave\n"); -} -EXPORT_SYMBOL(iwl_mac_reset_tsf); - int iwl_alloc_txq_mem(struct iwl_priv *priv) { if (!priv->txq) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 917d42eae55a..854613e4f2be 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -193,9 +193,6 @@ struct iwl_lib_ops { /* power */ int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - void (*post_associate)(struct iwl_priv *priv, - struct ieee80211_vif *vif); - void (*config_ap)(struct iwl_priv *priv, struct ieee80211_vif *vif); irqreturn_t (*isr) (int irq, void *data); /* eeprom operations (as defined in iwl-eeprom.h) */ @@ -203,10 +200,6 @@ struct iwl_lib_ops { /* temperature */ struct iwl_temp_ops temp_ops; - /* station management */ - int (*manage_ibss_station)(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add); - int (*update_bcast_stations)(struct iwl_priv *priv); /* recover from tx queue stall */ void (*recover_from_tx_stall)(unsigned long data); /* check for plcp health */ @@ -235,12 +228,22 @@ struct iwl_nic_ops { void (*additional_nic_config)(struct iwl_priv *priv); }; +struct iwl_legacy_ops { + void (*post_associate)(struct iwl_priv *priv); + void (*config_ap)(struct iwl_priv *priv); + /* station management */ + int (*update_bcast_stations)(struct iwl_priv *priv); + int (*manage_ibss_station)(struct iwl_priv *priv, + struct ieee80211_vif *vif, bool add); +}; + 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_led_ops *led; const struct iwl_nic_ops *nic; + const struct iwl_legacy_ops *legacy; const struct ieee80211_ops *ieee80211_ops; }; @@ -425,18 +428,10 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, u32 decrypt_res, struct ieee80211_rx_status *stats); void iwl_irq_handle_error(struct iwl_priv *priv); -void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif); -void iwl_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *bss_conf, - u32 changes); int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); -void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif); -void iwl_mac_reset_tsf(struct ieee80211_hw *hw); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); void iwlcore_tx_cmd_protection(struct iwl_priv *priv, @@ -732,11 +727,6 @@ static inline int iwlcore_commit_rxon(struct iwl_priv *priv, { return priv->cfg->ops->hcmd->commit_rxon(priv, ctx); } -static inline void iwlcore_config_ap(struct iwl_priv *priv, - struct ieee80211_vif *vif) -{ - priv->cfg->ops->lib->config_ap(priv, vif); -} static inline const struct ieee80211_supported_band *iwl_get_hw_mode( struct iwl_priv *priv, enum ieee80211_band band) { diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index cd6daed99931..9fcaaf0cfe93 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1162,6 +1162,8 @@ struct iwl_rxon_context { */ bool always_active, is_active; + bool ht_need_multiple_chains; + enum iwl_rxon_context_id ctxid; u32 interface_modes, exclusive_interface_modes; diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 86c2b6fed0c6..5a9129219c90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -134,6 +134,7 @@ int iwl_led_associate(struct iwl_priv *priv) return 0; } +EXPORT_SYMBOL(iwl_led_associate); int iwl_led_disassociate(struct iwl_priv *priv) { @@ -141,6 +142,7 @@ int iwl_led_disassociate(struct iwl_priv *priv) return 0; } +EXPORT_SYMBOL(iwl_led_disassociate); /* * calculate blink rate according to last second Tx/Rx activities diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c new file mode 100644 index 000000000000..b735fef9ee4b --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -0,0 +1,560 @@ +/****************************************************************************** + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include + +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-legacy.h" + +/** + * iwl_legacy_mac_config - mac80211 config callback + */ +int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) +{ + struct iwl_priv *priv = hw->priv; + const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_channel *channel = conf->channel; + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct iwl_rxon_context *ctx; + unsigned long flags = 0; + int ret = 0; + u16 ch; + int scan_active = 0; + + if (WARN_ON(!priv->cfg->ops->legacy)) + return -EOPNOTSUPP; + + mutex_lock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", + channel->hw_value, changed); + + if (unlikely(!priv->cfg->mod_params->disable_hw_scan && + test_bit(STATUS_SCANNING, &priv->status))) { + scan_active = 1; + IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + } + + if (changed & (IEEE80211_CONF_CHANGE_SMPS | + IEEE80211_CONF_CHANGE_CHANNEL)) { + /* mac80211 uses static for non-HT which is what we want */ + priv->current_ht_config.smps = conf->smps_mode; + + /* + * Recalculate chain counts. + * + * If monitor mode is enabled then mac80211 will + * set up the SM PS mode to OFF if an HT channel is + * configured. + */ + if (priv->cfg->ops->hcmd->set_rxon_chain) + for_each_context(priv, ctx) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + } + + /* during scanning mac80211 will delay channel setting until + * scan finish with changed = 0 + */ + if (!changed || (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + if (scan_active) + goto set_ch_out; + + ch = channel->hw_value; + ch_info = iwl_get_channel_info(priv, channel->band, ch); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - invalid channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + + spin_lock_irqsave(&priv->lock, flags); + + for_each_context(priv, ctx) { + /* Configure HT40 channels */ + ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled) { + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } + } else + ctx->ht.is_40mhz = false; + + /* + * Default to no protection. Protection mode will + * later be set from BSS config in iwl_ht_conf + */ + ctx->ht.protection = IEEE80211_HT_OP_MODE_PROTECTION_NONE; + + /* if we are switching from ht to 2.4 clear flags + * from any ht related info since 2.4 does not + * support ht */ + if ((le16_to_cpu(ctx->staging.channel) != ch)) + ctx->staging.flags = 0; + + iwl_set_rxon_channel(priv, channel, ctx); + iwl_set_rxon_ht(priv, ht_conf); + + iwl_set_flags_for_band(priv, ctx, channel->band, + ctx->vif); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->cfg->ops->legacy->update_bcast_stations) + ret = priv->cfg->ops->legacy->update_bcast_stations(priv); + + set_ch_out: + /* The list of supported rates and rate mask can be different + * for each band; since the band may have changed, reset + * the rate mask to what mac80211 lists */ + iwl_set_rate(priv); + } + + if (changed & (IEEE80211_CONF_CHANGE_PS | + IEEE80211_CONF_CHANGE_IDLE)) { + ret = iwl_power_update_mode(priv, false); + if (ret) + IWL_DEBUG_MAC80211(priv, "Error setting sleep level\n"); + } + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + IWL_DEBUG_MAC80211(priv, "TX Power old=%d new=%d\n", + priv->tx_power_user_lmt, conf->power_level); + + iwl_set_tx_power(priv, conf->power_level, false); + } + + if (!iwl_is_ready(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + goto out; + } + + if (scan_active) + goto out; + + for_each_context(priv, ctx) { + if (memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging))) + iwlcore_commit_rxon(priv, ctx); + else + IWL_DEBUG_INFO(priv, + "Not re-sending same RXON configuration.\n"); + } + +out: + IWL_DEBUG_MAC80211(priv, "leave\n"); + mutex_unlock(&priv->mutex); + return ret; +} +EXPORT_SYMBOL(iwl_legacy_mac_config); + +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + /* IBSS can only be the IWL_RXON_CTX_BSS context */ + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + + if (WARN_ON(!priv->cfg->ops->legacy)) + return; + + mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + + spin_lock_irqsave(&priv->lock, flags); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_config)); + spin_unlock_irqrestore(&priv->lock, flags); + + spin_lock_irqsave(&priv->lock, flags); + + /* new association get rid of ibss beacon skb */ + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); + + priv->beacon_skb = NULL; + + priv->timestamp = 0; + + spin_unlock_irqrestore(&priv->lock, flags); + + iwl_scan_cancel_timeout(priv, 100); + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); + mutex_unlock(&priv->mutex); + return; + } + + /* we are restarting association process + * clear RXON_FILTER_ASSOC_MSK bit + */ + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwlcore_commit_rxon(priv, ctx); + + iwl_set_rate(priv); + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} +EXPORT_SYMBOL(iwl_legacy_mac_reset_tsf); + +static void iwl_ht_conf(struct iwl_priv *priv, + struct ieee80211_vif *vif) +{ + struct iwl_ht_config *ht_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + IWL_DEBUG_ASSOC(priv, "enter:\n"); + + if (!ctx->ht.enabled) + return; + + ctx->ht.protection = + bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; + ctx->ht.non_gf_sta_present = + !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + ht_conf->single_chain_sufficient = false; + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (sta) { + struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + int maxstreams; + + maxstreams = (ht_cap->mcs.tx_params & + IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; + maxstreams += 1; + + if ((ht_cap->mcs.rx_mask[1] == 0) && + (ht_cap->mcs.rx_mask[2] == 0)) + ht_conf->single_chain_sufficient = true; + if (maxstreams <= 1) + ht_conf->single_chain_sufficient = true; + } else { + /* + * If at all, this can only happen through a race + * when the AP disconnects us while we're still + * setting up the connection, in that case mac80211 + * will soon tell us about that. + */ + ht_conf->single_chain_sufficient = true; + } + rcu_read_unlock(); + break; + case NL80211_IFTYPE_ADHOC: + ht_conf->single_chain_sufficient = true; + break; + default: + break; + } + + IWL_DEBUG_ASSOC(priv, "leave\n"); +} + +static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!ctx->is_active) + return; + + ctx->qos_data.def_qos_parm.qos_flags = 0; + + if (ctx->qos_data.qos_active) + ctx->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (ctx->ht.enabled) + ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + ctx->qos_data.qos_active, + ctx->qos_data.def_qos_parm.qos_flags); + + iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, + sizeof(struct iwl_qosparam_cmd), + &ctx->qos_data.def_qos_parm, NULL); +} + +static inline void iwl_set_no_assoc(struct iwl_priv *priv, + struct ieee80211_vif *vif) +{ + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + iwl_led_disassociate(priv); + /* + * inform the ucode that there is no longer an + * association and that no more packets should be + * sent + */ + ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + ctx->staging.assoc_id = 0; + iwlcore_commit_rxon(priv, ctx); +} + +static void iwlcore_beacon_update(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_priv *priv = hw->priv; + unsigned long flags; + __le64 timestamp; + struct sk_buff *skb = ieee80211_beacon_get(hw, vif); + + if (!skb) + return; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + lockdep_assert_held(&priv->mutex); + + if (!priv->beacon_ctx) { + IWL_ERR(priv, "update beacon but no beacon context!\n"); + dev_kfree_skb(skb); + return; + } + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->beacon_skb) + dev_kfree_skb(priv->beacon_skb); + + priv->beacon_skb = skb; + + timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; + priv->timestamp = le64_to_cpu(timestamp); + + IWL_DEBUG_MAC80211(priv, "leave\n"); + spin_unlock_irqrestore(&priv->lock, flags); + + if (!iwl_is_ready_rf(priv)) { + IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); + return; + } + + priv->cfg->ops->legacy->post_associate(priv); +} + +void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + int ret; + + if (WARN_ON(!priv->cfg->ops->legacy)) + return; + + IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); + + if (!iwl_is_alive(priv)) + return; + + mutex_lock(&priv->mutex); + + if (changes & BSS_CHANGED_QOS) { + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + ctx->qos_data.qos_active = bss_conf->qos; + iwl_update_qos(priv, ctx); + spin_unlock_irqrestore(&priv->lock, flags); + } + + if (changes & BSS_CHANGED_BEACON_ENABLED) { + /* + * the add_interface code must make sure we only ever + * have a single interface that could be beaconing at + * any time. + */ + if (vif->bss_conf.enable_beacon) + priv->beacon_ctx = ctx; + else + priv->beacon_ctx = NULL; + } + + if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_AP) { + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = ieee80211_beacon_get(hw, vif); + } + + if (changes & BSS_CHANGED_BEACON_INT && vif->type == NL80211_IFTYPE_AP) + iwl_send_rxon_timing(priv, ctx); + + if (changes & BSS_CHANGED_BSSID) { + IWL_DEBUG_MAC80211(priv, "BSSID %pM\n", bss_conf->bssid); + + /* + * If there is currently a HW scan going on in the + * background then we need to cancel it else the RXON + * below/in post_associate will fail. + */ + 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"); + mutex_unlock(&priv->mutex); + return; + } + + /* mac80211 only sets assoc when in STATION mode */ + if (vif->type == NL80211_IFTYPE_ADHOC || bss_conf->assoc) { + memcpy(ctx->staging.bssid_addr, + bss_conf->bssid, ETH_ALEN); + + /* currently needed in a few places */ + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + } else { + ctx->staging.filter_flags &= + ~RXON_FILTER_ASSOC_MSK; + } + + } + + /* + * This needs to be after setting the BSSID in case + * mac80211 decides to do both changes at once because + * it will invoke post_associate. + */ + if (vif->type == NL80211_IFTYPE_ADHOC && changes & BSS_CHANGED_BEACON) + iwlcore_beacon_update(hw, vif); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + IWL_DEBUG_MAC80211(priv, "ERP_PREAMBLE %d\n", + bss_conf->use_short_preamble); + if (bss_conf->use_short_preamble) + ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; + else + ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; + } + + if (changes & BSS_CHANGED_ERP_CTS_PROT) { + IWL_DEBUG_MAC80211(priv, "ERP_CTS %d\n", bss_conf->use_cts_prot); + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) + ctx->staging.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + ctx->staging.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + if (bss_conf->use_cts_prot) + ctx->staging.flags |= RXON_FLG_SELF_CTS_EN; + else + ctx->staging.flags &= ~RXON_FLG_SELF_CTS_EN; + } + + if (changes & BSS_CHANGED_BASIC_RATES) { + /* XXX use this information + * + * To do that, remove code from iwl_set_rate() and put something + * like this here: + * + if (A-band) + ctx->staging.ofdm_basic_rates = + bss_conf->basic_rates; + else + ctx->staging.ofdm_basic_rates = + bss_conf->basic_rates >> 4; + ctx->staging.cck_basic_rates = + bss_conf->basic_rates & 0xF; + */ + } + + if (changes & BSS_CHANGED_HT) { + iwl_ht_conf(priv, vif); + + if (priv->cfg->ops->hcmd->set_rxon_chain) + priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx); + } + + if (changes & BSS_CHANGED_ASSOC) { + IWL_DEBUG_MAC80211(priv, "ASSOC %d\n", bss_conf->assoc); + if (bss_conf->assoc) { + priv->timestamp = bss_conf->timestamp; + + iwl_led_associate(priv); + + if (!iwl_is_rfkill(priv)) + priv->cfg->ops->legacy->post_associate(priv); + } else + iwl_set_no_assoc(priv, vif); + } + + if (changes && iwl_is_associated_ctx(ctx) && bss_conf->aid) { + IWL_DEBUG_MAC80211(priv, "Changes (%#x) while associated\n", + changes); + ret = iwl_send_rxon_assoc(priv, ctx); + if (!ret) { + /* Sync active_rxon with latest change. */ + memcpy((void *)&ctx->active, + &ctx->staging, + sizeof(struct iwl_rxon_cmd)); + } + } + + if (changes & BSS_CHANGED_BEACON_ENABLED) { + if (vif->bss_conf.enable_beacon) { + memcpy(ctx->staging.bssid_addr, + bss_conf->bssid, ETH_ALEN); + memcpy(priv->bssid, bss_conf->bssid, ETH_ALEN); + iwl_led_associate(priv); + priv->cfg->ops->legacy->config_ap(priv); + } else + iwl_set_no_assoc(priv, vif); + } + + if (changes & BSS_CHANGED_IBSS) { + ret = priv->cfg->ops->legacy->manage_ibss_station(priv, vif, + bss_conf->ibss_joined); + if (ret) + IWL_ERR(priv, "failed to %s IBSS station %pM\n", + bss_conf->ibss_joined ? "add" : "remove", + bss_conf->bssid); + } + + mutex_unlock(&priv->mutex); + + IWL_DEBUG_MAC80211(priv, "leave\n"); +} +EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed); diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.h b/drivers/net/wireless/iwlwifi/iwl-legacy.h new file mode 100644 index 000000000000..2a746cbc30fe --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.h @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#ifndef __iwl_legacy_h__ +#define __iwl_legacy_h__ + +/* mac80211 handlers */ +int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed); +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw); +void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); + +#endif /* __iwl_legacy_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index d42bb22e5ed5..73f2f3fcb49c 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -61,6 +61,7 @@ #include "iwl-helpers.h" #include "iwl-dev.h" #include "iwl-spectrum.h" +#include "iwl-legacy.h" /* * module name, copyright, version, etc. @@ -3057,22 +3058,22 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) mutex_unlock(&priv->mutex); } -void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) +void iwl3945_post_associate(struct iwl_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - if (!vif || !priv->is_open) + if (!ctx->vif || !priv->is_open) return; - if (vif->type == NL80211_IFTYPE_AP) { + if (ctx->vif->type == NL80211_IFTYPE_AP) { IWL_ERR(priv, "%s Should not be called in AP mode\n", __func__); return; } IWL_DEBUG_ASSOC(priv, "Associated as %d to: %pM\n", - vif->bss_conf.aid, ctx->active.bssid_addr); + ctx->vif->bss_conf.aid, ctx->active.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -3091,18 +3092,18 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; - ctx->staging.assoc_id = cpu_to_le16(vif->bss_conf.aid); + ctx->staging.assoc_id = cpu_to_le16(ctx->vif->bss_conf.aid); IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n", - vif->bss_conf.aid, vif->bss_conf.beacon_int); + ctx->vif->bss_conf.aid, ctx->vif->bss_conf.beacon_int); - if (vif->bss_conf.use_short_preamble) + if (ctx->vif->bss_conf.use_short_preamble) ctx->staging.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; else ctx->staging.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK; if (ctx->staging.flags & RXON_FLG_BAND_24G_MSK) { - if (vif->bss_conf.use_short_slot) + if (ctx->vif->bss_conf.use_short_slot) ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK; else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; @@ -3110,7 +3111,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) iwl3945_commit_rxon(priv, ctx); - switch (vif->type) { + switch (ctx->vif->type) { case NL80211_IFTYPE_STATION: iwl3945_rate_scale_init(priv->hw, IWL_AP_ID); break; @@ -3119,7 +3120,7 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif) break; default: IWL_ERR(priv, "%s Should not be called in %d mode\n", - __func__, vif->type); + __func__, ctx->vif->type); break; } } @@ -3234,9 +3235,10 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return NETDEV_TX_OK; } -void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif) +void iwl3945_config_ap(struct iwl_priv *priv) { struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct ieee80211_vif *vif = ctx->vif; int rc = 0; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -3830,12 +3832,12 @@ struct ieee80211_ops iwl3945_hw_ops = { .stop = iwl3945_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, - .config = iwl_mac_config, + .config = iwl_legacy_mac_config, .configure_filter = iwl3945_configure_filter, .set_key = iwl3945_mac_set_key, .conf_tx = iwl_mac_conf_tx, - .reset_tsf = iwl_mac_reset_tsf, - .bss_info_changed = iwl_bss_info_changed, + .reset_tsf = iwl_legacy_mac_reset_tsf, + .bss_info_changed = iwl_legacy_mac_bss_info_changed, .hw_scan = iwl_mac_hw_scan, .sta_add = iwl3945_mac_sta_add, .sta_remove = iwl_mac_sta_remove, -- cgit v1.2.3 From bd50a8ab9f48787109f6ff761c8f0e185e3d0690 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Oct 2010 09:15:42 -0700 Subject: iwlwifi: fix IBSS beaconing My previous patch to clean up all RXON handling inadvertently broke IBSS because it failed to take into account that unlike in AP mode, IBSS requires beacons to be sent only after setting the RXON assoc. Fix this, clean up the code a bit, improve the error checking around this, and also react to beacon changes in IBSS mode from mac80211. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 47 ++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 58602457e415..11b3d8888360 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -72,6 +72,18 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, return ret; } +static int iwlagn_update_beacon(struct iwl_priv *priv, + struct ieee80211_vif *vif) +{ + lockdep_assert_held(&priv->mutex); + + dev_kfree_skb(priv->beacon_skb); + priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif); + if (!priv->beacon_skb) + return -ENOMEM; + return iwlagn_send_beacon_cmd(priv); +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -201,17 +213,19 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } if (new_assoc) { - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP || - ctx->vif->type == NL80211_IFTYPE_ADHOC)) { - /* - * We'll run into this code path when beaconing is - * enabled, but then we also need to send the beacon - * to the device. - */ - dev_kfree_skb(priv->beacon_skb); - priv->beacon_skb = ieee80211_beacon_get(priv->hw, - ctx->vif); - iwlagn_send_beacon_cmd(priv); + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { + ret = iwlagn_update_beacon(priv, ctx->vif); + if (ret) { + IWL_ERR(priv, + "Error sending required beacon (%d)!\n", + ret); + return ret; + } } priv->start_calib = 0; @@ -228,6 +242,11 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return ret; } memcpy(active, &ctx->staging, sizeof(*active)); + + /* IBSS beacon needs to be sent after setting assoc */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) + if (iwlagn_update_beacon(priv, ctx->vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); } iwl_print_rx_config_cmd(priv, ctx); @@ -558,5 +577,11 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, bss_conf->bssid); } + if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC && + priv->beacon_ctx) { + if (iwlagn_update_beacon(priv, vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); + } + mutex_unlock(&priv->mutex); } -- cgit v1.2.3 From d4daaea656e0b5543c2e37c31934cea8f044b31e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Oct 2010 09:15:43 -0700 Subject: iwlwifi: implement switching iftype while up Implement switching the interface while an interface is up in iwlwifi. Interfaces have to stay on the context they were created on. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 168 ++++++++++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-core.h | 3 + drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + 5 files changed, 130 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 8f07964e4305..6d313c817040 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2589,6 +2589,7 @@ struct ieee80211_ops iwl4965_hw_ops = { .stop = iwlagn_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, + .change_interface = iwl_mac_change_interface, .config = iwl_legacy_mac_config, .configure_filter = iwlagn_configure_filter, .set_key = iwlagn_mac_set_key, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 1050f31d90a4..481c993c2491 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3909,6 +3909,7 @@ struct ieee80211_ops iwlagn_hw_ops = { .stop = iwlagn_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, + .change_interface = iwl_mac_change_interface, .config = iwlagn_mac_config, .configure_filter = iwlagn_configure_filter, .set_key = iwlagn_mac_set_key, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 776713c6a7ff..180d09ec3136 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1427,10 +1427,8 @@ int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(iwl_mac_tx_last_beacon); -static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) +static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { - struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - iwl_connection_init_rx_config(priv, ctx); if (priv->cfg->ops->hcmd->set_rxon_chain) @@ -1439,12 +1437,49 @@ static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif) return iwlcore_commit_rxon(priv, ctx); } +static int iwl_setup_interface(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + struct ieee80211_vif *vif = ctx->vif; + int err; + + lockdep_assert_held(&priv->mutex); + + /* + * This variable will be correct only when there's just + * a single context, but all code using it is for hardware + * that supports only one context. + */ + priv->iw_mode = vif->type; + + ctx->is_active = true; + + err = iwl_set_mode(priv, ctx); + if (err) { + if (!ctx->always_active) + ctx->is_active = false; + return err; + } + + if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && + vif->type == NL80211_IFTYPE_ADHOC) { + /* + * pretend to have high BT traffic as long as we + * are operating in IBSS mode, as this will cause + * the rate scaling etc. to behave as intended. + */ + priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; + } + + return 0; +} + int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *tmp, *ctx = NULL; - int err = 0; + int err; IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", vif->type, vif->addr); @@ -1486,36 +1521,11 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) vif_priv->ctx = ctx; ctx->vif = vif; - /* - * This variable will be correct only when there's just - * a single context, but all code using it is for hardware - * that supports only one context. - */ - priv->iw_mode = vif->type; - - ctx->is_active = true; - - err = iwl_set_mode(priv, vif); - if (err) { - if (!ctx->always_active) - ctx->is_active = false; - goto out_err; - } - - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - vif->type == NL80211_IFTYPE_ADHOC) { - /* - * pretend to have high BT traffic as long as we - * are operating in IBSS mode, as this will cause - * the rate scaling etc. to behave as intended. - */ - priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH; - } - goto out; + err = iwl_setup_interface(priv, ctx); + if (!err) + goto out; - out_err: ctx->vif = NULL; priv->iw_mode = NL80211_IFTYPE_STATION; out: @@ -1526,27 +1536,24 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } EXPORT_SYMBOL(iwl_mac_add_interface); -void iwl_mac_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void iwl_teardown_interface(struct iwl_priv *priv, + struct ieee80211_vif *vif, + bool mode_change) { - struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - IWL_DEBUG_MAC80211(priv, "enter\n"); - - mutex_lock(&priv->mutex); - - WARN_ON(ctx->vif != vif); - ctx->vif = NULL; + lockdep_assert_held(&priv->mutex); if (priv->scan_vif == vif) { iwl_scan_cancel_timeout(priv, 200); iwl_force_scan_end(priv); } - iwl_set_mode(priv, vif); - if (!ctx->always_active) - ctx->is_active = false; + if (!mode_change) { + iwl_set_mode(priv, ctx); + if (!ctx->always_active) + ctx->is_active = false; + } /* * When removing the IBSS interface, overwrite the @@ -1557,6 +1564,22 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, */ if (vif->type == NL80211_IFTYPE_ADHOC) priv->bt_traffic_load = priv->notif_bt_traffic_load; +} + +void iwl_mac_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + + IWL_DEBUG_MAC80211(priv, "enter\n"); + + mutex_lock(&priv->mutex); + + WARN_ON(ctx->vif != vif); + ctx->vif = NULL; + + iwl_teardown_interface(priv, vif, false); memset(priv->bssid, 0, ETH_ALEN); mutex_unlock(&priv->mutex); @@ -1908,6 +1931,63 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) return 0; } +int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum nl80211_iftype newtype, bool newp2p) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *tmp; + u32 interface_modes; + int err; + + newtype = ieee80211_iftype_p2p(newtype, newp2p); + + mutex_lock(&priv->mutex); + + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; + + if (!(interface_modes & BIT(newtype))) { + err = -EBUSY; + goto out; + } + + if (ctx->exclusive_interface_modes & BIT(newtype)) { + for_each_context(priv, tmp) { + if (ctx == tmp) + continue; + + if (!tmp->vif) + continue; + + /* + * The current mode switch would be exclusive, but + * another context is active ... refuse the switch. + */ + err = -EBUSY; + goto out; + } + } + + /* success */ + iwl_teardown_interface(priv, vif, true); + vif->type = newtype; + err = iwl_setup_interface(priv, ctx); + WARN_ON(err); + /* + * We've switched internally, but submitting to the + * device may have failed for some reason. Mask this + * error, because otherwise mac80211 will not switch + * (and set the interface type back) and we'll be + * out of sync with it. + */ + err = 0; + + out: + mutex_unlock(&priv->mutex); + return err; +} +EXPORT_SYMBOL(iwl_mac_change_interface); + /** * iwl_bg_monitor_recover - Timer callback to check for stuck queue and recover * diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 854613e4f2be..8fb063affac4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -432,6 +432,9 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int iwl_mac_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype newtype, bool newp2p); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); void iwlcore_tx_cmd_protection(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 73f2f3fcb49c..6152a86c19b5 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -3832,6 +3832,7 @@ struct ieee80211_ops iwl3945_hw_ops = { .stop = iwl3945_mac_stop, .add_interface = iwl_mac_add_interface, .remove_interface = iwl_mac_remove_interface, + .change_interface = iwl_mac_change_interface, .config = iwl_legacy_mac_config, .configure_filter = iwl3945_configure_filter, .set_key = iwl3945_mac_set_key, -- cgit v1.2.3 From f5682c01eb85fce13d064d232c947322bd7e2631 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 23 Oct 2010 09:15:44 -0700 Subject: iwlagn: turn dynamic smps on while BT is on While BT is on and doing iscan and/or pscan, BT is in listen mode which will impact WiFi throughput, we need to enable dynamic smps in order to improve the rx throughput. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index b01d81a3550b..3427fc2b7d68 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1897,7 +1897,10 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) switch (priv->bt_traffic_load) { case IWL_BT_COEX_TRAFFIC_LOAD_NONE: - smps_request = IEEE80211_SMPS_AUTOMATIC; + if (priv->bt_status) + smps_request = IEEE80211_SMPS_DYNAMIC; + else + smps_request = IEEE80211_SMPS_AUTOMATIC; break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: smps_request = IEEE80211_SMPS_DYNAMIC; -- cgit v1.2.3 From 69d826b6c54de113f02a73990b6f6809289b48cc Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 23 Oct 2010 09:15:45 -0700 Subject: iwlwifi: add new devices to Kconfig Adding description to Kconfig to indicate more devices are being supported by iwlagn Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b82364258dc5..ed424574160e 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -106,6 +106,9 @@ config IWL5000 Intel WiFi Link 1000BGN Intel Wireless WiFi 5150AGN Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN + Intel 6000 Gen 2 Series Wi-Fi Adapters (6000G2A and 6000G2B) + Intel WIreless WiFi Link 6050BGN Gen 2 Adapter + Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" -- cgit v1.2.3 From 34d59c07e9ad7130813c28f8554ef1298af923b7 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 23 Oct 2010 09:15:46 -0700 Subject: iwlagn: use 6000g2b uCode for 130 series devices For 130 series device, 6000g2b uCode will be used, no need to have additional defines for 130 devices, so remove those. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index eacbce0d88b6..b1816900980c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -53,13 +53,11 @@ #define IWL6000_UCODE_API_MAX 4 #define IWL6050_UCODE_API_MAX 5 #define IWL6000G2_UCODE_API_MAX 5 -#define IWL130_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 4 #define IWL6050_UCODE_API_MIN 4 #define IWL6000G2_UCODE_API_MIN 4 -#define IWL130_UCODE_API_MIN 5 #define IWL6000_FW_PRE "iwlwifi-6000-" #define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode" @@ -77,10 +75,6 @@ #define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode" #define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api) -#define IWL130_FW_PRE "iwlwifi-130-" -#define _IWL130_MODULE_FIRMWARE(api) IWL130_FW_PRE #api ".ucode" -#define IWL130_MODULE_FIRMWARE(api) _IWL130_MODULE_FIRMWARE(api) - static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ @@ -838,8 +832,8 @@ struct iwl_cfg iwl6000_3agn_cfg = { struct iwl_cfg iwl130_bgn_cfg = { .name = "Intel(R) 130 Series 1x1 BGN", .fw_name_pre = IWL6000G2B_FW_PRE, - .ucode_api_max = IWL130_UCODE_API_MAX, - .ucode_api_min = IWL130_UCODE_API_MIN, + .ucode_api_max = IWL6000G2_UCODE_API_MAX, + .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G|IWL_SKU_N, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, @@ -858,8 +852,8 @@ struct iwl_cfg iwl130_bgn_cfg = { struct iwl_cfg iwl130_bg_cfg = { .name = "Intel(R) 130 Series 1x2 BG", .fw_name_pre = IWL6000G2B_FW_PRE, - .ucode_api_max = IWL130_UCODE_API_MAX, - .ucode_api_min = IWL130_UCODE_API_MIN, + .ucode_api_max = IWL6000G2_UCODE_API_MAX, + .ucode_api_min = IWL6000G2_UCODE_API_MIN, .sku = IWL_SKU_G, .valid_tx_ant = ANT_A, .valid_rx_ant = ANT_A, @@ -878,4 +872,3 @@ MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL130_MODULE_FIRMWARE(IWL130_UCODE_API_MAX)); -- cgit v1.2.3 From c8aea565e8f715d9f10064b1cbfbc15bf75df501 Mon Sep 17 00:00:00 2001 From: Gery Kahn Date: Tue, 5 Oct 2010 16:09:05 +0200 Subject: wl1271: ref_clock cosmetic changes Cosmetic cleanup for ref_clock code while configured by board. Signed-off-by: Gery Kahn Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_boot.c | 10 ++++------ include/linux/wl12xx.h | 8 ++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_boot.c b/drivers/net/wireless/wl12xx/wl1271_boot.c index b91021242098..5b190728ca55 100644 --- a/drivers/net/wireless/wl12xx/wl1271_boot.c +++ b/drivers/net/wireless/wl12xx/wl1271_boot.c @@ -471,20 +471,19 @@ int wl1271_boot(struct wl1271 *wl) { int ret = 0; u32 tmp, clk, pause; - int ref_clock = wl->ref_clock; wl1271_boot_hw_version(wl); - if (ref_clock == 0 || ref_clock == 2 || ref_clock == 4) + if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; - else if (ref_clock == 1 || ref_clock == 3) + else if (wl->ref_clock == 1 || wl->ref_clock == 3) /* ref clk: 26/52 */ clk = 0x5; else return -EINVAL; - if (ref_clock != 0) { + if (wl->ref_clock != 0) { u16 val; /* Set clock type (open drain) */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); @@ -529,8 +528,7 @@ int wl1271_boot(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - /* 2 */ - clk |= (ref_clock << 1) << 4; + clk |= (wl->ref_clock << 1) << 4; wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index 4f902e1908aa..bebb8efea0a6 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -24,6 +24,14 @@ #ifndef _LINUX_WL12XX_H #define _LINUX_WL12XX_H +/* The board reference clock values */ +enum { + WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ + WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ + WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ + WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ +}; + struct wl12xx_platform_data { void (*set_power)(bool enable); /* SDIO only: IRQ number if WLAN_IRQ line is used, 0 for SDIO IRQs */ -- cgit v1.2.3 From 6c6e669ed6282788d6045397ce0f201edc400d9d Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 12 Oct 2010 14:49:09 +0200 Subject: wl1271: TX aggregation optimization In case the aggregation buffer is too small to hold all available packets, the buffer is transferred to the FW and no more packets are aggregated. Although there may be enough available TX blocks, no additional packets will be handled by the current TX work. Fix this by flushing the aggregation buffer when it's full, and continue transferring packets as long as there are enough available TX blocks. Signed-off-by: Ido Yariv Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_tx.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index e3dc13c4d01a..b13b37330036 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -52,7 +52,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, int id, ret = -EBUSY; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) - return -EBUSY; + return -EAGAIN; /* allocate free identifier for the packet */ id = wl1271_tx_id(wl, skb); @@ -210,7 +210,8 @@ void wl1271_tx_work(struct work_struct *work) struct sk_buff *skb; bool woken_up = false; u32 sta_rates = 0; - u32 buf_offset; + u32 buf_offset = 0; + bool sent_packets = false; int ret; /* check if the rates supported by the AP have changed */ @@ -233,9 +234,6 @@ void wl1271_tx_work(struct work_struct *work) wl1271_acx_rate_policies(wl); } - /* Prepare the transfer buffer, by aggregating all - * available packets */ - buf_offset = 0; while ((skb = skb_dequeue(&wl->tx_queue))) { if (!woken_up) { ret = wl1271_ps_elp_wakeup(wl, false); @@ -245,10 +243,20 @@ void wl1271_tx_work(struct work_struct *work) } ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); - if (ret == -EBUSY) { + if (ret == -EAGAIN) { /* - * Either the firmware buffer is full, or the - * aggregation buffer is. + * Aggregation buffer is full. + * Flush buffer and try again. + */ + skb_queue_head(&wl->tx_queue, skb); + wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + sent_packets = true; + buf_offset = 0; + continue; + } else if (ret == -EBUSY) { + /* + * Firmware buffer is full. * Queue back last skb, and stop aggregating. */ skb_queue_head(&wl->tx_queue, skb); @@ -265,6 +273,9 @@ out_ack: if (buf_offset) { wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, buf_offset, true); + sent_packets = true; + } + if (sent_packets) { /* interrupt the firmware with the new packets */ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); } -- cgit v1.2.3 From a522550a283de31c7cfc30c7a129ce584e38c582 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 12 Oct 2010 14:49:10 +0200 Subject: wl1271: Fix TX starvation While wl1271_irq_work handles RX directly (by calling wl1271_rx), a different work is scheduled for transmitting packets. The IRQ work might handle more than one interrupt during a single call, including multiple TX completion interrupts. This might starve TX, since no packets are transmitted until all interrupts are handled. Fix this by calling the TX work function directly, instead of deferring it. Signed-off-by: Ido Yariv Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 19 +++++++++++++++---- drivers/net/wireless/wl12xx/wl1271_tx.c | 14 ++++++++++---- drivers/net/wireless/wl12xx/wl1271_tx.h | 1 + 4 files changed, 27 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 8a4cd763e5a2..4a034a3f7148 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -351,6 +351,7 @@ struct wl1271 { #define WL1271_FLAG_IDLE_REQUESTED (11) #define WL1271_FLAG_PSPOLL_FAILURE (12) #define WL1271_FLAG_STA_STATE_SENT (13) +#define WL1271_FLAG_FW_TX_BUSY (14) unsigned long flags; struct wl1271_partition_set part; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 48a4b9961ae6..18aff225bf82 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -481,9 +481,9 @@ static void wl1271_fw_status(struct wl1271 *wl, total += cnt; } - /* if more blocks are available now, schedule some tx work */ - if (total && !skb_queue_empty(&wl->tx_queue)) - ieee80211_queue_work(wl->hw, &wl->tx_work); + /* if more blocks are available now, tx work can be scheduled */ + if (total) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); /* update the host-chipset time offset */ getnstimeofday(&ts); @@ -537,6 +537,16 @@ static void wl1271_irq_work(struct work_struct *work) (wl->tx_results_count & 0xff)) wl1271_tx_complete(wl); + /* Check if any tx blocks were freed */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && + !skb_queue_empty(&wl->tx_queue)) { + /* + * In order to avoid starvation of the TX path, + * call the work function directly. + */ + wl1271_tx_work_locked(wl); + } + wl1271_rx(wl, wl->fw_status); } @@ -867,7 +877,8 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * before that, the tx_work will not be initialized! */ - ieee80211_queue_work(wl->hw, &wl->tx_work); + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + ieee80211_queue_work(wl->hw, &wl->tx_work); /* * The workqueue is slow to process the tx_queue and we need stop diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index b13b37330036..cf32a77a4ff5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -204,9 +204,8 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) return enabled_rates; } -void wl1271_tx_work(struct work_struct *work) +void wl1271_tx_work_locked(struct wl1271 *wl) { - struct wl1271 *wl = container_of(work, struct wl1271, tx_work); struct sk_buff *skb; bool woken_up = false; u32 sta_rates = 0; @@ -223,8 +222,6 @@ void wl1271_tx_work(struct work_struct *work) spin_unlock_irqrestore(&wl->wl_lock, flags); } - mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) goto out; @@ -260,6 +257,8 @@ void wl1271_tx_work(struct work_struct *work) * Queue back last skb, and stop aggregating. */ skb_queue_head(&wl->tx_queue, skb); + /* No work left, avoid scheduling redundant tx work */ + set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); goto out_ack; } else if (ret < 0) { dev_kfree_skb(skb); @@ -283,7 +282,14 @@ out_ack: out: if (woken_up) wl1271_ps_elp_sleep(wl); +} +void wl1271_tx_work(struct work_struct *work) +{ + struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + + mutex_lock(&wl->mutex); + wl1271_tx_work_locked(wl); mutex_unlock(&wl->mutex); } diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index d12a129ad11c..f1c906519b7d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -140,6 +140,7 @@ static inline int wl1271_tx_get_queue(int queue) } void wl1271_tx_work(struct work_struct *work); +void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl); -- cgit v1.2.3 From 25eeb9e3876a161e3afcc820c6cb72e13f9b7c7e Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 12 Oct 2010 16:20:06 +0200 Subject: wl1271: Allocate TX descriptors more efficiently On each TX descriptor allocation, a free entry is found by traversing the TX descriptors array. Improve this by holding a bitmap of all TX descriptors, and using efficient bit operations to search for free entries. Signed-off-by: Ido Yariv Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 1 + drivers/net/wireless/wl12xx/wl1271_main.c | 1 + drivers/net/wireless/wl12xx/wl1271_tx.c | 38 ++++++++++++++++++------------- 3 files changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 4a034a3f7148..718e96d97d0b 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -398,6 +398,7 @@ struct wl1271 { struct work_struct tx_work; /* Pending TX frames */ + unsigned long tx_frames_map[BITS_TO_LONGS(ACX_TX_DESCRIPTORS)]; struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS]; int tx_frames_cnt; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 18aff225bf82..0fd472597fa6 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2532,6 +2532,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sg_enabled = true; wl->hw_pg_ver = -1; + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index cf32a77a4ff5..85878e5e7526 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -30,17 +30,26 @@ #include "wl1271_ps.h" #include "wl1271_tx.h" -static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb) +static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) { - int i; - for (i = 0; i < ACX_TX_DESCRIPTORS; i++) - if (wl->tx_frames[i] == NULL) { - wl->tx_frames[i] = skb; - wl->tx_frames_cnt++; - return i; - } + int id; + + id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); + if (id >= ACX_TX_DESCRIPTORS) + return -EBUSY; + + __set_bit(id, wl->tx_frames_map); + wl->tx_frames[id] = skb; + wl->tx_frames_cnt++; + return id; +} - return -EBUSY; +static void wl1271_free_tx_id(struct wl1271 *wl, int id) +{ + if (__test_and_clear_bit(id, wl->tx_frames_map)) { + wl->tx_frames[id] = NULL; + wl->tx_frames_cnt--; + } } static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, @@ -55,7 +64,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return -EAGAIN; /* allocate free identifier for the packet */ - id = wl1271_tx_id(wl, skb); + id = wl1271_alloc_tx_id(wl, skb); if (id < 0) return id; @@ -79,8 +88,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, "tx_allocate: size: %d, blocks: %d, id: %d", total_len, total_blocks, id); } else { - wl->tx_frames[id] = NULL; - wl->tx_frames_cnt--; + wl1271_free_tx_id(wl, id); } return ret; @@ -352,8 +360,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, /* return the packet to the stack */ ieee80211_tx_status(wl->hw, skb); - wl->tx_frames[result->id] = NULL; - wl->tx_frames_cnt--; + wl1271_free_tx_id(wl, result->id); } /* Called upon reception of a TX complete interrupt */ @@ -422,11 +429,10 @@ void wl1271_tx_reset(struct wl1271 *wl) for (i = 0; i < ACX_TX_DESCRIPTORS; i++) if (wl->tx_frames[i] != NULL) { skb = wl->tx_frames[i]; - wl->tx_frames[i] = NULL; + wl1271_free_tx_id(wl, i); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); ieee80211_tx_status(wl->hw, skb); } - wl->tx_frames_cnt = 0; } #define WL1271_TX_FLUSH_TIMEOUT 500000 -- cgit v1.2.3 From 2fe33e8cff354a3f320549544bffebbbab680145 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Tue, 12 Oct 2010 14:49:12 +0200 Subject: wl1271: Fix TX queue low watermark handling The number of entries in the TX queue is compared to the low watermark value each time TX completion interrupts are handled. However, the fact that a TX completion arrived does not necessarily mean there are any less skbs in the TX queue. In addition, a TX completion interrupt does not necessarily mean that there are any new available TX blocks. Thus, queuing TX work when the low watermark is reached might not be needed. Fix this by moving the low watermark handling to the TX work function, and avoid queuing TX work in this case. Signed-off-by: Ido Yariv Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_tx.c | 35 +++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 85878e5e7526..dc3172bea0dd 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -212,6 +212,20 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) return enabled_rates; } +static void handle_tx_low_watermark(struct wl1271 *wl) +{ + unsigned long flags; + + if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && + skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { + /* firmware buffer has space, restart queues */ + spin_lock_irqsave(&wl->wl_lock, flags); + ieee80211_wake_queues(wl->hw); + clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); + spin_unlock_irqrestore(&wl->wl_lock, flags); + } +} + void wl1271_tx_work_locked(struct wl1271 *wl) { struct sk_buff *skb; @@ -225,6 +239,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl) if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags))) { unsigned long flags; + spin_lock_irqsave(&wl->wl_lock, flags); sta_rates = wl->sta_rate_set; spin_unlock_irqrestore(&wl->wl_lock, flags); @@ -285,6 +300,7 @@ out_ack: if (sent_packets) { /* interrupt the firmware with the new packets */ wl1271_write32(wl, WL1271_HOST_WR_ACCESS, wl->tx_packets_count); + handle_tx_low_watermark(wl); } out: @@ -399,19 +415,6 @@ void wl1271_tx_complete(struct wl1271 *wl) wl->tx_results_count++; } - - if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && - skb_queue_len(&wl->tx_queue) <= WL1271_TX_QUEUE_LOW_WATERMARK) { - unsigned long flags; - - /* firmware buffer has space, restart queues */ - wl1271_debug(DEBUG_TX, "tx_complete: waking queues"); - spin_lock_irqsave(&wl->wl_lock, flags); - ieee80211_wake_queues(wl->hw); - clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); - spin_unlock_irqrestore(&wl->wl_lock, flags); - ieee80211_queue_work(wl->hw, &wl->tx_work); - } } /* caller must hold wl->mutex */ @@ -426,6 +429,12 @@ void wl1271_tx_reset(struct wl1271 *wl) ieee80211_tx_status(wl->hw, skb); } + /* + * Make sure the driver is at a consistent state, in case this + * function is called from a context other than interface removal. + */ + handle_tx_low_watermark(wl); + for (i = 0; i < ACX_TX_DESCRIPTORS; i++) if (wl->tx_frames[i] != NULL) { skb = wl->tx_frames[i]; -- cgit v1.2.3 From e8b03a2b8debc6056f6f43d24f98f601097301a1 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 13 Oct 2010 16:09:39 +0200 Subject: wl1271: 11n Support, Add Definitions Two acx commands: ht_capabilities & ht_information, 11n sta capabilities macro. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271.h | 11 ++++- drivers/net/wireless/wl12xx/wl1271_acx.h | 81 +++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_main.c | 15 ++++++ 3 files changed, 106 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h index 718e96d97d0b..ab53162b4343 100644 --- a/drivers/net/wireless/wl12xx/wl1271.h +++ b/drivers/net/wireless/wl12xx/wl1271.h @@ -434,7 +434,12 @@ struct wl1271 { /* Our association ID */ u16 aid; - /* currently configured rate set */ + /* + * currently configured rate set: + * bits 0-15 - 802.11abg rates + * bits 16-23 - 802.11n MCS index mask + * support only 1 stream, thus only 8 bits for the MCS rates (0-7). + */ u32 sta_rate_set; u32 basic_rate_set; u32 basic_rate; @@ -511,4 +516,8 @@ int wl1271_plt_stop(struct wl1271 *wl); #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ +/* Macros to handle wl1271.sta_rate_set */ +#define HW_BG_RATES_MASK 0xffff +#define HW_HT_RATES_OFFSET 16 + #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index ebb341d36e8c..f090a0470ebc 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -964,6 +964,87 @@ struct wl1271_acx_rssi_snr_avg_weights { u8 snr_data; }; +/* + * ACX_PEER_HT_CAP + * Configure HT capabilities - declare the capabilities of the peer + * we are connected to. + */ +struct wl1271_acx_ht_capabilities { + struct acx_header header; + + /* + * bit 0 - Allow HT Operation + * bit 1 - Allow Greenfield format in TX + * bit 2 - Allow Short GI in TX + * bit 3 - Allow L-SIG TXOP Protection in TX + * bit 4 - Allow HT Control fields in TX. + * Note, driver will still leave space for HT control in packets + * regardless of the value of this field. FW will be responsible + * to drop the HT field from any frame when this Bit set to 0. + * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD. + * Exact policy setting for this feature is TBD. + * Note, this bit can only be set to 1 if bit 3 is set to 1. + */ + __le32 ht_capabilites; + + /* + * Indicates to which peer these capabilities apply. + * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance + * for all peers. + * Only valid for IBSS/DLS operation. + */ + u8 mac_address[ETH_ALEN]; + + /* + * This the maximum A-MPDU length supported by the AP. The FW may not + * exceed this length when sending A-MPDUs + */ + u8 ampdu_max_length; + + /* This is the minimal spacing required when sending A-MPDUs to the AP*/ + u8 ampdu_min_spacing; +} __packed; + +/* HT Capabilites Fw Bit Mask Mapping */ +#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0) +#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1) +#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2) +#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3) +#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4) +#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5) + + +/* + * ACX_HT_BSS_OPERATION + * Configure HT capabilities - AP rules for behavior in the BSS. + */ +struct wl1271_acx_ht_information { + struct acx_header header; + + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ + u8 rifs_mode; + + /* Values: 0 - 3 like in spec */ + u8 ht_protection; + + /* Values: 0 - GF protection not required, 1 - GF protection required */ + u8 gf_protection; + + /*Values: 0 - TX Burst limit not required, 1 - TX Burst Limit required*/ + u8 ht_tx_burst_limit; + + /* + * Values: 0 - Dual CTS protection not required, + * 1 - Dual CTS Protection required + * Note: When this value is set to 1 FW will protect all TXOP with RTS + * frame and will not use CTS-to-self regardless of the value of the + * ACX_CTS_PROTECTION information element + */ + u8 dual_cts_protection; + + u8 padding[3]; +} __packed; + struct wl1271_acx_fw_tsf_information { struct acx_header header; diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 0fd472597fa6..5d5f4c6a9644 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2145,6 +2145,21 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { 0 /* CONF_HW_RXTX_RATE_1 */ }; +/* 11n STA capabilities */ +#define HW_RX_HIGHEST_RATE 72 + +#define WL1271_HT_CAP { \ + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ + .ht_supported = true, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ + .mcs = { \ + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \ + .rx_highest = cpu_to_le16(HW_RX_HIGHEST_RATE), \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ + }, \ +} + /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1271_band_2ghz = { .channels = wl1271_channels, -- cgit v1.2.3 From c4db1c879679e795689ef3c9dd7d3f6568ea14c5 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 13 Oct 2010 16:09:40 +0200 Subject: wl1271: 11n Support, ACX Commands Added ACX command to the FW for 11n support. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_acx.c | 83 ++++++++++++++++++++++++++++++++ drivers/net/wireless/wl12xx/wl1271_acx.h | 5 ++ 2 files changed, 88 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.c b/drivers/net/wireless/wl12xx/wl1271_acx.c index 618993405262..bd7f95f4eef3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.c +++ b/drivers/net/wireless/wl12xx/wl1271_acx.c @@ -1226,6 +1226,89 @@ out: return ret; } +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation) +{ + struct wl1271_acx_ht_capabilities *acx; + u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + /* Allow HT Operation ? */ + if (allow_ht_operation) { + acx->ht_capabilites = + WL1271_ACX_FW_CAP_HT_OPERATION; + if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; + if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; + if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) + acx->ht_capabilites |= + WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; + + /* get data from A-MPDU parameters field */ + acx->ampdu_max_length = ht_cap->ampdu_factor; + acx->ampdu_min_spacing = ht_cap->ampdu_density; + + memcpy(acx->mac_address, mac_address, ETH_ALEN); + } else { /* HT operations are not allowed */ + acx->ht_capabilites = 0; + } + + ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx ht capabilities setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_set_ht_information(struct wl1271 *wl, + u16 ht_operation_mode) +{ + struct wl1271_acx_ht_information *acx; + int ret = 0; + + wl1271_debug(DEBUG_ACX, "acx ht information setting"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->ht_protection = + (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); + acx->rifs_mode = 0; + acx->gf_protection = 0; + acx->ht_tx_burst_limit = 0; + acx->dual_cts_protection = 0; + + ret = wl1271_cmd_configure(wl, ACX_HT_BSS_OPERATION, acx, sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx ht information setting failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime) { struct wl1271_acx_fw_tsf_information *tsf_info; diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index f090a0470ebc..758916760912 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -1174,6 +1174,11 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid); int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, s16 thold, u8 hyst); int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); +int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, + struct ieee80211_sta_ht_cap *ht_cap, + bool allow_ht_operation); +int wl1271_acx_set_ht_information(struct wl1271 *wl, + u16 ht_operation_mode); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); #endif /* __WL1271_ACX_H__ */ -- cgit v1.2.3 From 18357850b694ba3fa29363c7d86ccd8783f4a065 Mon Sep 17 00:00:00 2001 From: Shahar Levi Date: Wed, 13 Oct 2010 16:09:41 +0200 Subject: wl1271: 11n Support, functionality and configuration ability Add 11n ability in scan, connection and using MCS rates. The configuration is temporary due to the code incomplete and still in testing process. That plans to be remove in the future. Signed-off-by: Shahar Levi Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/Kconfig | 10 ++++ drivers/net/wireless/wl12xx/wl1271_main.c | 96 +++++++++++++++++++++++++------ drivers/net/wireless/wl12xx/wl1271_rx.c | 6 ++ drivers/net/wireless/wl12xx/wl1271_tx.c | 11 ++++ 4 files changed, 105 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index b447559f1db5..1b3b7bdd6a19 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -18,6 +18,16 @@ config WL1271 If you choose to build a module, it'll be called wl1271. Say N if unsure. +config WL1271_HT + bool "TI wl1271 802.11 HT support (EXPERIMENTAL)" + depends on WL1271 && EXPERIMENTAL + default n + ---help--- + This will enable 802.11 HT support for TI wl1271 chipset. + + That configuration is temporary due to the code incomplete and + still in testing process. + config WL1271_SPI tristate "TI wl1271 SPI support" depends on WL1271 && SPI_MASTER diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 5d5f4c6a9644..532ccd01cf6f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -861,12 +861,32 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_sta *sta = txinfo->control.sta; unsigned long flags; - /* peek into the rates configured in the STA entry */ + /* + * peek into the rates configured in the STA entry. + * The rates set after connection stage, The first block only BG sets: + * the compare is for bit 0-16 of sta_rate_set. The second block add + * HT rates in case of HT supported. + */ spin_lock_irqsave(&wl->wl_lock, flags); - if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { + if (sta && + (sta->supp_rates[conf->channel->band] != + (wl->sta_rate_set & HW_BG_RATES_MASK))) { wl->sta_rate_set = sta->supp_rates[conf->channel->band]; set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); } + +#ifdef CONFIG_WL1271_HT + if (sta && + sta->ht_cap.ht_supported && + ((wl->sta_rate_set >> HW_HT_RATES_OFFSET) != + sta->ht_cap.mcs.rx_mask[0])) { + /* Clean MCS bits before setting them */ + wl->sta_rate_set &= HW_BG_RATES_MASK; + wl->sta_rate_set |= + (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); + set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); + } +#endif spin_unlock_irqrestore(&wl->wl_lock, flags); /* queue the packet */ @@ -1720,6 +1740,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, { enum wl1271_cmd_ps_mode mode; struct wl1271 *wl = hw->priv; + struct ieee80211_sta *sta = ieee80211_find_sta(vif, bss_conf->bssid); bool do_join = false; bool set_assoc = false; int ret; @@ -1938,6 +1959,37 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, } } + /* + * Takes care of: New association with HT enable, + * HT information change in beacon. + */ + if (sta && + (changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", ret); + goto out_sleep; + } + ret = wl1271_acx_set_ht_information(wl, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out_sleep; + } + } + /* + * Takes care of: New association without HT, + * Disassociation. + */ + else if (sta && (changed & BSS_CHANGED_ASSOC)) { + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, false); + if (ret < 0) { + wl1271_warning("Set ht cap false failed %d", ret); + goto out_sleep; + } + } + if (changed & BSS_CHANGED_ARP_FILTER) { __be32 addr = bss_conf->arp_addr_list[0]; WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); @@ -2118,14 +2170,14 @@ static struct ieee80211_channel wl1271_channels[] = { /* mapping to indexes for wl1271_rates */ static const u8 wl1271_rate_to_idx_2ghz[] = { /* MCS rates are used only with 11n */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */ + 7, /* CONF_HW_RXTX_RATE_MCS7 */ + 6, /* CONF_HW_RXTX_RATE_MCS6 */ + 5, /* CONF_HW_RXTX_RATE_MCS5 */ + 4, /* CONF_HW_RXTX_RATE_MCS4 */ + 3, /* CONF_HW_RXTX_RATE_MCS3 */ + 2, /* CONF_HW_RXTX_RATE_MCS2 */ + 1, /* CONF_HW_RXTX_RATE_MCS1 */ + 0, /* CONF_HW_RXTX_RATE_MCS0 */ 11, /* CONF_HW_RXTX_RATE_54 */ 10, /* CONF_HW_RXTX_RATE_48 */ @@ -2148,6 +2200,7 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { /* 11n STA capabilities */ #define HW_RX_HIGHEST_RATE 72 +#ifdef CONFIG_WL1271_HT #define WL1271_HT_CAP { \ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ .ht_supported = true, \ @@ -2159,6 +2212,11 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ }, \ } +#else +#define WL1271_HT_CAP { \ + .ht_supported = false, \ +} +#endif /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1271_band_2ghz = { @@ -2166,6 +2224,7 @@ static struct ieee80211_supported_band wl1271_band_2ghz = { .n_channels = ARRAY_SIZE(wl1271_channels), .bitrates = wl1271_rates, .n_bitrates = ARRAY_SIZE(wl1271_rates), + .ht_cap = WL1271_HT_CAP, }; /* 5 GHz data rates for WL1273 */ @@ -2248,14 +2307,14 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = { /* mapping to indexes for wl1271_rates_5ghz */ static const u8 wl1271_rate_to_idx_5ghz[] = { /* MCS rates are used only with 11n */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS5 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS4 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS3 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS2 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS1 */ - CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS0 */ + 7, /* CONF_HW_RXTX_RATE_MCS7 */ + 6, /* CONF_HW_RXTX_RATE_MCS6 */ + 5, /* CONF_HW_RXTX_RATE_MCS5 */ + 4, /* CONF_HW_RXTX_RATE_MCS4 */ + 3, /* CONF_HW_RXTX_RATE_MCS3 */ + 2, /* CONF_HW_RXTX_RATE_MCS2 */ + 1, /* CONF_HW_RXTX_RATE_MCS1 */ + 0, /* CONF_HW_RXTX_RATE_MCS0 */ 7, /* CONF_HW_RXTX_RATE_54 */ 6, /* CONF_HW_RXTX_RATE_48 */ @@ -2280,6 +2339,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { .n_channels = ARRAY_SIZE(wl1271_channels_5ghz), .bitrates = wl1271_rates_5ghz, .n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz), + .ht_cap = WL1271_HT_CAP, }; static const u8 *wl1271_band_rate_to_idx[] = { diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index bea133b6e489..ac13f7d25219 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -53,6 +53,12 @@ static void wl1271_rx_status(struct wl1271 *wl, status->band = wl->band; status->rate_idx = wl1271_rate_to_idx(wl, desc->rate); +#ifdef CONFIG_WL1271_HT + /* 11n support */ + if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) + status->flag |= RX_FLAG_HT; +#endif + status->signal = desc->rssi; /* diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index dc3172bea0dd..87a5aed00c8c 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -209,6 +209,17 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) rate_set >>= 1; } +#ifdef CONFIG_WL1271_HT + /* MCS rates indication are on bits 16 - 23 */ + rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; + + for (bit = 0; bit < 8; bit++) { + if (rate_set & 0x1) + enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); + rate_set >>= 1; + } +#endif + return enabled_rates; } -- cgit v1.2.3 From 6a2de93b2553c2e9a72997370534993c85c1eee6 Mon Sep 17 00:00:00 2001 From: Teemu Paasikivi Date: Thu, 14 Oct 2010 11:00:04 +0200 Subject: wl1271: Fix warning about unsupported RX rate While scanning, it is possible that beacon and probe response frames are received on other band than configured to the driver. In rx status handling this has caused "Unsupported RX rate from HW" warnings. This patch changes the wl1271_rate_to_index function to take the band of the received frame as a parameter instead of using value configuret to wl->band. Signed-off-by: Teemu Paasikivi Reviewed-by: Juuso Oikarinen Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 6 +++--- drivers/net/wireless/wl12xx/wl1271_rx.c | 10 +++++++++- drivers/net/wireless/wl12xx/wl1271_rx.h | 2 +- drivers/net/wireless/wl12xx/wl1271_tx.c | 2 +- drivers/net/wireless/wl12xx/wl1271_tx.h | 2 +- 5 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 532ccd01cf6f..63036b53f9e4 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -2367,18 +2367,18 @@ static const struct ieee80211_ops wl1271_ops = { }; -u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate) +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band) { u8 idx; - BUG_ON(wl->band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); + BUG_ON(band >= sizeof(wl1271_band_rate_to_idx)/sizeof(u8 *)); if (unlikely(rate >= CONF_HW_RXTX_RATE_MAX)) { wl1271_error("Illegal RX rate from HW: %d", rate); return 0; } - idx = wl1271_band_rate_to_idx[wl->band][rate]; + idx = wl1271_band_rate_to_idx[band][rate]; if (unlikely(idx == CONF_HW_RXTX_RATE_UNSUPPORTED)) { wl1271_error("Unsupported RX rate from HW: %d", rate); return 0; diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index ac13f7d25219..35448e7c0dd5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -48,10 +48,18 @@ static void wl1271_rx_status(struct wl1271 *wl, struct ieee80211_rx_status *status, u8 beacon) { + enum ieee80211_band desc_band; + memset(status, 0, sizeof(struct ieee80211_rx_status)); status->band = wl->band; - status->rate_idx = wl1271_rate_to_idx(wl, desc->rate); + + if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) + desc_band = IEEE80211_BAND_2GHZ; + else + desc_band = IEEE80211_BAND_5GHZ; + + status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); #ifdef CONFIG_WL1271_HT /* 11n support */ diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h index 13a232333b13..6d41981ce53f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.h +++ b/drivers/net/wireless/wl12xx/wl1271_rx.h @@ -116,6 +116,6 @@ struct wl1271_rx_descriptor { } __packed; void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status); -u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); #endif diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 87a5aed00c8c..46fafe08f81a 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -350,7 +350,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, if (result->status == TX_SUCCESS) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_ACK; - rate = wl1271_rate_to_idx(wl, result->rate_class_index); + rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); retries = result->ack_failures; } else if (result->status == TX_RETRY_EXCEEDED) { wl->stats.excessive_retries++; diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h index f1c906519b7d..9dc6f228c0de 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.h +++ b/drivers/net/wireless/wl12xx/wl1271_tx.h @@ -144,7 +144,7 @@ void wl1271_tx_work_locked(struct wl1271 *wl); void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl); -u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate); +u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); #endif -- cgit v1.2.3 From 5404643139c16e56d31a6ebd09cfa6db1eb03a36 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 20 Oct 2010 15:15:52 +0300 Subject: wl1271: exit ELP mode when setting enabled rates in tx This bug was being triggered by a call to acx_rate_policies in tx_work without calling ps_elp_wakeup first. If we have full PSM enabled, this happens rather often, immediately after association. Reported-by: Tuomas Katila Signed-off-by: Luciano Coelho Tested-by: Tuomas Katila --- drivers/net/wireless/wl12xx/wl1271_tx.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c index 46fafe08f81a..279be5b98d9f 100644 --- a/drivers/net/wireless/wl12xx/wl1271_tx.c +++ b/drivers/net/wireless/wl12xx/wl1271_tx.c @@ -261,6 +261,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) /* if rates have changed, re-configure the rate policy */ if (unlikely(sta_rates)) { + ret = wl1271_ps_elp_wakeup(wl, false); + if (ret < 0) + goto out; + woken_up = true; + wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); wl1271_acx_rate_policies(wl); } -- cgit v1.2.3 From ff6d76fd3d45ed5494287e57d76073739721214b Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Mon, 25 Oct 2010 15:30:03 +0200 Subject: wireless/wl1271: remove redundant if-statement v2 wl1271_ps_elp_sleep() is void and cannot return a value. Signed-off-by: Nicolas Kaiser Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_event.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c index 7b3f50382963..38ccef7d73a5 100644 --- a/drivers/net/wireless/wl12xx/wl1271_event.c +++ b/drivers/net/wireless/wl12xx/wl1271_event.c @@ -134,8 +134,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* go to extremely low power mode */ wl1271_ps_elp_sleep(wl); - if (ret < 0) - break; break; case EVENT_EXIT_POWER_SAVE_FAIL: wl1271_debug(DEBUG_PSM, "PSM exit failed"); -- cgit v1.2.3 From fb2382c75b1292aff0ebc8e209b0cb9ba70bb2cf Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Mon, 25 Oct 2010 11:24:29 +0200 Subject: wl1271: Fix RX path stall The wl1271_rx function loops through packets in an aggregated buffer. Each packet in the buffer is handled by a call to wl1271_rx_handle_data, which will fail if skb memory allocation fails or production mode is enabled. These failures currently prevent the rx counters to be incremented, thus causing the rx loop to run forever. Fix this by ignoring error codes reported wl1271_rx_handle_data function. This essentially means that frames will be dropped in production mode, which is the intetion, and frames will be dropped if memory allocation fails, which is a decent way to recover from that situation. Signed-off-by: Juuso Oikarinen Tested-by: Tuomas Katila Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_rx.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.c b/drivers/net/wireless/wl12xx/wl1271_rx.c index 35448e7c0dd5..cacfee56a0d0 100644 --- a/drivers/net/wireless/wl12xx/wl1271_rx.c +++ b/drivers/net/wireless/wl12xx/wl1271_rx.c @@ -184,10 +184,14 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status) while (pkt_offset < buf_size) { pkt_length = wl1271_rx_get_buf_size(status, drv_rx_counter); - if (wl1271_rx_handle_data(wl, - wl->aggr_buf + pkt_offset, - pkt_length) < 0) - break; + /* + * the handle data call can only fail in memory-outage + * conditions, in that case the received frame will just + * be dropped. + */ + wl1271_rx_handle_data(wl, + wl->aggr_buf + pkt_offset, + pkt_length); wl->rx_counter++; drv_rx_counter++; drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; -- cgit v1.2.3 From b739a42c921dcb0ae92cc14032b7f75dcba88e3b Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 26 Oct 2010 13:24:38 +0200 Subject: wl1271: Fix scan failure detection In scan_complete_work, because the mutex is released before accessing the scan->failed flag, it is possible for unfounded hardware recovery rounds to be executed. Fix this. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 17 ++++++++++++++--- drivers/net/wireless/wl12xx/wl1271_scan.c | 5 +++-- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index 63036b53f9e4..bec2b3d78782 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1056,6 +1056,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->scan.state = WL1271_SCAN_STATE_IDLE; kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; + wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } @@ -1676,6 +1677,16 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); + if (wl->state == WL1271_STATE_OFF) { + /* + * We cannot return -EBUSY here because cfg80211 will expect + * a call to ieee80211_scan_completed if we do - in this case + * there won't be any call. + */ + ret = -EAGAIN; + goto out; + } + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -2093,14 +2104,14 @@ static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, { struct wl1271 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; - + if (idx != 0) return -ENOENT; - + survey->channel = conf->channel; survey->filled = SURVEY_INFO_NOISE_DBM; survey->noise = wl->noise; - + return 0; } diff --git a/drivers/net/wireless/wl12xx/wl1271_scan.c b/drivers/net/wireless/wl12xx/wl1271_scan.c index 909bb47995b6..e0661a543a35 100644 --- a/drivers/net/wireless/wl12xx/wl1271_scan.c +++ b/drivers/net/wireless/wl12xx/wl1271_scan.c @@ -48,14 +48,15 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.state = WL1271_SCAN_STATE_IDLE; kfree(wl->scan.scanned_ch); wl->scan.scanned_ch = NULL; - mutex_unlock(&wl->mutex); - + wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); ieee80211_queue_work(wl->hw, &wl->recovery_work); } + mutex_unlock(&wl->mutex); + } -- cgit v1.2.3 From f8d9802f66eda9ff14f7667f99a46b31e9a9e273 Mon Sep 17 00:00:00 2001 From: Juuso Oikarinen Date: Tue, 26 Oct 2010 13:24:39 +0200 Subject: wl1271: Check interface state in op_* functions Check the state of the interface on op_* function so we don't try to access the hardware in when its off. The mac80211 may call these in some corner cases related, for instance, to the hardware recovery procedure. These accesses cause a kernel crash on at least some SDIO devices, because the bus is not properly claimed in that scenario. Signed-off-by: Juuso Oikarinen Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index bec2b3d78782..c54887c80646 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -1344,8 +1344,10 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; goto out; + } ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) @@ -1568,6 +1570,11 @@ static int wl1271_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out_unlock; + } + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out_unlock; @@ -1708,8 +1715,10 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) mutex_lock(&wl->mutex); - if (unlikely(wl->state == WL1271_STATE_OFF)) + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; goto out; + } ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) @@ -1760,6 +1769,9 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -2040,6 +2052,11 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, wl1271_debug(DEBUG_MAC80211, "mac80211 conf tx %d", queue); + if (unlikely(wl->state == WL1271_STATE_OFF)) { + ret = -EAGAIN; + goto out; + } + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; @@ -2083,6 +2100,9 @@ static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + ret = wl1271_ps_elp_wakeup(wl, false); if (ret < 0) goto out; -- cgit v1.2.3 From 71125abdf0c297adc00dc5632f0318b2397286f5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 28 Oct 2010 21:46:43 +0200 Subject: wl1271: set wl->vif only if add_interface succeeded. set wl->vif to the newly created interface only after the firmware booted successfully. on the way - make the function flow more clear. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_main.c | 33 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index c54887c80646..a3a1ebc578a3 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -950,18 +950,19 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; int retries = WL1271_BOOT_RETRIES; int ret = 0; + bool booted = false; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", vif->type, vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { + wl1271_debug(DEBUG_MAC80211, + "multiple vifs are not supported yet"); ret = -EBUSY; goto out; } - wl->vif = vif; - switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; @@ -999,15 +1000,8 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto irq_disable; - wl->state = WL1271_STATE_ON; - wl1271_info("firmware booted (%s)", wl->chip.fw_ver); - - /* update hw/fw version info in wiphy struct */ - wiphy->hw_version = wl->chip.id; - strncpy(wiphy->fw_version, wl->chip.fw_ver, - sizeof(wiphy->fw_version)); - - goto out; + booted = true; + break; irq_disable: wl1271_disable_interrupts(wl); @@ -1025,8 +1019,21 @@ power_off: wl1271_power_off(wl); } - wl1271_error("firmware boot failed despite %d retries", - WL1271_BOOT_RETRIES); + if (!booted) { + wl1271_error("firmware boot failed despite %d retries", + WL1271_BOOT_RETRIES); + goto out; + } + + wl->vif = vif; + wl->state = WL1271_STATE_ON; + wl1271_info("firmware booted (%s)", wl->chip.fw_ver); + + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver, + sizeof(wiphy->fw_version)); + out: mutex_unlock(&wl->mutex); -- cgit v1.2.3 From 03107a4b5923aa7767329e857caf227749087e47 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 27 Oct 2010 14:58:30 +0200 Subject: wl1271: refactor debugfs function generation code refactor wl1271_debugfs by using a format© function, instead of duplicating the code for each generated function. this change reduces about 3Kb from wl1271.ko Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_debugfs.c | 215 ++++++++++++++------------- 1 file changed, 111 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_debugfs.c b/drivers/net/wireless/wl12xx/wl1271_debugfs.c index 66c2b90ddfd4..3468b849852e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1271_debugfs.c @@ -35,17 +35,28 @@ #define WL1271_DEBUGFS_STATS_LIFETIME 1000 /* debugfs macros idea from mac80211 */ +#define DEBUGFS_FORMAT_BUFFER_SIZE 100 +static int wl1271_format_buffer(char __user *userbuf, size_t count, + loff_t *ppos, char *fmt, ...) +{ + va_list args; + char buf[DEBUGFS_FORMAT_BUFFER_SIZE]; + int res; -#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ + va_start(args, fmt); + res = vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + return simple_read_from_buffer(userbuf, count, ppos, buf, res); +} + +#define DEBUGFS_READONLY_FILE(name, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ struct wl1271 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ - \ - res = scnprintf(buf, buflen, fmt "\n", ##value); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ + return wl1271_format_buffer(userbuf, count, ppos, \ + fmt "\n", ##value); \ } \ \ static const struct file_operations name## _ops = { \ @@ -69,20 +80,17 @@ static const struct file_operations name## _ops = { \ wl->debugfs.name = NULL; \ } while (0) -#define DEBUGFS_FWSTATS_FILE(sub, name, buflen, fmt) \ +#define DEBUGFS_FWSTATS_FILE(sub, name, fmt) \ static ssize_t sub## _ ##name## _read(struct file *file, \ char __user *userbuf, \ size_t count, loff_t *ppos) \ { \ struct wl1271 *wl = file->private_data; \ - char buf[buflen]; \ - int res; \ \ wl1271_debugfs_update_stats(wl); \ \ - res = scnprintf(buf, buflen, fmt "\n", \ - wl->stats.fw_stats->sub.name); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ + return wl1271_format_buffer(userbuf, count, ppos, fmt "\n", \ + wl->stats.fw_stats->sub.name); \ } \ \ static const struct file_operations sub## _ ##name## _ops = { \ @@ -126,100 +134,99 @@ static int wl1271_open_file_generic(struct inode *inode, struct file *file) return 0; } -DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rx, out_of_mem, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, hw_stuck, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, dropped, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, fcs_err, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, path_reset, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rx, reset_counter, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(dma, rx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, rx_errors, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_requested, 20, "%u"); -DEBUGFS_FWSTATS_FILE(dma, tx_errors, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, fiqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_headers, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_rdys, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, irqs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, decrypt_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma0_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, dma1_done, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, commands, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, rx_procs, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, pci_pm, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, wakeups, 20, "%u"); -DEBUGFS_FWSTATS_FILE(isr, low_rssi, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(wep, addr_key_count, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, default_key_count, 20, "%u"); +DEBUGFS_FWSTATS_FILE(tx, internal_desc_overflow, "%u"); + +DEBUGFS_FWSTATS_FILE(rx, out_of_mem, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hdr_overflow, "%u"); +DEBUGFS_FWSTATS_FILE(rx, hw_stuck, "%u"); +DEBUGFS_FWSTATS_FILE(rx, dropped, "%u"); +DEBUGFS_FWSTATS_FILE(rx, fcs_err, "%u"); +DEBUGFS_FWSTATS_FILE(rx, xfr_hint_trig, "%u"); +DEBUGFS_FWSTATS_FILE(rx, path_reset, "%u"); +DEBUGFS_FWSTATS_FILE(rx, reset_counter, "%u"); + +DEBUGFS_FWSTATS_FILE(dma, rx_requested, "%u"); +DEBUGFS_FWSTATS_FILE(dma, rx_errors, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_requested, "%u"); +DEBUGFS_FWSTATS_FILE(dma, tx_errors, "%u"); + +DEBUGFS_FWSTATS_FILE(isr, cmd_cmplt, "%u"); +DEBUGFS_FWSTATS_FILE(isr, fiqs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_headers, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_mem_overflow, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_rdys, "%u"); +DEBUGFS_FWSTATS_FILE(isr, irqs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_procs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, decrypt_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma0_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, dma1_done, "%u"); +DEBUGFS_FWSTATS_FILE(isr, tx_exch_complete, "%u"); +DEBUGFS_FWSTATS_FILE(isr, commands, "%u"); +DEBUGFS_FWSTATS_FILE(isr, rx_procs, "%u"); +DEBUGFS_FWSTATS_FILE(isr, hw_pm_mode_changes, "%u"); +DEBUGFS_FWSTATS_FILE(isr, host_acknowledges, "%u"); +DEBUGFS_FWSTATS_FILE(isr, pci_pm, "%u"); +DEBUGFS_FWSTATS_FILE(isr, wakeups, "%u"); +DEBUGFS_FWSTATS_FILE(isr, low_rssi, "%u"); + +DEBUGFS_FWSTATS_FILE(wep, addr_key_count, "%u"); +DEBUGFS_FWSTATS_FILE(wep, default_key_count, "%u"); /* skipping wep.reserved */ -DEBUGFS_FWSTATS_FILE(wep, key_not_found, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(wep, interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(pwr, ps_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, elp_enter, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, power_save_off, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, enable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, disable_ps, 20, "%u"); -DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, 20, "%u"); +DEBUGFS_FWSTATS_FILE(wep, key_not_found, "%u"); +DEBUGFS_FWSTATS_FILE(wep, decrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(wep, packets, "%u"); +DEBUGFS_FWSTATS_FILE(wep, interrupt, "%u"); + +DEBUGFS_FWSTATS_FILE(pwr, ps_enter, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, elp_enter, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, missing_bcns, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_host, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, wake_on_timer_exp, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_with_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, tx_without_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, rcvd_beacons, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, power_save_off, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, enable_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, disable_ps, "%u"); +DEBUGFS_FWSTATS_FILE(pwr, fix_tsf_ps, "%u"); /* skipping cont_miss_bcns_spread for now */ -DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(mic, rx_pkts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(mic, calc_failure, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, 20, "%u"); -DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(event, heart_beat, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, calibration, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mismatch, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, rx_pool, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, oom_late, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, 20, "%u"); -DEBUGFS_FWSTATS_FILE(event, tx_stuck, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, 20, "%u"); -DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, 20, "%u"); - -DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, - 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, 20, "%u"); -DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, 20, "%u"); - -DEBUGFS_READONLY_FILE(retry_count, 20, "%u", wl->stats.retry_count); -DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u", +DEBUGFS_FWSTATS_FILE(pwr, rcvd_awake_beacons, "%u"); + +DEBUGFS_FWSTATS_FILE(mic, rx_pkts, "%u"); +DEBUGFS_FWSTATS_FILE(mic, calc_failure, "%u"); + +DEBUGFS_FWSTATS_FILE(aes, encrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_fail, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_packets, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_packets, "%u"); +DEBUGFS_FWSTATS_FILE(aes, encrypt_interrupt, "%u"); +DEBUGFS_FWSTATS_FILE(aes, decrypt_interrupt, "%u"); + +DEBUGFS_FWSTATS_FILE(event, heart_beat, "%u"); +DEBUGFS_FWSTATS_FILE(event, calibration, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mismatch, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_mem_empty, "%u"); +DEBUGFS_FWSTATS_FILE(event, rx_pool, "%u"); +DEBUGFS_FWSTATS_FILE(event, oom_late, "%u"); +DEBUGFS_FWSTATS_FILE(event, phy_transmit_error, "%u"); +DEBUGFS_FWSTATS_FILE(event, tx_stuck, "%u"); + +DEBUGFS_FWSTATS_FILE(ps, pspoll_timeouts, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_timeouts, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_sptime, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_max_apturn, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_max_apturn, "%u"); +DEBUGFS_FWSTATS_FILE(ps, pspoll_utilization, "%u"); +DEBUGFS_FWSTATS_FILE(ps, upsd_utilization, "%u"); + +DEBUGFS_FWSTATS_FILE(rxpipe, rx_prep_beacon_drop, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, descr_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, beacon_buffer_thres_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, missed_beacon_host_int_trig_rx_data, "%u"); +DEBUGFS_FWSTATS_FILE(rxpipe, tx_xfr_host_int_trig_rx_data, "%u"); + +DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count); +DEBUGFS_READONLY_FILE(excessive_retries, "%u", wl->stats.excessive_retries); static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf, -- cgit v1.2.3 From ccc83b046c03378bbaf7cf095d8d7e9b9abb24c5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 27 Oct 2010 14:09:57 +0200 Subject: wl1271: handle HW watchdog interrupt unmask the WL1271_ACX_INTR_WATCHDOG interrupt. when getting it - enqueue a recovery work and bail out. Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_acx.h | 3 ++- drivers/net/wireless/wl12xx/wl1271_main.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h index 758916760912..b7c490845f3e 100644 --- a/drivers/net/wireless/wl12xx/wl1271_acx.h +++ b/drivers/net/wireless/wl12xx/wl1271_acx.h @@ -61,7 +61,8 @@ WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_DATA) -#define WL1271_INTR_MASK (WL1271_ACX_INTR_EVENT_A | \ +#define WL1271_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_EVENT_A | \ WL1271_ACX_INTR_EVENT_B | \ WL1271_ACX_INTR_HW_AVAILABLE | \ WL1271_ACX_INTR_DATA) diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c index a3a1ebc578a3..f5b1d19bc88d 100644 --- a/drivers/net/wireless/wl12xx/wl1271_main.c +++ b/drivers/net/wireless/wl12xx/wl1271_main.c @@ -529,6 +529,15 @@ static void wl1271_irq_work(struct work_struct *work) intr &= WL1271_INTR_MASK; + if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { + wl1271_error("watchdog interrupt received! " + "starting recovery."); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + + /* restarting the chip. ignore any other interrupt. */ + goto out; + } + if (intr & WL1271_ACX_INTR_DATA) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); -- cgit v1.2.3 From e285a5250c0772c5596a9137041a96b2c1f744d6 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 27 Oct 2010 14:09:58 +0200 Subject: wl1271: add recover testmode command add RECOVER testmode command. this command triggers a recovery sequence (by enqueueing a recovery_work). Signed-off-by: Eliad Peller Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho --- drivers/net/wireless/wl12xx/wl1271_testmode.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c index a3aa84386c88..55ec4428922b 100644 --- a/drivers/net/wireless/wl12xx/wl1271_testmode.c +++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c @@ -37,6 +37,7 @@ enum wl1271_tm_commands { WL1271_TM_CMD_CONFIGURE, WL1271_TM_CMD_NVS_PUSH, WL1271_TM_CMD_SET_PLT_MODE, + WL1271_TM_CMD_RECOVER, __WL1271_TM_CMD_AFTER_LAST }; @@ -248,6 +249,15 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) return ret; } +static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) +{ + wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); + + ieee80211_queue_work(wl->hw, &wl->recovery_work); + + return 0; +} + int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) { struct wl1271 *wl = hw->priv; @@ -272,6 +282,8 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) return wl1271_tm_cmd_nvs_push(wl, tb); case WL1271_TM_CMD_SET_PLT_MODE: return wl1271_tm_cmd_set_plt_mode(wl, tb); + case WL1271_TM_CMD_RECOVER: + return wl1271_tm_cmd_recover(wl, tb); default: return -EOPNOTSUPP; } -- cgit v1.2.3 From 19999792d2889350611ba9e346d6a2924959dc2d Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Thu, 28 Oct 2010 20:01:00 -0200 Subject: rtl8187b: do not do per packet TX AGC Clearing the per packet TX AGC for the RTL8187B device appears to increase its overall TX power. This allows the device to associate and a connection to be established using APs a little further away. This is in accordance to what is done for RTL8187L devices and also what Realtek drivers do. Tested-by: Thadeu Lima de Souza Cascardo Signed-off-by: Thadeu Lima de Souza Cascardo Cc: linux-wireless@vger.kernel.org Cc: Larry Finger Cc: Rogerio Luz Coelho Cc: Herton Ronaldo Krzesinski Cc: Hin-Tak Leung Cc: seno Tested-by: Herton Ronaldo Krzesinski Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 38fa8244cc96..6e26149809bf 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -775,10 +775,6 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); - reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); - reg |= RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT | - RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; - rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); @@ -929,6 +925,12 @@ static int rtl8187_start(struct ieee80211_hw *dev) priv->rx_conf = reg; rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, RTL818X_TX_CONF_HW_SEQNUM | RTL818X_TX_CONF_DISREQQSIZE | -- cgit v1.2.3 From bdd7bd16439975133d36bcd7c9c489302a114525 Mon Sep 17 00:00:00 2001 From: Blaise Gassend Date: Thu, 28 Oct 2010 02:01:24 -0700 Subject: mac80211_hwsim: Incorporate txpower into rssi Up to now mac80211_hwsim has been reporting an rssi of -50. This patch improves the model slightly by returning txpower-50. This makes it easy to stimulate tests that need to see a varying rssi. Signed-off-by: Blaise Gassend Signed-off-by: John W. Linville --- drivers/net/wireless/mac80211_hwsim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 7eaaa3bab547..454f045ddff3 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -309,6 +309,8 @@ struct mac80211_hwsim_data { */ u64 group; struct dentry *debugfs_group; + + int power_level; }; @@ -497,7 +499,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, rx_status.band = data->channel->band; rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate real signal strength (and optional packet loss) */ - rx_status.signal = -50; + rx_status.signal = data->power_level - 50; if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -698,6 +700,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) data->idle = !!(conf->flags & IEEE80211_CONF_IDLE); data->channel = conf->channel; + data->power_level = conf->power_level; if (!data->started || !data->beacon_int) del_timer(&data->beacon_timer); else -- cgit v1.2.3 From 3f1240e4f4b249f2388903864bdc766973f76687 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 29 Oct 2010 22:44:59 +0200 Subject: carl9170: import hw/fw header updates This patch imports all shared header changes from carl9170fw.git. * add some strategic __aligned(4). This allows the compiler generate optimized code for architectures which can't access (unaligned/packed) data efficiently. ("ath9k_hw: optimize all descriptor access functions") * add a forgotten __CARL9170FW__ ifdef around a private firmware-internal struct. * GET_VAL macro helper Very useful for extracting data out of the bit-packed PHY registers. * cosmetic changes e.g.: _CCA_MINCCA_ to just _CCA_MIN_. * version bump 1.8.8.3 -> 1.9.0. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/fwcmd.h | 13 +++++++++---- drivers/net/wireless/ath/carl9170/hw.h | 7 ++++++- drivers/net/wireless/ath/carl9170/phy.h | 24 ++++++++++++------------ drivers/net/wireless/ath/carl9170/version.h | 6 +++--- 4 files changed, 30 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index d552166db505..3680dfc70f46 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -97,13 +97,13 @@ struct carl9170_set_key_cmd { __le16 type; u8 macAddr[6]; u32 key[4]; -} __packed; +} __packed __aligned(4); #define CARL9170_SET_KEY_CMD_SIZE 28 struct carl9170_disable_key_cmd { __le16 user; __le16 padding; -} __packed; +} __packed __aligned(4); #define CARL9170_DISABLE_KEY_CMD_SIZE 4 struct carl9170_u32_list { @@ -206,7 +206,7 @@ struct carl9170_cmd { struct carl9170_rx_filter_cmd rx_filter; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; } __packed; -} __packed; +} __packed __aligned(4); #define CARL9170_TX_STATUS_QUEUE 3 #define CARL9170_TX_STATUS_QUEUE_S 0 @@ -216,6 +216,7 @@ struct carl9170_cmd { #define CARL9170_TX_STATUS_TRIES (7 << CARL9170_TX_STATUS_TRIES_S) #define CARL9170_TX_STATUS_SUCCESS 0x80 +#ifdef __CARL9170FW__ /* * NOTE: * Both structs [carl9170_tx_status and _carl9170_tx_status] @@ -232,6 +233,8 @@ struct carl9170_tx_status { u8 tries:3; u8 success:1; } __packed; +#endif /* __CARL9170FW__ */ + struct _carl9170_tx_status { /* * This version should be immune to all alignment bugs. @@ -272,13 +275,15 @@ struct carl9170_rsp { struct carl9170_rf_init_result rf_init_res; struct carl9170_u32_list rreg_res; struct carl9170_u32_list echo; +#ifdef __CARL9170FW__ struct carl9170_tx_status tx_status[0]; +#endif /* __CARL9170FW__ */ struct _carl9170_tx_status _tx_status[0]; struct carl9170_gpio gpio; struct carl9170_tsf_rsp tsf; struct carl9170_psm psm; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; } __packed; -} __packed; +} __packed __aligned(4); #endif /* __CARL9170_SHARED_FWCMD_H */ diff --git a/drivers/net/wireless/ath/carl9170/hw.h b/drivers/net/wireless/ath/carl9170/hw.h index 2f471b3f05af..e85df6edfed3 100644 --- a/drivers/net/wireless/ath/carl9170/hw.h +++ b/drivers/net/wireless/ath/carl9170/hw.h @@ -712,7 +712,8 @@ struct ar9170_stream { __le16 tag; u8 payload[0]; -}; +} __packed __aligned(4); +#define AR9170_STREAM_LEN 4 #define AR9170_MAX_ACKTABLE_ENTRIES 8 #define AR9170_MAX_VIRTUAL_MAC 7 @@ -736,4 +737,8 @@ struct ar9170_stream { #define MOD_VAL(reg, value, newvalue) \ (((value) & ~reg) | (((newvalue) << reg##_S) & reg)) + +#define GET_VAL(reg, value) \ + (((value) & reg) >> reg##_S) + #endif /* __CARL9170_SHARED_HW_H */ diff --git a/drivers/net/wireless/ath/carl9170/phy.h b/drivers/net/wireless/ath/carl9170/phy.h index 02c34eb4ebde..024fb42bc787 100644 --- a/drivers/net/wireless/ath/carl9170/phy.h +++ b/drivers/net/wireless/ath/carl9170/phy.h @@ -139,8 +139,8 @@ #define AR9170_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 #define AR9170_PHY_REG_CCA (AR9170_PHY_REG_BASE + 0x0064) -#define AR9170_PHY_CCA_MINCCA_PWR 0x0ff80000 -#define AR9170_PHY_CCA_MINCCA_PWR_S 19 +#define AR9170_PHY_CCA_MIN_PWR 0x0ff80000 +#define AR9170_PHY_CCA_MIN_PWR_S 19 #define AR9170_PHY_CCA_THRESH62 0x0007f000 #define AR9170_PHY_CCA_THRESH62_S 12 @@ -338,8 +338,8 @@ #define AR9170_PHY_EXT_CCA_CYCPWR_THR1_S 9 #define AR9170_PHY_EXT_CCA_THRESH62 0x007f0000 #define AR9170_PHY_EXT_CCA_THRESH62_S 16 -#define AR9170_PHY_EXT_MINCCA_PWR 0xff800000 -#define AR9170_PHY_EXT_MINCCA_PWR_S 23 +#define AR9170_PHY_EXT_CCA_MIN_PWR 0xff800000 +#define AR9170_PHY_EXT_CCA_MIN_PWR_S 23 #define AR9170_PHY_REG_SFCORR_EXT (AR9170_PHY_REG_BASE + 0x01c0) #define AR9170_PHY_SFCORR_EXT_M1_THRESH 0x0000007f @@ -546,19 +546,19 @@ #define AR9170_PHY_FORCE_XPA_CFG_S 0 #define AR9170_PHY_REG_CH1_CCA (AR9170_PHY_REG_BASE + 0x1064) -#define AR9170_PHY_CH1_MINCCA_PWR 0x0ff80000 -#define AR9170_PHY_CH1_MINCCA_PWR_S 19 +#define AR9170_PHY_CH1_CCA_MIN_PWR 0x0ff80000 +#define AR9170_PHY_CH1_CCA_MIN_PWR_S 19 #define AR9170_PHY_REG_CH2_CCA (AR9170_PHY_REG_BASE + 0x2064) -#define AR9170_PHY_CH2_MINCCA_PWR 0x0ff80000 -#define AR9170_PHY_CH2_MINCCA_PWR_S 19 +#define AR9170_PHY_CH2_CCA_MIN_PWR 0x0ff80000 +#define AR9170_PHY_CH2_CCA_MIN_PWR_S 19 #define AR9170_PHY_REG_CH1_EXT_CCA (AR9170_PHY_REG_BASE + 0x11bc) -#define AR9170_PHY_CH1_EXT_MINCCA_PWR 0xff800000 -#define AR9170_PHY_CH1_EXT_MINCCA_PWR_S 23 +#define AR9170_PHY_CH1_EXT_CCA_MIN_PWR 0xff800000 +#define AR9170_PHY_CH1_EXT_CCA_MIN_PWR_S 23 #define AR9170_PHY_REG_CH2_EXT_CCA (AR9170_PHY_REG_BASE + 0x21bc) -#define AR9170_PHY_CH2_EXT_MINCCA_PWR 0xff800000 -#define AR9170_PHY_CH2_EXT_MINCCA_PWR_S 23 +#define AR9170_PHY_CH2_EXT_CCA_MIN_PWR 0xff800000 +#define AR9170_PHY_CH2_EXT_CCA_MIN_PWR_S 23 #endif /* __CARL9170_SHARED_PHY_H */ diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index ff53f078a0b5..ee0f84f2a2f6 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 10 -#define CARL9170FW_VERSION_MONTH 9 -#define CARL9170FW_VERSION_DAY 28 -#define CARL9170FW_VERSION_GIT "1.8.8.3" +#define CARL9170FW_VERSION_MONTH 10 +#define CARL9170FW_VERSION_DAY 29 +#define CARL9170FW_VERSION_GIT "1.9.0" #endif /* __CARL9170_SHARED_VERSION_H */ -- cgit v1.2.3 From e27769059ccb15273a7eb69ed31b8e08f9b0eda8 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 29 Oct 2010 23:17:38 +0200 Subject: carl9170: initialize HW aMPDU parameters properly This patch changes the initial aMPDU density and factor settings to match those of Otus. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index 2305bc27151c..c34eeeeb8af3 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -205,8 +205,8 @@ int carl9170_init_mac(struct ar9170 *ar) carl9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105); /* Aggregation MAX number and timeout */ - carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0xa); - carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a00); + carl9170_regwrite(AR9170_MAC_REG_AMPDU_FACTOR, 0x8000a); + carl9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, 0x140a07); carl9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER, AR9170_MAC_FTF_DEFAULTS); -- cgit v1.2.3 From e4a668c59080f862af3ecc28b359533027cbe434 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 29 Oct 2010 23:26:13 +0200 Subject: carl9170: fix spurious restart due to high latency RX Stress tests of unidirectional bulk traffic with bitrates of up to 220Mbit/s have revealed that the fatal-event recovery logic [which was solely triggered by an out-of-rx-buffer situation] is too aggressive. The new method now "pings" the device and then decides - based on the response - whenever a restart is needed or not. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/carl9170.h | 3 ++- drivers/net/wireless/ath/carl9170/main.c | 17 +++++++++++++++++ drivers/net/wireless/ath/carl9170/usb.c | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index b69d31972c77..d07ff7f2fd92 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -215,7 +215,7 @@ enum carl9170_restart_reasons { CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS, CARL9170_RR_WATCHDOG, CARL9170_RR_STUCK_TX, - CARL9170_RR_SLOW_SYSTEM, + CARL9170_RR_UNRESPONSIVE_DEVICE, CARL9170_RR_COMMAND_TIMEOUT, CARL9170_RR_TOO_MANY_PHY_ERRORS, CARL9170_RR_LOST_RSP, @@ -287,6 +287,7 @@ struct ar9170 { /* reset / stuck frames/queue detection */ struct work_struct restart_work; + struct work_struct ping_work; unsigned int restart_counter; unsigned long queue_stop_timeout[__AR9170_NUM_TXQ]; unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ]; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index d521bc2b0496..4ae6a5849076 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -428,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar) cancel_delayed_work_sync(&ar->led_work); #endif /* CONFIG_CARL9170_LEDS */ cancel_work_sync(&ar->ps_work); + cancel_work_sync(&ar->ping_work); cancel_work_sync(&ar->ampdu_work); } @@ -533,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r) */ } +static void carl9170_ping_work(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, ping_work); + int err; + + if (!IS_STARTED(ar)) + return; + + mutex_lock(&ar->mutex); + err = carl9170_echo_test(ar, 0xdeadbeef); + if (err) + carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE); + mutex_unlock(&ar->mutex); +} + static int carl9170_init_interface(struct ar9170 *ar, struct ieee80211_vif *vif) { @@ -1614,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size) skb_queue_head_init(&ar->tx_pending[i]); } INIT_WORK(&ar->ps_work, carl9170_ps_work); + INIT_WORK(&ar->ping_work, carl9170_ping_work); INIT_WORK(&ar->restart_work, carl9170_restart_work); INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work); INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor); diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index d8607f4c144d..ddf5373ee689 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -431,7 +431,7 @@ static void carl9170_usb_rx_complete(struct urb *urb) * device. */ - carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM); + ieee80211_queue_work(ar->hw, &ar->ping_work); } } else { /* -- cgit v1.2.3 From 2a6cef513fab525399e484edc9bfb39b6d462f76 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 29 Oct 2010 23:41:16 +0200 Subject: carl9170: stop stale uplink BA sessions This patch fixes a possible lengthy stall if the device is operating as an experimental 11n AP and an STA [during heavy txrx action] suddenly signalized to go off-channel (old NetworkManager), or (sleep - which is unlikely, because then it wouldn't be *active* at all!?). Because the driver has to manage the BA Window, the sudden PSM transition can leave active uplink BA sessions to the STA in a bad state and a proper cleanup is needed. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/tx.c | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index b575c865142d..b27969c41812 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -524,6 +524,59 @@ next: } } +static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) +{ + struct carl9170_sta_tid *iter; + struct sk_buff *skb; + struct ieee80211_tx_info *txinfo; + struct carl9170_tx_info *arinfo; + struct _carl9170_tx_superframe *super; + struct ieee80211_sta *sta; + struct ieee80211_vif *vif; + struct ieee80211_hdr *hdr; + unsigned int vif_id; + + rcu_read_lock(); + list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { + if (iter->state < CARL9170_TID_STATE_IDLE) + continue; + + spin_lock_bh(&iter->lock); + skb = skb_peek(&iter->queue); + if (!skb) + goto unlock; + + txinfo = IEEE80211_SKB_CB(skb); + arinfo = (void *)txinfo->rate_driver_data; + if (time_is_after_jiffies(arinfo->timeout + + msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) + goto unlock; + + super = (void *) skb->data; + hdr = (void *) super->frame_data; + + vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> + CARL9170_TX_SUPER_MISC_VIF_ID_S; + + if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) + goto unlock; + + vif = rcu_dereference(ar->vif_priv[vif_id].vif); + if (WARN_ON(!vif)) + goto unlock; + + sta = ieee80211_find_sta(vif, hdr->addr1); + if (WARN_ON(!sta)) + goto unlock; + + ieee80211_stop_tx_ba_session(sta, iter->tid); +unlock: + spin_unlock_bh(&iter->lock); + + } + rcu_read_unlock(); +} + void carl9170_tx_janitor(struct work_struct *work) { struct ar9170 *ar = container_of(work, struct ar9170, @@ -534,6 +587,7 @@ void carl9170_tx_janitor(struct work_struct *work) ar->tx_janitor_last_run = jiffies; carl9170_check_queue_stop_timeout(ar); + carl9170_tx_ampdu_timeout(ar); if (!atomic_read(&ar->tx_total_queued)) return; -- cgit v1.2.3 From 3eedb6f436858f3e864139dc184adc9a51440c92 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 30 Oct 2010 00:36:53 +0200 Subject: carl9170: configurable beacon rates Previously, the beacon rate was fixed to either: * 1Mb/s [2.4GHz band] * 6Mb/s [5GHz band] This limitation has been addressed and now the beacon rate is selected by ieee80211_tx_info's rate control info, almost like any ordinary data frame. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/mac.c | 52 ++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index c34eeeeb8af3..385cf508479b 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -457,8 +457,9 @@ int carl9170_set_beacon_timers(struct ar9170 *ar) int carl9170_update_beacon(struct ar9170 *ar, const bool submit) { - struct sk_buff *skb; + struct sk_buff *skb = NULL; struct carl9170_vif_info *cvif; + struct ieee80211_tx_info *txinfo; __le32 *data, *old = NULL; u32 word, off, addr, len; int i = 0, err = 0; @@ -487,7 +488,13 @@ found: if (!skb) { err = -ENOMEM; - goto out_unlock; + goto err_free; + } + + txinfo = IEEE80211_SKB_CB(skb); + if (txinfo->control.rates[0].flags & IEEE80211_TX_RC_MCS) { + err = -EINVAL; + goto err_free; } spin_lock_bh(&ar->beacon_lock); @@ -504,11 +511,8 @@ found: wiphy_err(ar->hw->wiphy, "beacon does not " "fit into device memory!\n"); } - - spin_unlock_bh(&ar->beacon_lock); - dev_kfree_skb_any(skb); err = -EINVAL; - goto out_unlock; + goto err_unlock; } if (len > AR9170_MAC_BCN_LENGTH_MAX) { @@ -518,22 +522,22 @@ found: AR9170_MAC_BCN_LENGTH_MAX, len); } - spin_unlock_bh(&ar->beacon_lock); - dev_kfree_skb_any(skb); err = -EMSGSIZE; - goto out_unlock; + goto err_unlock; } - carl9170_async_regwrite_begin(ar); + i = txinfo->control.rates[0].idx; + if (txinfo->band != IEEE80211_BAND_2GHZ) + i += 4; - /* XXX: use skb->cb info */ - if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) { - carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400); - } else { - carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, - ((skb->len + FCS_LEN) << 16) + 0x001b); - } + word = __carl9170_ratetable[i].hw_value & 0xf; + if (i < 4) + word |= ((skb->len + FCS_LEN) << (3 + 16)) + 0x0400; + else + word |= ((skb->len + FCS_LEN) << 16) + 0x0010; + + carl9170_async_regwrite_begin(ar); + carl9170_async_regwrite(AR9170_MAC_REG_BCN_PLCP, word); for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) { /* @@ -557,7 +561,7 @@ found: cvif->beacon = skb; spin_unlock_bh(&ar->beacon_lock); if (err) - goto out_unlock; + goto err_free; if (submit) { err = carl9170_bcn_ctrl(ar, cvif->id, @@ -565,10 +569,18 @@ found: addr, skb->len + FCS_LEN); if (err) - goto out_unlock; + goto err_free; } out_unlock: rcu_read_unlock(); + return 0; + +err_unlock: + spin_unlock_bh(&ar->beacon_lock); + +err_free: + rcu_read_unlock(); + dev_kfree_skb_any(skb); return err; } -- cgit v1.2.3 From c0bf9ca98e07ca72c444a6cfb272aafa9890b9b6 Mon Sep 17 00:00:00 2001 From: Nishant Sarmukadam Date: Mon, 1 Nov 2010 17:55:48 -0700 Subject: mwl8k: force AP mode to use non-AMPDU frames AP firmware uses xmitcontrol to differentiate between AMPDU and non-AMPDU frames. As the support for AMPDU is not yet added, set xmitcontrol to non-AMPDU for all tx frames for AP firmware. This field will be set to indicate ampdu/non-ampdu frames when tx AMPDU support is added. Signed-off-by: Pradeep Nemavat Signed-off-by: Brian Cavagnolo Acked-by: Lennert Buytenhek Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index f152a25be59f..1bbcd7c1d02a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1125,10 +1125,12 @@ struct mwl8k_tx_desc { __le32 reserved; __le16 rate_info; __u8 peer_id; - __u8 tx_frag_cnt; + __u8 xmitcontrol; } __packed; #define MWL8K_TX_DESCS 128 +#define MWL8K_XMITCONTROL_NON_AMPDU 0x04 + static int mwl8k_txq_init(struct ieee80211_hw *hw, int index) { @@ -1448,6 +1450,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; else tx->peer_id = 0; + + if (priv->ap_fw) + tx->xmitcontrol = MWL8K_XMITCONTROL_NON_AMPDU; wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); -- cgit v1.2.3 From 327571ea9927beec2ee2ed9a266c57c1515393b4 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:31 -0200 Subject: rtl8187: remove redundant initialization of ARFR This removes redundant write to Auto Rate Fallback Register on RTL8187B. The same value was being written twice in the same function. Avoid this removing the duplicate initialization on rtl8187b_reg_table, and also add comment for this write (information from Realtek source). Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 6e26149809bf..3dbf3053c09f 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -712,10 +712,9 @@ static const u8 rtl8187b_reg_table[][3] = { {0x58, 0x4B, 1}, {0x59, 0x00, 1}, {0x5A, 0x4B, 1}, {0x5B, 0x00, 1}, {0x60, 0x4B, 1}, {0x61, 0x09, 1}, {0x62, 0x4B, 1}, {0x63, 0x09, 1}, - {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xE0, 0xFF, 1}, {0xE1, 0x0F, 1}, - {0xE2, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, {0xF2, 0x02, 1}, - {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, {0xF6, 0x06, 1}, - {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, + {0xCE, 0x0F, 1}, {0xCF, 0x00, 1}, {0xF0, 0x4E, 1}, {0xF1, 0x01, 1}, + {0xF2, 0x02, 1}, {0xF3, 0x03, 1}, {0xF4, 0x04, 1}, {0xF5, 0x05, 1}, + {0xF6, 0x06, 1}, {0xF7, 0x07, 1}, {0xF8, 0x08, 1}, {0x4E, 0x00, 2}, {0x0C, 0x04, 2}, {0x21, 0x61, 2}, {0x22, 0x68, 2}, {0x23, 0x6F, 2}, {0x24, 0x76, 2}, {0x25, 0x7D, 2}, {0x26, 0x84, 2}, @@ -776,7 +775,9 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + /* Auto Rate Fallback Register (ARFR): 1M-54M setting */ rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); + rtl818x_iowrite8_idx(priv, (u8 *)0xFFE2, 0x00, 1); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); -- cgit v1.2.3 From f002c25cc13e86762551c0eda29a40c60d6dbf1b Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:32 -0200 Subject: rtl8187: remove setting of beacon/atim registers from initialization On 8187B path, we set a initial value for beacon interval and atim window on initialization. But this isn't needed, since same setup is done on rtl8187_config. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 3dbf3053c09f..30c2120dd302 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -779,8 +779,6 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16_idx(priv, (__le16 *)0xFFE0, 0x0FFF, 1); rtl818x_iowrite8_idx(priv, (u8 *)0xFFE2, 0x00, 1); - rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); rtl818x_iowrite16_idx(priv, (__le16 *)0xFFD4, 0xFFFF, 1); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, -- cgit v1.2.3 From 60f589145d76cf834ec5e485c5412ec0994e52d1 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:33 -0200 Subject: rtl8187: fix wrong register initialization in 8187B We were using wrong address for BRSR (Basic Rate Set Register) while initializing its value, comparing with Realtek sources, for 8187B case. Also, the same register is initialized in rtl8187b_reg_table, so remove the duplicate initialization from the table. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 30c2120dd302..b9ce2a8739cd 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -725,11 +725,11 @@ static const u8 rtl8187b_reg_table[][3] = { {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, {0x73, 0x9A, 2}, - {0x34, 0xF0, 0}, {0x35, 0x0F, 0}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, - {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, - {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, {0x95, 0x12, 0}, {0x96, 0x00, 0}, - {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, - {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, {0xEE, 0x00, 0}, {0x4C, 0x00, 2}, + {0x5B, 0x40, 0}, {0x84, 0x88, 0}, {0x85, 0x24, 0}, {0x88, 0x54, 0}, + {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, + {0x95, 0x12, 0}, {0x96, 0x00, 0}, {0x97, 0x06, 0}, {0x9D, 0x1A, 0}, + {0x9F, 0x10, 0}, {0xB4, 0x22, 0}, {0xBE, 0x80, 0}, {0xDB, 0x00, 0}, + {0xEE, 0x00, 0}, {0x4C, 0x00, 2}, {0x9F, 0x00, 3}, {0x8C, 0x01, 0}, {0x8D, 0x10, 0}, {0x8E, 0x08, 0}, {0x8F, 0x00, 0} @@ -770,7 +770,11 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) if (res) return res; - rtl818x_iowrite16(priv, (__le16 *)0xFF2D, 0x0FFF); + /* BRSR (Basic Rate Set Register) on 8187B looks to be the same as + * RESP_RATE on 8187L in Realtek sources: each bit should be each + * one of the 12 rates, all are enabled */ + rtl818x_iowrite16(priv, (__le16 *)0xFF34, 0x0FFF); + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); -- cgit v1.2.3 From a8ff34e37a186ebb7d2d90ee40ef88a3ef95ad47 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:34 -0200 Subject: rtl8187: avoid redundant write to register FF72 (RFSW_CTRL) The table with misc register initialization was setting it, and later on we would set it again with a explicity call to rtl818x_iowrite16_idx. Remove duplicate initialization from the register table. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index b9ce2a8739cd..063374aba863 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -722,8 +722,7 @@ static const u8 rtl8187b_reg_table[][3] = { {0x52, 0x04, 2}, {0x53, 0xA0, 2}, {0x54, 0x1F, 2}, {0x55, 0x23, 2}, {0x56, 0x45, 2}, {0x57, 0x67, 2}, {0x58, 0x08, 2}, {0x59, 0x08, 2}, {0x5A, 0x08, 2}, {0x5B, 0x08, 2}, {0x60, 0x08, 2}, {0x61, 0x08, 2}, - {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x72, 0x56, 2}, - {0x73, 0x9A, 2}, + {0x62, 0x08, 2}, {0x63, 0x08, 2}, {0x64, 0xCF, 2}, {0x5B, 0x40, 0}, {0x84, 0x88, 0}, {0x85, 0x24, 0}, {0x88, 0x54, 0}, {0x8B, 0xB8, 0}, {0x8C, 0x07, 0}, {0x8D, 0x00, 0}, {0x94, 0x1B, 0}, @@ -810,6 +809,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00004001); + /* RFSW_CTRL register */ rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, -- cgit v1.2.3 From 896cae65fc0489b8e42bb7790f64731d53a2cecf Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:35 -0200 Subject: rtl8187: move pll reset at start out of ANAPARAM write On 8187B start, comment about pll reset, and move it out of ANAPARAM write sequence, so that code is more readable. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 063374aba863..2b4ee26c6745 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -742,7 +742,6 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); @@ -752,19 +751,19 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) RTL8187B_RTL8225_ANAPARAM_ON); rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, RTL8187B_RTL8225_ANAPARAM3_ON); - - rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); - reg = rtl818x_ioread8(priv, (u8 *)0xFF62); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); - rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + /* Reset PLL sequence on 8187B. Realtek note: reduces power + * consumption about 30 mA */ + rtl818x_iowrite8(priv, (u8 *)0xFF61, 0x10); + reg = rtl818x_ioread8(priv, (u8 *)0xFF62); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg & ~(1 << 5)); + rtl818x_iowrite8(priv, (u8 *)0xFF62, reg | (1 << 5)); + res = rtl8187_cmd_reset(dev); if (res) return res; -- cgit v1.2.3 From fe3326903d7aafd7b5602d8e178537c8b0465f6c Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:36 -0200 Subject: rtl8187: don't set RTL818X_CONFIG3_GNT_SELECT flag on 8187B The GNTSel bit should only concern pci devices by looking at RTL8180 spec, which is not the case of 8187B. Also testing shows that trying to set this bit fails, a subsequent read from the register after trying to set it shows that the bit isn't set, seems the hardware ignores it, which makes sense. This setting was a left over from Realtek sources. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 2b4ee26c6745..d7ea5d1a2888 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -743,7 +743,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE | RTL818X_CONFIG3_GNT_SELECT; + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8187B_RTL8225_ANAPARAM2_ON); -- cgit v1.2.3 From 0bf198eb4d05a4662143e4a2e2a44fb592e2b177 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:37 -0200 Subject: rtl8187: consolidate anaparam on/off write sequences There are repeated calls for anaparam on/off sequence in the code. Consolidate the common code in rtl8187_set_anaparam and use it where needed. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 84 ++++++++++++++------------ drivers/net/wireless/rtl818x/rtl8187_rtl8225.c | 22 ------- 2 files changed, 44 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index d7ea5d1a2888..c0c75aa13db2 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -553,6 +553,46 @@ static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) return ret; } +static void rtl8187_set_anaparam(struct rtl8187_priv *priv, bool rfon) +{ + u32 anaparam, anaparam2; + u8 anaparam3, reg; + + if (!priv->is_rtl8187b) { + if (rfon) { + anaparam = RTL8187_RTL8225_ANAPARAM_ON; + anaparam2 = RTL8187_RTL8225_ANAPARAM2_ON; + } else { + anaparam = RTL8187_RTL8225_ANAPARAM_OFF; + anaparam2 = RTL8187_RTL8225_ANAPARAM2_OFF; + } + } else { + if (rfon) { + anaparam = RTL8187B_RTL8225_ANAPARAM_ON; + anaparam2 = RTL8187B_RTL8225_ANAPARAM2_ON; + anaparam3 = RTL8187B_RTL8225_ANAPARAM3_ON; + } else { + anaparam = RTL8187B_RTL8225_ANAPARAM_OFF; + anaparam2 = RTL8187B_RTL8225_ANAPARAM2_OFF; + anaparam3 = RTL8187B_RTL8225_ANAPARAM3_OFF; + } + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, anaparam2); + if (priv->is_rtl8187b) + rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, anaparam3); + reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, + RTL818X_EEPROM_CMD_NORMAL); +} + static int rtl8187_cmd_reset(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; @@ -603,19 +643,7 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) int res; /* reset */ - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | - RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & - ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); + rtl8187_set_anaparam(priv, true); rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); @@ -629,17 +657,7 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) if (res) return res; - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, - reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + rtl8187_set_anaparam(priv, true); /* setup card */ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0); @@ -740,22 +758,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) int res, i; u8 reg; - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_ON); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_ON); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_ON); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg &= ~RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); + rtl8187_set_anaparam(priv, true); /* Reset PLL sequence on 8187B. Realtek note: reduces power * consumption about 30 mA */ @@ -1006,6 +1009,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CMD, reg); priv->rf->stop(dev); + rtl8187_set_anaparam(priv, false); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); diff --git a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 97eebdcf7eb9..5c6666f09ac1 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -898,29 +898,7 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) static void rtl8225_rf_stop(struct ieee80211_hw *dev) { - u8 reg; - struct rtl8187_priv *priv = dev->priv; - rtl8225_write(dev, 0x4, 0x1f); - - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); - if (!priv->is_rtl8187b) { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187_RTL8225_ANAPARAM_OFF); - } else { - rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, - RTL8187B_RTL8225_ANAPARAM2_OFF); - rtl818x_iowrite32(priv, &priv->map->ANAPARAM, - RTL8187B_RTL8225_ANAPARAM_OFF); - rtl818x_iowrite8(priv, &priv->map->ANAPARAM3, - RTL8187B_RTL8225_ANAPARAM3_OFF); - } - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, -- cgit v1.2.3 From 998606cfd75e7a8169ed0d324061a8d6bc60716a Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:38 -0200 Subject: rtl8187: remove uneeded setting of anaparam write Usually you set RTL818X_CONFIG3_ANAPARAM_WRITE when you are going to change/write ANAPARAM registers. But in current initialization of RTL8187B there is a place where ANAPARAM_WRITE bit is set without any ANAPARAM register being written, without reason, so remove it. Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Cc: seno Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index c0c75aa13db2..4448647d6cf6 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -814,14 +814,6 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) /* RFSW_CTRL register */ rtl818x_iowrite16_idx(priv, (__le16 *)0xFF72, 0x569A, 2); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_CONFIG); - reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); - reg |= RTL818X_CONFIG3_ANAPARAM_WRITE; - rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); - rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, - RTL818X_EEPROM_CMD_NORMAL); - rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); -- cgit v1.2.3 From daeeb074105a80a34f90a454c24efc14e9a8d3c3 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Mon, 1 Nov 2010 22:59:39 -0200 Subject: rtl8187: restore anaparam registers after reset with 8187B Current 8187B initialization misses anaparam registers restore after 8187 reset. This causes ANAPARAM register to stay zeroed out (ANAPARAM2 kept its value on my tests). To avoid this, call rtl8187_set_anaparam right after chip reset (to be on the safe side, as it makes sure we restore all ANAPARAM registers). Signed-off-by: Herton Ronaldo Krzesinski Acked-by: Larry Finger Cc: seno Signed-off-by: John W. Linville --- drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c index 4448647d6cf6..eeee244fcaab 100644 --- a/drivers/net/wireless/rtl818x/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -771,6 +771,8 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) if (res) return res; + rtl8187_set_anaparam(priv, true); + /* BRSR (Basic Rate Set Register) on 8187B looks to be the same as * RESP_RATE on 8187L in Realtek sources: each bit should be each * one of the 12 rates, all are enabled */ -- cgit v1.2.3 From 8cecc90e4a302ac214c48e362709ce906a96a295 Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Tue, 2 Nov 2010 23:10:12 +0100 Subject: zd1211rw: add 2 missing usb id's "These USB ID came from Palnex Worked fine." says Mandriva patch for their 2.6.32 and earlier. Web has evidence for both id's to work, so just add them upstream: http://www.mail-archive.com/zd1211-devs@lists.sourceforge.net/msg00507.html http://ubuntuforums.org/showthread.php?t=473046 Signed-off-by: Go Taniguchi Signed-off-by: maximilian attems Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 818e1480ca93..06041cb1c422 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -55,6 +55,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x14ea, 0xab10), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, @@ -92,6 +93,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B }, + { USB_DEVICE(0x2019, 0xed01), .driver_info = DEVICE_ZD1211B }, /* "Driverless" devices that need ejecting */ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, { USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER }, -- cgit v1.2.3 From d94519c1b0de827d5d142b9333b7f114c0b3a021 Mon Sep 17 00:00:00 2001 From: maximilian attems Date: Tue, 2 Nov 2010 23:39:12 +0100 Subject: zd1201: Add missing id The Mandriva patch seems to stem from 2.6.14, so much for their upstreaming effort. Didn't find another Linux reference of it, just an omnious "USB\VID_1044&PID_8004" from GigabyteZD1201U.INF for Gigabyte GN-WLBZ101 802.11b USB Adapter, which matches the Mandriva patch comment. Aboves file also lists an "USB\VID_1044&PID_8006", which I have kept appart as this "Gigabyte GN-WBZB-M 802.11b USB Adapter" didn't show up in googling. Signed-off-by: maximilian attems Signed-off-by: John W. Linville --- drivers/net/wireless/zd1201.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 390d77f762c4..b97aa9c78a96 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -30,6 +30,7 @@ static struct usb_device_id zd1201_table[] = { {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */ {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */ {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */ + {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */ {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */ {} }; -- cgit v1.2.3 From 21e731a1b15bf03927e292af1b4a2c84fc8af817 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 3 Nov 2010 21:36:12 +0100 Subject: b43legacy: rfkill: use status register based on core revision (not PHY's) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rafał Miłecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/rfkill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index d579df72b783..b90f223fb31c 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -29,7 +29,7 @@ /* Returns TRUE, if the radio is enabled in hardware. */ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { - if (dev->phy.rev >= 3) { + if (dev->dev->id.revision >= 3) { if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) return 1; -- cgit v1.2.3 From 066dae93bdfcc7af5e38a33617773fd5c6457607 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 7 Nov 2010 14:59:39 +0100 Subject: ath9k: rework tx queue selection and fix queue stopping/waking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current ath9k tx queue handling code showed a few issues that could lead to locking issues, tx stalls due to stopped queues, and maybe even DMA issues. The main source of these issues is that in some places the queue is selected via skb queue mapping in places where this mapping may no longer be valid. One such place is when data frames are transmitted via the CAB queue (for powersave buffered frames). This is made even worse by a lookup WMM AC values from the assigned tx queue (which is undefined for the CAB queue). This messed up the pending frame counting, which in turn caused issues with queues getting stopped, but not woken again. To fix these issues, this patch removes an unnecessary abstraction separating a driver internal queue number from the skb queue number (not to be confused with the hardware queue number). It seems that this abstraction may have been necessary because of tx queue preinitialization from the initvals. This patch avoids breakage here by pushing the software <-> hardware queue mapping to the function that assigns the tx queues and redefining the WMM AC definitions to match the numbers used by mac80211 (also affects ath9k_htc). To ensure consistency wrt. pending frame count tracking, these counters are moved to the ath_txq struct, updated with the txq lock held, but only where the tx queue selected by the skb queue map actually matches the tx queue used by the driver for the frame. Signed-off-by: Felix Fietkau Reported-by: Björn Smedman Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ath9k.h | 9 +-- drivers/net/wireless/ath/ath9k/beacon.c | 6 +- drivers/net/wireless/ath/ath9k/common.h | 9 +-- drivers/net/wireless/ath/ath9k/debug.c | 36 +++++----- drivers/net/wireless/ath/ath9k/debug.h | 5 +- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 9 ++- drivers/net/wireless/ath/ath9k/hw.h | 7 ++ drivers/net/wireless/ath/ath9k/init.c | 52 ++------------ drivers/net/wireless/ath/ath9k/main.c | 71 +++--------------- drivers/net/wireless/ath/ath9k/virtual.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 100 ++++++++++++-------------- 11 files changed, 109 insertions(+), 197 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 61d450750acb..21433465bde4 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -195,7 +195,6 @@ enum ATH_AGGR_STATUS { #define ATH_TXFIFO_DEPTH 8 struct ath_txq { - int axq_class; u32 axq_qnum; u32 *axq_link; struct list_head axq_q; @@ -208,11 +207,12 @@ struct ath_txq { struct list_head txq_fifo_pending; u8 txq_headidx; u8 txq_tailidx; + int pending_frames; }; struct ath_atx_ac { + struct ath_txq *txq; int sched; - int qnum; struct list_head list; struct list_head tid_q; }; @@ -290,12 +290,11 @@ struct ath_tx_control { struct ath_tx { u16 seq_no; u32 txqsetup; - int hwq_map[WME_NUM_AC]; spinlock_t txbuflock; struct list_head txbuf; struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma txdma; - int pending_frames[WME_NUM_AC]; + struct ath_txq *txq_map[WME_NUM_AC]; }; struct ath_rx_edma { @@ -325,7 +324,6 @@ void ath_rx_cleanup(struct ath_softc *sc); int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); -int ath_tx_setup(struct ath_softc *sc, int haltype); void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx); void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx); @@ -665,7 +663,6 @@ struct ath_wiphy { void ath9k_tasklet(unsigned long data); int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); static inline void ath_read_cachesize(struct ath_common *common, int *csz) diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 333da7bf2d7d..2377376c8d4d 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -28,7 +28,7 @@ int ath_beaconq_config(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi, qi_be; - int qnum; + struct ath_txq *txq; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { @@ -38,8 +38,8 @@ int ath_beaconq_config(struct ath_softc *sc) qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - qnum = sc->tx.hwq_map[WME_AC_BE]; - ath9k_hw_get_txq_props(ah, qnum, &qi_be); + txq = sc->tx.txq_map[WME_AC_BE]; + ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); qi.tqi_aifs = qi_be.tqi_aifs; qi.tqi_cwmin = 4*qi_be.tqi_cwmin; qi.tqi_cwmax = qi_be.tqi_cwmax; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index c76c75a77c62..4c04ee85ff0e 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -31,10 +31,11 @@ #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) -#define WME_AC_BE 0 -#define WME_AC_BK 1 -#define WME_AC_VI 2 -#define WME_AC_VO 3 +/* These must match mac80211 skb queue mapping numbers */ +#define WME_AC_VO 0 +#define WME_AC_VI 1 +#define WME_AC_BE 2 +#define WME_AC_BK 3 #define WME_NUM_AC 4 #define ATH_RSSI_DUMMY_MARKER 0x127 diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index a4052711eca8..0c3c74c157fb 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -585,10 +585,10 @@ static const struct file_operations fops_wiphy = { do { \ len += snprintf(buf + len, size - len, \ "%s%13u%11u%10u%10u\n", str, \ - sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BE]].elem, \ - sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_BK]].elem, \ - sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VI]].elem, \ - sc->debug.stats.txstats[sc->tx.hwq_map[WME_AC_VO]].elem); \ + sc->debug.stats.txstats[WME_AC_BE].elem, \ + sc->debug.stats.txstats[WME_AC_BK].elem, \ + sc->debug.stats.txstats[WME_AC_VI].elem, \ + sc->debug.stats.txstats[WME_AC_VO].elem); \ } while(0) static ssize_t read_file_xmit(struct file *file, char __user *user_buf, @@ -630,33 +630,35 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, return retval; } -void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf, struct ath_tx_status *ts) +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts) { - TX_STAT_INC(txq->axq_qnum, tx_pkts_all); - sc->debug.stats.txstats[txq->axq_qnum].tx_bytes_all += bf->bf_mpdu->len; + int qnum = skb_get_queue_mapping(bf->bf_mpdu); + + TX_STAT_INC(qnum, tx_pkts_all); + sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { if (bf_isxretried(bf)) - TX_STAT_INC(txq->axq_qnum, a_xretries); + TX_STAT_INC(qnum, a_xretries); else - TX_STAT_INC(txq->axq_qnum, a_completed); + TX_STAT_INC(qnum, a_completed); } else { - TX_STAT_INC(txq->axq_qnum, completed); + TX_STAT_INC(qnum, completed); } if (ts->ts_status & ATH9K_TXERR_FIFO) - TX_STAT_INC(txq->axq_qnum, fifo_underrun); + TX_STAT_INC(qnum, fifo_underrun); if (ts->ts_status & ATH9K_TXERR_XTXOP) - TX_STAT_INC(txq->axq_qnum, xtxop); + TX_STAT_INC(qnum, xtxop); if (ts->ts_status & ATH9K_TXERR_TIMER_EXPIRED) - TX_STAT_INC(txq->axq_qnum, timer_exp); + TX_STAT_INC(qnum, timer_exp); if (ts->ts_flags & ATH9K_TX_DESC_CFG_ERR) - TX_STAT_INC(txq->axq_qnum, desc_cfg_err); + TX_STAT_INC(qnum, desc_cfg_err); if (ts->ts_flags & ATH9K_TX_DATA_UNDERRUN) - TX_STAT_INC(txq->axq_qnum, data_underrun); + TX_STAT_INC(qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) - TX_STAT_INC(txq->axq_qnum, delim_underrun); + TX_STAT_INC(qnum, delim_underrun); } static const struct file_operations fops_xmit = { diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index bb0823242ba0..646ff7e04c88 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -169,8 +169,8 @@ void ath9k_exit_debug(struct ath_hw *ah); int ath9k_debug_create_root(void); void ath9k_debug_remove_root(void); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); -void ath_debug_stat_tx(struct ath_softc *sc, struct ath_txq *txq, - struct ath_buf *bf, struct ath_tx_status *ts); +void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_status *ts); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); #else @@ -199,7 +199,6 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, } static inline void ath_debug_stat_tx(struct ath_softc *sc, - struct ath_txq *txq, struct ath_buf *bf, struct ath_tx_status *ts) { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3d19b5bc937f..5324ffd96ec7 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -20,8 +20,15 @@ /* TX */ /******/ +static const int subtype_txq_to_hwq[] = { + [WME_AC_BE] = ATH_TXQ_AC_BE, + [WME_AC_BK] = ATH_TXQ_AC_BK, + [WME_AC_VI] = ATH_TXQ_AC_VI, + [WME_AC_VO] = ATH_TXQ_AC_VO, +}; + #define ATH9K_HTC_INIT_TXQ(subtype) do { \ - qi.tqi_subtype = subtype; \ + qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \ qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \ qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \ qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 366f088dc15d..e5b72262fd96 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -157,6 +157,13 @@ #define PAPRD_GAIN_TABLE_ENTRIES 32 #define PAPRD_TABLE_SZ 24 +enum ath_hw_txq_subtype { + ATH_TXQ_AC_BE = 0, + ATH_TXQ_AC_BK = 1, + ATH_TXQ_AC_VI = 2, + ATH_TXQ_AC_VO = 3, +}; + enum ath_ini_subsys { ATH_INI_PRE = 0, ATH_INI_CORE, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index adff0da01f4c..498f62180f1c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -395,7 +395,8 @@ static void ath9k_init_crypto(struct ath_softc *sc) static int ath9k_init_btcoex(struct ath_softc *sc) { - int r, qnum; + struct ath_txq *txq; + int r; switch (sc->sc_ah->btcoex_hw.scheme) { case ATH_BTCOEX_CFG_NONE: @@ -408,8 +409,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc) r = ath_init_btcoex_timer(sc); if (r) return -1; - qnum = sc->tx.hwq_map[WME_AC_BE]; - ath9k_hw_init_btcoex_hw(sc->sc_ah, qnum); + txq = sc->tx.txq_map[WME_AC_BE]; + ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; break; default: @@ -422,59 +423,18 @@ static int ath9k_init_btcoex(struct ath_softc *sc) static int ath9k_init_queues(struct ath_softc *sc) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); int i = 0; - for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) - sc->tx.hwq_map[i] = -1; - sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah); - if (sc->beacon.beaconq == -1) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup a beacon xmit queue\n"); - goto err; - } - sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->beacon.cabq == NULL) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup CAB xmit queue\n"); - goto err; - } sc->config.cabqReadytime = ATH_CABQ_READY_TIME; ath_cabq_update(sc); - if (!ath_tx_setup(sc, WME_AC_BK)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BK traffic\n"); - goto err; - } - - if (!ath_tx_setup(sc, WME_AC_BE)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for BE traffic\n"); - goto err; - } - if (!ath_tx_setup(sc, WME_AC_VI)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VI traffic\n"); - goto err; - } - if (!ath_tx_setup(sc, WME_AC_VO)) { - ath_print(common, ATH_DBG_FATAL, - "Unable to setup xmit queue for VO traffic\n"); - goto err; - } + for (i = 0; i < WME_NUM_AC; i++) + sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); return 0; - -err: - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->tx.txq[i]); - - return -EIO; } static int ath9k_init_channels_rates(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d522112cf736..df7c62d9bec4 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -330,7 +330,7 @@ void ath_paprd_calibrate(struct work_struct *work) struct ath_tx_control txctl; struct ath9k_hw_cal_data *caldata = ah->caldata; struct ath_common *common = ath9k_hw_common(ah); - int qnum, ftype; + int ftype; int chain_ok = 0; int chain; int len = 1800; @@ -357,8 +357,7 @@ void ath_paprd_calibrate(struct work_struct *work) memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); memset(&txctl, 0, sizeof(txctl)); - qnum = sc->tx.hwq_map[WME_AC_BE]; - txctl.txq = &sc->tx.txq[qnum]; + txctl.txq = sc->tx.txq_map[WME_AC_BE]; ath9k_ps_wakeup(sc); ar9003_paprd_init_table(ah); @@ -1024,56 +1023,6 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } -static int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case 0: - qnum = sc->tx.hwq_map[WME_AC_VO]; - break; - case 1: - qnum = sc->tx.hwq_map[WME_AC_VI]; - break; - case 2: - qnum = sc->tx.hwq_map[WME_AC_BE]; - break; - case 3: - qnum = sc->tx.hwq_map[WME_AC_BK]; - break; - default: - qnum = sc->tx.hwq_map[WME_AC_BE]; - break; - } - - return qnum; -} - -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case WME_AC_VO: - qnum = 0; - break; - case WME_AC_VI: - qnum = 1; - break; - case WME_AC_BE: - qnum = 2; - break; - case WME_AC_BK: - qnum = 3; - break; - default: - qnum = -1; - break; - } - - return qnum; -} - /* XXX: Remove me once we don't depend on ath9k_channel for all * this redundant data */ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, @@ -1243,7 +1192,6 @@ static int ath9k_tx(struct ieee80211_hw *hw, struct ath_tx_control txctl; int padpos, padsize; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int qnum; if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) { ath_print(common, ATH_DBG_XMIT, @@ -1316,8 +1264,7 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, padpos); } - qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txctl.txq = &sc->tx.txq[qnum]; + txctl.txq = sc->tx.txq_map[skb_get_queue_mapping(skb)]; ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); @@ -1801,12 +1748,15 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, struct ath_wiphy *aphy = hw->priv; struct ath_softc *sc = aphy->sc; struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_txq *txq; struct ath9k_tx_queue_info qi; - int ret = 0, qnum; + int ret = 0; if (queue >= WME_NUM_AC) return 0; + txq = sc->tx.txq_map[queue]; + mutex_lock(&sc->mutex); memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -1815,20 +1765,19 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; qi.tqi_burstTime = params->txop; - qnum = ath_get_hal_qnum(queue, sc); ath_print(common, ATH_DBG_CONFIG, "Configure tx [queue/halq] [%d/%d], " "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - queue, qnum, params->aifs, params->cw_min, + queue, txq->axq_qnum, params->aifs, params->cw_min, params->cw_max, params->txop); - ret = ath_txq_update(sc, qnum, &qi); + ret = ath_txq_update(sc, txq->axq_qnum, &qi); if (ret) ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) - if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret) + if (queue == WME_AC_BE && !ret) ath_beaconq_config(sc); mutex_unlock(&sc->mutex); diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c index cb6c48be1245..4008f51d34c8 100644 --- a/drivers/net/wireless/ath/ath9k/virtual.c +++ b/drivers/net/wireless/ath/ath9k/virtual.c @@ -187,7 +187,7 @@ static int ath9k_send_nullfunc(struct ath_wiphy *aphy, info->control.rates[1].idx = -1; memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.txq = &sc->tx.txq[sc->tx.hwq_map[WME_AC_VO]]; + txctl.txq = sc->tx.txq_map[WME_AC_VO]; txctl.frame_type = ps ? ATH9K_IFT_PAUSE : ATH9K_IFT_UNPAUSE; if (ath_tx_start(aphy->hw, skb, &txctl) != 0) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2bc422eb80c7..6380bbd82d49 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -124,7 +124,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + struct ath_txq *txq = tid->ac->txq; WARN_ON(!tid->paused); @@ -142,7 +142,7 @@ unlock: static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; + struct ath_txq *txq = tid->ac->txq; struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; @@ -817,7 +817,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { struct ath_node *an = (struct ath_node *)sta->drv_priv; struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; + struct ath_txq *txq = txtid->ac->txq; if (txtid->state & AGGR_CLEANUP) return; @@ -888,10 +888,16 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; + static const int subtype_txq_to_hwq[] = { + [WME_AC_BE] = ATH_TXQ_AC_BE, + [WME_AC_BK] = ATH_TXQ_AC_BK, + [WME_AC_VI] = ATH_TXQ_AC_VI, + [WME_AC_VO] = ATH_TXQ_AC_VO, + }; int qnum, i; memset(&qi, 0, sizeof(qi)); - qi.tqi_subtype = subtype; + qi.tqi_subtype = subtype_txq_to_hwq[subtype]; qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; @@ -940,7 +946,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) if (!ATH_TXQ_SETUP(sc, qnum)) { struct ath_txq *txq = &sc->tx.txq[qnum]; - txq->axq_class = subtype; txq->axq_qnum = qnum; txq->axq_link = NULL; INIT_LIST_HEAD(&txq->axq_q); @@ -1210,24 +1215,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) } } -int ath_tx_setup(struct ath_softc *sc, int haltype) -{ - struct ath_txq *txq; - - if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { - ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, - "HAL AC %u out of range, max %zu!\n", - haltype, ARRAY_SIZE(sc->tx.hwq_map)); - return 0; - } - txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); - if (txq != NULL) { - sc->tx.hwq_map[haltype] = txq->axq_qnum; - return 1; - } else - return 0; -} - /***********/ /* TX, DMA */ /***********/ @@ -1708,6 +1695,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } + WARN_ON(tid->ac->txq != txctl->txq); if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* * Try aggregation if it's a unicast data frame @@ -1747,6 +1735,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, return -1; } + q = skb_get_queue_mapping(skb); r = ath_tx_setup_buffer(hw, bf, skb, txctl); if (unlikely(r)) { ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n"); @@ -1756,8 +1745,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, * we will at least have to run TX completionon one buffer * on the queue */ spin_lock_bh(&txq->axq_lock); - if (!txq->stopped && txq->axq_depth > 1) { - ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); + if (txq == sc->tx.txq_map[q] && !txq->stopped && + txq->axq_depth > 1) { + ath_mac80211_stop_queue(sc, q); txq->stopped = 1; } spin_unlock_bh(&txq->axq_lock); @@ -1767,13 +1757,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, return r; } - q = skb_get_queue_mapping(skb); - if (q >= 4) - q = 0; - spin_lock_bh(&txq->axq_lock); - if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) { - ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb)); + if (txq == sc->tx.txq_map[q] && + ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { + ath_mac80211_stop_queue(sc, q); txq->stopped = 1; } spin_unlock_bh(&txq->axq_lock); @@ -1841,7 +1828,8 @@ exit: /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_wiphy *aphy, int tx_flags) + struct ath_wiphy *aphy, int tx_flags, + struct ath_txq *txq) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1888,11 +1876,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, ath9k_tx_status(hw, skb); else { q = skb_get_queue_mapping(skb); - if (q >= 4) - q = 0; - - if (--sc->tx.pending_frames[q] < 0) - sc->tx.pending_frames[q] = 0; + if (txq == sc->tx.txq_map[q]) { + spin_lock_bh(&txq->axq_lock); + if (WARN_ON(--txq->pending_frames < 0)) + txq->pending_frames = 0; + spin_unlock_bh(&txq->axq_lock); + } ieee80211_tx_status(hw, skb); } @@ -1927,8 +1916,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, else complete(&sc->paprd_complete); } else { - ath_debug_stat_tx(sc, txq, bf, ts); - ath_tx_complete(sc, skb, bf->aphy, tx_flags); + ath_debug_stat_tx(sc, bf, ts); + ath_tx_complete(sc, skb, bf->aphy, tx_flags, txq); } /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't * accidentally reference it later. @@ -2018,16 +2007,13 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1; } -static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) +static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum) { - int qnum; - - qnum = ath_get_mac80211_qnum(txq->axq_class, sc); - if (qnum == -1) - return; + struct ath_txq *txq; + txq = sc->tx.txq_map[qnum]; spin_lock_bh(&txq->axq_lock); - if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) { + if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { if (ath_mac80211_start_queue(sc, qnum)) txq->stopped = 0; } @@ -2044,6 +2030,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_tx_status ts; int txok; int status; + int qnum; ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), @@ -2119,12 +2106,15 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true); } + qnum = skb_get_queue_mapping(bf->bf_mpdu); + if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0); - ath_wake_mac80211_queue(sc, txq); + if (txq == sc->tx.txq_map[qnum]) + ath_wake_mac80211_queue(sc, qnum); spin_lock_bh(&txq->axq_lock); if (sc->sc_flags & SC_OP_TXAGGR) @@ -2194,6 +2184,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) struct list_head bf_head; int status; int txok; + int qnum; for (;;) { status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs); @@ -2237,13 +2228,16 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true); } + qnum = skb_get_queue_mapping(bf->bf_mpdu); + if (bf_isampdu(bf)) ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok); else ath_tx_complete_buf(sc, bf, txq, &bf_head, &txs, txok, 0); - ath_wake_mac80211_queue(sc, txq); + if (txq == sc->tx.txq_map[qnum]) + ath_wake_mac80211_queue(sc, qnum); spin_lock_bh(&txq->axq_lock); if (!list_empty(&txq->txq_fifo_pending)) { @@ -2375,7 +2369,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) for (acno = 0, ac = &an->ac[acno]; acno < WME_NUM_AC; acno++, ac++) { ac->sched = false; - ac->qnum = sc->tx.hwq_map[acno]; + ac->txq = sc->tx.txq_map[acno]; INIT_LIST_HEAD(&ac->tid_q); } } @@ -2385,17 +2379,13 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) struct ath_atx_ac *ac; struct ath_atx_tid *tid; struct ath_txq *txq; - int i, tidno; + int tidno; for (tidno = 0, tid = &an->tid[tidno]; tidno < WME_NUM_TID; tidno++, tid++) { - i = tid->ac->qnum; - - if (!ATH_TXQ_SETUP(sc, i)) - continue; - txq = &sc->tx.txq[i]; ac = tid->ac; + txq = ac->txq; spin_lock_bh(&txq->axq_lock); -- cgit v1.2.3 From 961621abee08fde2328daf6f8000e1059e5205e9 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:36:59 +0100 Subject: rt2x00: Add TXOP_CTRL_CFG register definition Remove the magic value initialisation of the TXOP_CTRL_CFG register by defining its fields and using them during intialisation. The field RESERVED_TRUN_EN is referred to as reserved, however it is set to 1 by the legacy drivers. Hence, do the same. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 23 +++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt2800lib.c | 18 +++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index eb8b6cab9925..6cfed0638ceb 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -960,8 +960,31 @@ /* * TXOP_CTRL_CFG: + * TIMEOUT_TRUN_EN: Enable/Disable TXOP timeout truncation + * AC_TRUN_EN: Enable/Disable truncation for AC change + * TXRATEGRP_TRUN_EN: Enable/Disable truncation for TX rate group change + * USER_MODE_TRUN_EN: Enable/Disable truncation for user TXOP mode + * MIMO_PS_TRUN_EN: Enable/Disable truncation for MIMO PS RTS/CTS + * RESERVED_TRUN_EN: Reserved + * LSIG_TXOP_EN: Enable/Disable L-SIG TXOP protection + * EXT_CCA_EN: Enable/Disable extension channel CCA reference (Defer 40Mhz + * transmissions if extension CCA is clear). + * EXT_CCA_DLY: Extension CCA signal delay time (unit: us) + * EXT_CWMIN: CwMin for extension channel backoff + * 0: Disabled + * */ #define TXOP_CTRL_CFG 0x1340 +#define TXOP_CTRL_CFG_TIMEOUT_TRUN_EN FIELD32(0x00000001) +#define TXOP_CTRL_CFG_AC_TRUN_EN FIELD32(0x00000002) +#define TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN FIELD32(0x00000004) +#define TXOP_CTRL_CFG_USER_MODE_TRUN_EN FIELD32(0x00000008) +#define TXOP_CTRL_CFG_MIMO_PS_TRUN_EN FIELD32(0x00000010) +#define TXOP_CTRL_CFG_RESERVED_TRUN_EN FIELD32(0x00000020) +#define TXOP_CTRL_CFG_LSIG_TXOP_EN FIELD32(0x00000040) +#define TXOP_CTRL_CFG_EXT_CCA_EN FIELD32(0x00000080) +#define TXOP_CTRL_CFG_EXT_CCA_DLY FIELD32(0x0000ff00) +#define TXOP_CTRL_CFG_EXT_CWMIN FIELD32(0x000f0000) /* * TX_RTS_CFG: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5f00e00789d8..54bf08570557 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -2097,7 +2097,23 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg); } - rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, 0x0000583f); + /* + * The legacy driver also sets TXOP_CTRL_CFG_RESERVED_TRUN_EN to 1 + * although it is reserved. + */ + rt2800_register_read(rt2x00dev, TXOP_CTRL_CFG, ®); + rt2x00_set_field32(®, TXOP_CTRL_CFG_TIMEOUT_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_AC_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_TXRATEGRP_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_USER_MODE_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_MIMO_PS_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_RESERVED_TRUN_EN, 1); + rt2x00_set_field32(®, TXOP_CTRL_CFG_LSIG_TXOP_EN, 0); + rt2x00_set_field32(®, TXOP_CTRL_CFG_EXT_CCA_EN, 0); + rt2x00_set_field32(®, TXOP_CTRL_CFG_EXT_CCA_DLY, 88); + rt2x00_set_field32(®, TXOP_CTRL_CFG_EXT_CWMIN, 0); + rt2800_register_write(rt2x00dev, TXOP_CTRL_CFG, reg); + rt2800_register_write(rt2x00dev, TXOP_HLDR_ET, 0x00000002); rt2800_register_read(rt2x00dev, TX_RTS_CFG, ®); -- cgit v1.2.3 From efd2f271e44c7ea011cdb0363d38f40338ab80d2 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:37:22 +0100 Subject: rt2x00: Sync Tx and RX ring sizes with legacy drivers All rt2x00 devices used the same Tx and Rx ring size (24 entries) till now. Newer devices (like rt2800) can however make use of a larger TX and RX ring due to 11n capabilities (AMPDUs of size 64 for example). Hence, bring rt2x00 in sync with the legacy drivers and use the same TX and RX ring sizes. Also remove the global defines RX_ENTRIES, TX_ENTRIES, BEACON_ENTRIES and ATIM_ENTRIES and use per driver values. That is 24 entries for rt2400pci, 32 entries for rt2500pci, rt2500usb, rt61pci and rt73usb and 128 (RX) and 64 (TX) for rt2800pci and rt2800usb. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2500pci.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2500usb.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2800pci.c | 8 ++++---- drivers/net/wireless/rt2x00/rt2800usb.c | 9 +++++---- drivers/net/wireless/rt2x00/rt2x00queue.h | 16 ---------------- drivers/net/wireless/rt2x00/rt61pci.c | 8 ++++---- drivers/net/wireless/rt2x00/rt73usb.c | 6 +++--- 9 files changed, 29 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4f420a9ec5dc..c94aa1e5d089 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1640,28 +1640,28 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { }; static const struct data_queue_desc rt2400pci_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 24, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 24, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_bcn = { - .entry_num = BEACON_ENTRIES, + .entry_num = 1, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2400pci_queue_atim = { - .entry_num = ATIM_ENTRIES, + .entry_num = 8, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 97feb7aef809..ab6c9eccd9bb 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1937,28 +1937,28 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { }; static const struct data_queue_desc rt2500pci_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_bcn = { - .entry_num = BEACON_ENTRIES, + .entry_num = 1, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2500pci_queue_atim = { - .entry_num = ATIM_ENTRIES, + .entry_num = 8, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 93e44c7f3a74..725ae34f1815 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1829,28 +1829,28 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { }; static const struct data_queue_desc rt2500usb_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2500usb_queue_bcn = { - .entry_num = BEACON_ENTRIES, + .entry_num = 1, .data_size = MGMT_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb_bcn), }; static const struct data_queue_desc rt2500usb_queue_atim = { - .entry_num = ATIM_ENTRIES, + .entry_num = 8, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 54bf08570557..b1738bbf87ff 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -727,7 +727,7 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev) * that the TX_STA_FIFO stack has a size of 16. We stick to our * tx ring size for now. */ - for (i = 0; i < TX_ENTRIES; i++) { + for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { rt2800_register_read(rt2x00dev, TX_STA_FIFO, ®); if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID)) break; diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index b26739535986..2c12b598be50 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -777,7 +777,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) * Since we have only one producer and one consumer we don't * need to lock the kfifo. */ - for (i = 0; i < TX_ENTRIES; i++) { + for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status); if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID)) @@ -991,21 +991,21 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { }; static const struct data_queue_desc rt2800pci_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 128, .data_size = AGGREGATION_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2800pci_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 64, .data_size = AGGREGATION_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt2800pci_queue_bcn = { - .entry_num = 8 * BEACON_ENTRIES, + .entry_num = 8, .data_size = 0, /* No DMA required for beacons */ .desc_size = TXWI_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3dff56ec195a..3f44131baeee 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -165,7 +165,8 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev) * this limit so reduce the number to prevent errors. */ rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_AGG_LIMIT, - ((RX_ENTRIES * DATA_FRAME_SIZE) / 1024) - 3); + ((rt2x00dev->ops->rx->entry_num * DATA_FRAME_SIZE) + / 1024) - 3); rt2x00_set_field32(®, USB_DMA_CFG_RX_BULK_EN, 1); rt2x00_set_field32(®, USB_DMA_CFG_TX_BULK_EN, 1); rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg); @@ -553,21 +554,21 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { }; static const struct data_queue_desc rt2800usb_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 128, .data_size = AGGREGATION_SIZE, .desc_size = RXINFO_DESC_SIZE + RXWI_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2800usb_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 64, .data_size = AGGREGATION_SIZE, .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt2800usb_queue_bcn = { - .entry_num = 8 * BEACON_ENTRIES, + .entry_num = 8, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_DESC_SIZE + TXWI_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index d81d85f34866..64acfb62d909 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -42,22 +42,6 @@ #define MGMT_FRAME_SIZE 256 #define AGGREGATION_SIZE 3840 -/** - * DOC: Number of entries per queue - * - * Under normal load without fragmentation, 12 entries are sufficient - * without the queue being filled up to the maximum. When using fragmentation - * and the queue threshold code, we need to add some additional margins to - * make sure the queue will never (or only under extreme load) fill up - * completely. - * Since we don't use preallocated DMA, having a large number of queue entries - * will have minimal impact on the memory requirements for the queue. - */ -#define RX_ENTRIES 24 -#define TX_ENTRIES 24 -#define BEACON_ENTRIES 1 -#define ATIM_ENTRIES 8 - /** * enum data_queue_qid: Queue identification * diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index af548c87f108..3232336b7f42 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2078,7 +2078,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) * that the TX_STA_FIFO stack has a size of 16. We stick to our * tx ring size for now. */ - for (i = 0; i < TX_ENTRIES; i++) { + for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) { rt2x00pci_register_read(rt2x00dev, STA_CSR4, ®); if (!rt2x00_get_field32(reg, STA_CSR4_VALID)) break; @@ -2857,21 +2857,21 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { }; static const struct data_queue_desc rt61pci_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), }; static const struct data_queue_desc rt61pci_queue_bcn = { - .entry_num = 4 * BEACON_ENTRIES, + .entry_num = 4, .data_size = 0, /* No DMA required for beacons */ .desc_size = TXINFO_SIZE, .priv_size = sizeof(struct queue_entry_priv_pci), diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 9be8089317e4..67447ec005bf 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2296,21 +2296,21 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { }; static const struct data_queue_desc rt73usb_queue_rx = { - .entry_num = RX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = RXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_tx = { - .entry_num = TX_ENTRIES, + .entry_num = 32, .data_size = DATA_FRAME_SIZE, .desc_size = TXD_DESC_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), }; static const struct data_queue_desc rt73usb_queue_bcn = { - .entry_num = 4 * BEACON_ENTRIES, + .entry_num = 4, .data_size = MGMT_FRAME_SIZE, .desc_size = TXINFO_SIZE, .priv_size = sizeof(struct queue_entry_priv_usb), -- cgit v1.2.3 From 08e5310028359de2daaa39cd10e9ca493c51792b Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:37:47 +0100 Subject: rt2x00: Wait up to one second on rt2800 for WPDMA to be ready At least some devices need such a long time to inititalize WPDMA. This only increases the maximum wait time and shouldn't affect devices that have been working before. Reported-by: Joshua Smith Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index b1738bbf87ff..dcd3a8981ca2 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -277,13 +277,17 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev) unsigned int i; u32 reg; + /* + * Some devices are really slow to respond here. Wait a whole second + * before timing out. + */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, ®); if (!rt2x00_get_field32(reg, WPDMA_GLO_CFG_TX_DMA_BUSY) && !rt2x00_get_field32(reg, WPDMA_GLO_CFG_RX_DMA_BUSY)) return 0; - msleep(1); + msleep(10); } ERROR(rt2x00dev, "WPDMA TX/RX busy, aborting.\n"); -- cgit v1.2.3 From 2b23cdaa3b0e9567597563e5a7a5103ecda447f0 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:38:15 +0100 Subject: rt2x00: Reduce tx descriptor size The tx descriptor values qid, cw_min, cw_max and aifs are directly accessible through the tx entry struct. So there's no need to copy them into the tx descriptor and passing them to the indiviual drivers. Instead we can just get the correct value from the tx entry. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.c | 6 +++--- drivers/net/wireless/rt2x00/rt2500usb.c | 6 +++--- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 8 -------- drivers/net/wireless/rt2x00/rt2x00queue.h | 9 --------- drivers/net/wireless/rt2x00/rt61pci.c | 14 +++++++------- drivers/net/wireless/rt2x00/rt73usb.c | 8 ++++---- 7 files changed, 18 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index ab6c9eccd9bb..b69e55fedda9 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1193,9 +1193,9 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry, rt2x00_desc_read(txd, 2, &word); rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field32(&word, TXD_W2_AIFS, txdesc->aifs); - rt2x00_set_field32(&word, TXD_W2_CWMIN, txdesc->cw_min); - rt2x00_set_field32(&word, TXD_W2_CWMAX, txdesc->cw_max); + rt2x00_set_field32(&word, TXD_W2_AIFS, entry->queue->aifs); + rt2x00_set_field32(&word, TXD_W2_CWMIN, entry->queue->cw_min); + rt2x00_set_field32(&word, TXD_W2_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 725ae34f1815..f20ab79b2817 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1081,9 +1081,9 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry, rt2x00_desc_read(txd, 1, &word); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); - rt2x00_set_field32(&word, TXD_W1_AIFS, txdesc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); + rt2x00_set_field32(&word, TXD_W1_AIFS, entry->queue->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); rt2x00_desc_write(txd, 1, word); rt2x00_desc_read(txd, 2, &word); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index dcd3a8981ca2..6fa654956f4e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -487,7 +487,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, txdesc->key_idx : 0xff); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, txdesc->length); - rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, txdesc->qid); + rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid); rt2x00_set_field32(&word, TXWI_W1_PACKETID_ENTRY, (entry->entry_idx % 3) + 1); rt2x00_desc_write(txwi, 1, word); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index e360d287defb..4e2a8c2e014d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -310,14 +310,6 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, memset(txdesc, 0, sizeof(*txdesc)); - /* - * Initialize information from queue - */ - txdesc->qid = entry->queue->qid; - txdesc->cw_min = entry->queue->cw_min; - txdesc->cw_max = entry->queue->cw_max; - txdesc->aifs = entry->queue->aifs; - /* * Header and frame information. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 64acfb62d909..8a36ef31e893 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -280,7 +280,6 @@ enum txentry_desc_flags { * Summary of information for the frame descriptor before sending a TX frame. * * @flags: Descriptor flags (See &enum queue_entry_flags). - * @qid: Queue identification (See &enum data_queue_qid). * @length: Length of the entire frame. * @header_length: Length of 802.11 header. * @length_high: PLCP length high word. @@ -293,11 +292,8 @@ enum txentry_desc_flags { * @rate_mode: Rate mode (See @enum rate_modulation). * @mpdu_density: MDPU density. * @retry_limit: Max number of retries. - * @aifs: AIFS value. * @ifs: IFS value. * @txop: IFS value for 11n capable chips. - * @cw_min: cwmin value. - * @cw_max: cwmax value. * @cipher: Cipher type used for encryption. * @key_idx: Key index used for encryption. * @iv_offset: Position where IV should be inserted by hardware. @@ -306,8 +302,6 @@ enum txentry_desc_flags { struct txentry_desc { unsigned long flags; - enum data_queue_qid qid; - u16 length; u16 header_length; @@ -323,11 +317,8 @@ struct txentry_desc { u16 mpdu_density; short retry_limit; - short aifs; short ifs; short txop; - short cw_min; - short cw_max; enum cipher cipher; u16 key_idx; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 3232336b7f42..fba9ee11873b 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1789,10 +1789,10 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); - rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); + rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); @@ -1820,7 +1820,7 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); - if (txdesc->qid != QID_BEACON) { + if (entry->queue->qid != QID_BEACON) { rt2x00_desc_read(txd, 6, &word); rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, skbdesc->skb_dma); @@ -1866,8 +1866,8 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry, * Register descriptor details in skb frame descriptor. */ skbdesc->desc = txd; - skbdesc->desc_len = - (txdesc->qid == QID_BEACON) ? TXINFO_SIZE : TXD_DESC_SIZE; + skbdesc->desc_len = (entry->queue->qid == QID_BEACON) ? TXINFO_SIZE : + TXD_DESC_SIZE; } /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 67447ec005bf..3c86f0075aed 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1472,10 +1472,10 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry, rt2x00_desc_write(txd, 0, word); rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, txdesc->qid); - rt2x00_set_field32(&word, TXD_W1_AIFSN, txdesc->aifs); - rt2x00_set_field32(&word, TXD_W1_CWMIN, txdesc->cw_min); - rt2x00_set_field32(&word, TXD_W1_CWMAX, txdesc->cw_max); + rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, entry->queue->qid); + rt2x00_set_field32(&word, TXD_W1_AIFSN, entry->queue->aifs); + rt2x00_set_field32(&word, TXD_W1_CWMIN, entry->queue->cw_min); + rt2x00_set_field32(&word, TXD_W1_CWMAX, entry->queue->cw_max); rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, test_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags)); -- cgit v1.2.3 From e2f8c8752b994026fc0ddb4bb29ca229b3e0c104 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:38:56 +0100 Subject: rt2x00: Optimize rt2x00debug_dump_frame when frame dumping is not active When rt2x00 is compiled with debugging but frame dumping is currently not active we can avoid the call to do_gettimeofday. Furthermore, frame dumping is not the default case, mark it as unlikely. Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index fcdb6b0dc40f..8296a9d47bbd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -162,11 +162,11 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct timeval timestamp; u32 data_len; - do_gettimeofday(×tamp); - - if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) + if (likely(!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))) return; + do_gettimeofday(×tamp); + if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) { DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n"); return; -- cgit v1.2.3 From 7225ce1ea93d24c0914eea0410dcfc426281f996 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 4 Nov 2010 20:39:23 +0100 Subject: rt2x00: Rename rt2x00queue_timeout Rename rt2x00queue_timeout to rt2x00queue_status_timeout to better describe what is actually timing out (note that we already have a rt2x00queue_dma_timeout). Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.h | 4 ++-- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 8a36ef31e893..64c00e2ab716 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -593,10 +593,10 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00queue_timeout - Check if a timeout occured for STATUS reorts + * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports * @queue: Queue to check. */ -static inline int rt2x00queue_timeout(struct data_queue *queue) +static inline int rt2x00queue_status_timeout(struct data_queue *queue) { return time_after(queue->last_action[Q_INDEX_DMA_DONE], queue->last_action[Q_INDEX_DONE] + (HZ / 10)); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index b3317df7a7d4..88995d50a5c7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -361,7 +361,7 @@ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev) if (!rt2x00queue_empty(queue)) { if (rt2x00queue_dma_timeout(queue)) rt2x00usb_watchdog_tx_dma(queue); - if (rt2x00queue_timeout(queue)) + if (rt2x00queue_status_timeout(queue)) rt2x00usb_watchdog_tx_status(queue); } } -- cgit v1.2.3 From aaf886bd215396f295bc0489e8ae09d1c03d9aa0 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 4 Nov 2010 20:39:48 +0100 Subject: rt2x00: Remove failsave from rt2x00usb_watchdog_tx_dma When the TX status handler failed to clear the queue in rt2x00usb_watchdog_tx_dma() we shouldn't use a failsave to use the rt2x00usb txdone handler. If a driver has overriden the txdone handler it must make sure the txdone handler is capable of cleaning up the queue itself. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00usb.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 88995d50a5c7..6dd96192dd91 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -322,21 +322,6 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue) */ rt2x00dev->txdone_work.func(&rt2x00dev->txdone_work); - /* - * Security measure: if the driver did override the - * txdone_work function, and the hardware did arrive - * in a state which causes it to malfunction, it is - * possible that the driver couldn't handle the txdone - * event correctly. So after giving the driver the - * chance to cleanup, we now force a cleanup of any - * leftovers. - */ - if (!rt2x00queue_empty(queue)) { - WARNING(queue->rt2x00dev, "TX queue %d DMA timed out," - " status handling failed, invoke hard reset", queue->qid); - rt2x00usb_work_txdone(&rt2x00dev->txdone_work); - } - /* * The queue has been reset, and mac80211 is allowed to use the * queue again. -- cgit v1.2.3 From f44df18c58d4debe3ec0bb76a490aa2f3929fd8b Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 4 Nov 2010 20:40:11 +0100 Subject: rt2x00: Implement flush callback Implement a basic flush callback function, which simply loops over all TX queues and waits until all frames have been transmitted and the status reports have been gathered. At this moment we don't support dropping any frames during the flush, but mac80211 will only send 'false' for this argument anyway, so this is not important at this time. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 1 + drivers/net/wireless/rt2x00/rt2500pci.c | 1 + drivers/net/wireless/rt2x00/rt2500usb.c | 1 + drivers/net/wireless/rt2x00/rt2800pci.c | 1 + drivers/net/wireless/rt2x00/rt2800usb.c | 1 + drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00mac.c | 38 +++++++++++++++++++++++++++++++++ drivers/net/wireless/rt2x00/rt61pci.c | 1 + drivers/net/wireless/rt2x00/rt73usb.c | 1 + 9 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index c94aa1e5d089..bc1ae1ebfdb0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -1612,6 +1612,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .get_tsf = rt2400pci_get_tsf, .tx_last_beacon = rt2400pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, }; static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index b69e55fedda9..54754150250b 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1909,6 +1909,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .get_tsf = rt2500pci_get_tsf, .tx_last_beacon = rt2500pci_tx_last_beacon, .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, }; static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index f20ab79b2817..478c4f127ce6 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1801,6 +1801,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, }; static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 2c12b598be50..6dc61b7710b9 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -943,6 +943,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .get_tsf = rt2800_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .ampdu_action = rt2800_ampdu_action, + .flush = rt2x00mac_flush, }; static const struct rt2800_ops rt2800pci_rt2800_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 3f44131baeee..04dfedc70f85 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -508,6 +508,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .get_tsf = rt2800_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, .ampdu_action = rt2800_ampdu_action, + .flush = rt2x00mac_flush, }; static const struct rt2800_ops rt2800usb_rt2800_ops = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 94fe589acfaa..42bd3a96f23b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -1133,6 +1133,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); +void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); /* * Driver allocation handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index c3c206a97d54..283a8d9874ee 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -719,3 +719,41 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) wiphy_rfkill_set_hw_state(hw->wiphy, !active); } EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); + +void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct data_queue *queue; + unsigned int i = 0; + + ieee80211_stop_queues(hw); + + /* + * Run over all queues to kick them, this will force + * any pending frames to be transmitted. + */ + tx_queue_for_each(rt2x00dev, queue) { + rt2x00dev->ops->lib->kick_tx_queue(queue); + } + + /** + * All queues have been kicked, now wait for each queue + * to become empty. With a bit of luck, we only have to wait + * for the first queue to become empty, because while waiting + * for the that queue, the other queues will have transmitted + * all their frames as well (since they were already kicked). + */ + tx_queue_for_each(rt2x00dev, queue) { + for (i = 0; i < 10; i++) { + if (rt2x00queue_empty(queue)) + break; + msleep(100); + } + + if (!rt2x00queue_empty(queue)) + WARNING(rt2x00dev, "Failed to flush queue %d", queue->qid); + } + + ieee80211_wake_queues(hw); +} +EXPORT_SYMBOL_GPL(rt2x00mac_flush); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index fba9ee11873b..f01bff7656bc 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -2824,6 +2824,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .conf_tx = rt61pci_conf_tx, .get_tsf = rt61pci_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, }; static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 3c86f0075aed..dcb9211c4771 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2264,6 +2264,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .conf_tx = rt73usb_conf_tx, .get_tsf = rt73usb_get_tsf, .rfkill_poll = rt2x00mac_rfkill_poll, + .flush = rt2x00mac_flush, }; static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { -- cgit v1.2.3 From 303c7d6abfd0430e39e84a43361492b4a8c890b6 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 4 Nov 2010 20:40:46 +0100 Subject: rt2x00: Fix MCU_SLEEP arguments Legacy driver uses 0xff as the second argument for the MCU_SLEEP command. It is still unknown what the values actually mean, but this will at least keep the command in-sync with the original driver. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.c | 2 +- drivers/net/wireless/rt2x00/rt2800usb.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 6dc61b7710b9..1db0c3bf2e1f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -442,7 +442,7 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev, * if the device is booting and wasn't asleep it will return * failure when attempting to wakeup. */ - rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2); if (state == STATE_AWAKE) { rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 04dfedc70f85..5c31e3350aac 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -184,9 +184,9 @@ static int rt2800usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) { if (state == STATE_AWAKE) - rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 0); + rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, 0xff, 0, 2); else - rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0, 2); + rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0xff, 0xff, 2); return 0; } -- cgit v1.2.3 From 070192dd2975c0e97bbdeac7623b755235c6db7d Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Thu, 4 Nov 2010 20:41:05 +0100 Subject: rt2x00: Fix crash on USB unplug By not scheduling the TX/RX completion worker threads when Radio is disabled, or hardware has been unplugged, the queues cannot be completely cleaned. This causes crashes when the hardware has been unplugged while the radio is still enabled. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 12 ++++++++++-- drivers/net/wireless/rt2x00/rt2x00usb.c | 8 ++------ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5ba79b935f09..0f34d996975b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -483,6 +483,10 @@ void rt2x00lib_rxdone(struct queue_entry *entry) unsigned int header_length; int rate_idx; + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || + !test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + goto submit_entry; + if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) goto submit_entry; @@ -567,9 +571,13 @@ void rt2x00lib_rxdone(struct queue_entry *entry) entry->skb = skb; submit_entry: - rt2x00dev->ops->lib->clear_entry(entry); - rt2x00queue_index_inc(entry->queue, Q_INDEX); + entry->flags = 0; rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); + if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && + test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { + rt2x00dev->ops->lib->clear_entry(entry); + rt2x00queue_index_inc(entry->queue, Q_INDEX); + } } EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 6dd96192dd91..9ac14598e2a0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -226,9 +226,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) * Schedule the delayed work for reading the TX status * from the device. */ - if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->txdone_work); } static void rt2x00usb_kick_tx_entry(struct queue_entry *entry) @@ -409,9 +407,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Schedule the delayed work for reading the RX status * from the device. */ - if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && - test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) - ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); + ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->rxdone_work); } /* -- cgit v1.2.3 From fa8b4b22d543b4052602b0c86065150613ed19e8 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Thu, 4 Nov 2010 20:42:36 +0100 Subject: rt2x00: Fix hw crypto in AP mode for some devices The BSSID register shouldn't be set in AP mode on some older devices (like rt73usb) as it breaks hw crypto on these. However, rt2800 devices explicitly need the BSSID register set to the same value as our own MAC address (only in AP mode). Hence, don't set the BSSID from rt2x00lib but move it down into rt2800 to avoid problems on older devices. This fixes a regression (at least for rt73usb) and avoids a new regression for rt2800 devices in 2.6.36. Reported-by: Johannes Stezenbach Reported-by: Lee Signed-off-by: Helmut Schaa Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 13 ++++++++++++- drivers/net/wireless/rt2x00/rt2x00mac.c | 10 ++-------- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 6fa654956f4e..a53536dc882d 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1148,6 +1148,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, struct rt2x00intf_conf *conf, const unsigned int flags) { u32 reg; + bool update_bssid = false; if (flags & CONFIG_UPDATE_TYPE) { /* @@ -1177,6 +1178,16 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, } if (flags & CONFIG_UPDATE_MAC) { + if (flags & CONFIG_UPDATE_TYPE && + conf->sync == TSF_SYNC_AP_NONE) { + /* + * The BSSID register has to be set to our own mac + * address in AP mode. + */ + memcpy(conf->bssid, conf->mac, sizeof(conf->mac)); + update_bssid = true; + } + if (!is_zero_ether_addr((const u8 *)conf->mac)) { reg = le32_to_cpu(conf->mac[1]); rt2x00_set_field32(®, MAC_ADDR_DW1_UNICAST_TO_ME_MASK, 0xff); @@ -1187,7 +1198,7 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, conf->mac, sizeof(conf->mac)); } - if (flags & CONFIG_UPDATE_BSSID) { + if ((flags & CONFIG_UPDATE_BSSID) || update_bssid) { if (!is_zero_ether_addr((const u8 *)conf->bssid)) { reg = le32_to_cpu(conf->bssid[1]); rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 283a8d9874ee..36ddee8dc9e2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -283,14 +283,8 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, * invalid behavior in the device. */ memcpy(&intf->mac, vif->addr, ETH_ALEN); - if (vif->type == NL80211_IFTYPE_AP) { - memcpy(&intf->bssid, vif->addr, ETH_ALEN); - rt2x00lib_config_intf(rt2x00dev, intf, vif->type, - intf->mac, intf->bssid); - } else { - rt2x00lib_config_intf(rt2x00dev, intf, vif->type, - intf->mac, NULL); - } + rt2x00lib_config_intf(rt2x00dev, intf, vif->type, + intf->mac, NULL); /* * Some filters depend on the current working mode. We can force -- cgit v1.2.3 From 723fc7af5300dba9eac40cb23dbefa67589e5181 Mon Sep 17 00:00:00 2001 From: Lalith Suresh Date: Thu, 4 Nov 2010 20:43:16 +0100 Subject: rt2x00: Fix comments in rt73usb.h and rt61pci.h This patch fixes a few comments in rt73usb.h and rt61pci.h. Signed-off-by: Lalith Suresh Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt61pci.h | 2 +- drivers/net/wireless/rt2x00/rt73usb.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index e2e728ab0b2e..afc803b7959f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -412,7 +412,7 @@ struct hw_pairwise_ta_entry { * DROP_VERSION_ERROR: Drop version error frame. * DROP_MULTICAST: Drop multicast frames. * DROP_BORADCAST: Drop broadcast frames. - * ROP_ACK_CTS: Drop received ACK and CTS. + * DROP_ACK_CTS: Drop received ACK and CTS. */ #define TXRX_CSR0 0x3040 #define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 44d5b2bebd39..1315ce5c992f 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -322,7 +322,7 @@ struct hw_pairwise_ta_entry { * DROP_VERSION_ERROR: Drop version error frame. * DROP_MULTICAST: Drop multicast frames. * DROP_BORADCAST: Drop broadcast frames. - * ROP_ACK_CTS: Drop received ACK and CTS. + * DROP_ACK_CTS: Drop received ACK and CTS. */ #define TXRX_CSR0 0x3040 #define TXRX_CSR0_RX_ACK_TIMEOUT FIELD32(0x000001ff) -- cgit v1.2.3 From 041fb8f504fb0a6b61bc2131679da554b2fa8c9d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 6 Nov 2010 14:07:10 +0100 Subject: carl9170: tx path review This patch fixes a few shortcomings in the tx path. * move temp. ampdu_[ack]_len out of txinfo->pad. * fix WARN_ON from tx.c:line 300 when tx_ampdu_queue fails to queue the frame. * In tx_prepare, we already have a local pointer to the station's ieee80211_sta struct. * remove a second !sta check, tx_prepare already takes care of that. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/tx.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index b27969c41812..688eede48516 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -242,9 +242,11 @@ static void carl9170_tx_release(struct kref *ref) ar->tx_ampdu_schedule = true; if (txinfo->flags & IEEE80211_TX_STAT_AMPDU) { - txinfo->status.ampdu_len = txinfo->pad[0]; - txinfo->status.ampdu_ack_len = txinfo->pad[1]; - txinfo->pad[0] = txinfo->pad[1] = 0; + struct _carl9170_tx_superframe *super; + + super = (void *)skb->data; + txinfo->status.ampdu_len = super->s.rix; + txinfo->status.ampdu_ack_len = super->s.cnt; } else if (txinfo->flags & IEEE80211_TX_STAT_ACK) { /* * drop redundant tx_status reports: @@ -337,7 +339,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, u8 tid; if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || - txinfo->flags & IEEE80211_TX_CTL_INJECTED) + txinfo->flags & IEEE80211_TX_CTL_INJECTED || + (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) return; tx_info = IEEE80211_SKB_CB(skb); @@ -389,8 +392,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, sta_info->stats[tid].ampdu_ack_len++; if (super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_IMM_BA)) { - txinfo->pad[0] = sta_info->stats[tid].ampdu_len; - txinfo->pad[1] = sta_info->stats[tid].ampdu_ack_len; + super->s.rix = sta_info->stats[tid].ampdu_len; + super->s.cnt = sta_info->stats[tid].ampdu_ack_len; txinfo->flags |= IEEE80211_TX_STAT_AMPDU; sta_info->stats[tid].clear = true; } @@ -896,10 +899,8 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb) if (unlikely(!sta || !cvif)) goto err_out; - factor = min_t(unsigned int, 1u, - info->control.sta->ht_cap.ampdu_factor); - - density = info->control.sta->ht_cap.ampdu_density; + factor = min_t(unsigned int, 1u, sta->ht_cap.ampdu_factor); + density = sta->ht_cap.ampdu_density; if (density) { /* @@ -1260,6 +1261,7 @@ static void carl9170_tx(struct ar9170 *ar) static bool carl9170_tx_ampdu_queue(struct ar9170 *ar, struct ieee80211_sta *sta, struct sk_buff *skb) { + struct _carl9170_tx_superframe *super = (void *) super; struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *agg; struct sk_buff *iter; @@ -1328,6 +1330,7 @@ err_unlock: err_unlock_rcu: rcu_read_unlock(); + super->f.mac_control &= ~cpu_to_le16(AR9170_TX_MAC_AGGR); carl9170_tx_status(ar, skb, false); ar->tx_dropped++; return false; @@ -1356,9 +1359,6 @@ int carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) */ if (info->flags & IEEE80211_TX_CTL_AMPDU) { - if (WARN_ON_ONCE(!sta)) - goto err_free; - run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) carl9170_tx_ampdu(ar); -- cgit v1.2.3 From 46b9786975a69a75f25b71796f7e36d203fbd4ee Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:44:00 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2400pci.h rt2400pci.h:812: ERROR: space prohibited after that open parenthesis '(' rt2400pci.h:812: ERROR: space prohibited before that close parenthesis ')' rt2400pci.h:813: ERROR: space prohibited after that open parenthesis '(' rt2400pci.h:813: ERROR: space prohibited before that close parenthesis ')' rt2400pci.h:950: ERROR: Macros with complex values should be enclosed in parenthesis Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index c048b18f4133..d3a4a68cc439 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -809,8 +809,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 8 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 8 * sizeof(__le32) ) +#define TXD_DESC_SIZE (8 * sizeof(__le32)) +#define RXD_DESC_SIZE (8 * sizeof(__le32)) /* * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. @@ -948,6 +948,6 @@ ((__CLAMP_TX(__txpower) - MAX_TXPOWER) + MIN_TXPOWER) #define TXPOWER_TO_DEV(__txpower) \ - MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER) + (MAX_TXPOWER - (__CLAMP_TX(__txpower) - MIN_TXPOWER)) #endif /* RT2400PCI_H */ -- cgit v1.2.3 From cb771b1a5de81e3ee59bd8b7ed17da6d09ffcf68 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:44:15 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2500pci.h rt2500pci.h:1091: ERROR: space prohibited after that open parenthesis '(' rt2500pci.h:1091: ERROR: space prohibited before that close parenthesis ')' rt2500pci.h:1092: ERROR: space prohibited after that open parenthesis '(' rt2500pci.h:1092: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500pci.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index d708031361ac..2aad7ba8a100 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1088,8 +1088,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 11 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 11 * sizeof(__le32) ) +#define TXD_DESC_SIZE (11 * sizeof(__le32)) +#define RXD_DESC_SIZE (11 * sizeof(__le32)) /* * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. -- cgit v1.2.3 From cf553477a4dfb819c66ebfcad9f3b5cc3b93a9af Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:44:33 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2500usb.c rt2500usb.c:42: ERROR: do not initialise statics to 0 or NULL Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2500usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 478c4f127ce6..10e51f208f07 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -39,7 +39,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt = 0; +static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -- cgit v1.2.3 From fd8dab9a67b22c35f38f0f5bfff4b3f6ed02e43a Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:44:52 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2800.h rt2800.h:1511: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1511: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1513: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1513: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1515: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1515: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1517: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1517: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1519: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1519: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1521: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1521: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1661: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1661: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1662: ERROR: space prohibited after that open parenthesis '(' rt2800.h:1662: ERROR: space prohibited before that close parenthesis ')' rt2800.h:1663: ERROR: space prohibited before that close parenthesis ')' rt2800.h:2013: ERROR: space prohibited after that open parenthesis '(' rt2800.h:2013: ERROR: space prohibited before that close parenthesis ')' rt2800.h:2014: ERROR: space prohibited after that open parenthesis '(' rt2800.h:2014: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 6cfed0638ceb..c2cc126502d6 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -1508,17 +1508,17 @@ #define SHARED_KEY_MODE_BASE 0x7000 #define MAC_WCID_ENTRY(__idx) \ - ( MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry)) ) + (MAC_WCID_BASE + ((__idx) * sizeof(struct mac_wcid_entry))) #define PAIRWISE_KEY_ENTRY(__idx) \ - ( PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) + (PAIRWISE_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry))) #define MAC_IVEIV_ENTRY(__idx) \ - ( MAC_IVEIV_TABLE_BASE + ((__idx) * sizeof(struct mac_iveiv_entry)) ) + (MAC_IVEIV_TABLE_BASE + ((__idx) * sizeof(struct mac_iveiv_entry))) #define MAC_WCID_ATTR_ENTRY(__idx) \ - ( MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32)) ) + (MAC_WCID_ATTRIBUTE_BASE + ((__idx) * sizeof(u32))) #define SHARED_KEY_ENTRY(__idx) \ - ( SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry)) ) + (SHARED_KEY_TABLE_BASE + ((__idx) * sizeof(struct hw_key_entry))) #define SHARED_KEY_MODE_ENTRY(__idx) \ - ( SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32)) ) + (SHARED_KEY_MODE_BASE + ((__idx) * sizeof(u32))) struct mac_wcid_entry { u8 mac[6]; @@ -1658,9 +1658,9 @@ struct mac_iveiv_entry { #define HW_BEACON_BASE7 0x5bc0 #define HW_BEACON_OFFSET(__index) \ - ( ((__index) < 4) ? ( HW_BEACON_BASE0 + (__index * 0x0200) ) : \ - (((__index) < 6) ? ( HW_BEACON_BASE4 + ((__index - 4) * 0x0200) ) : \ - (HW_BEACON_BASE6 - ((__index - 6) * 0x0200))) ) + (((__index) < 4) ? (HW_BEACON_BASE0 + (__index * 0x0200)) : \ + (((__index) < 6) ? (HW_BEACON_BASE4 + ((__index - 4) * 0x0200)) : \ + (HW_BEACON_BASE6 - ((__index - 6) * 0x0200)))) /* * BBP registers. @@ -2010,8 +2010,8 @@ struct mac_iveiv_entry { /* * DMA descriptor defines. */ -#define TXWI_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXWI_DESC_SIZE ( 4 * sizeof(__le32) ) +#define TXWI_DESC_SIZE (4 * sizeof(__le32)) +#define RXWI_DESC_SIZE (4 * sizeof(__le32)) /* * TX WI structure -- cgit v1.2.3 From bf1b15125e2aa245ddd9348f80d041d4f1fd13a9 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:45:06 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2800lib.c rt2800lib.c:831: ERROR: inline keyword should sit between storage class and type Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index a53536dc882d..b5d2ebab6ea8 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -828,7 +828,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) } EXPORT_SYMBOL_GPL(rt2800_write_beacon); -static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, +static inline void rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev, unsigned int beacon_base) { int i; -- cgit v1.2.3 From c6cbadeb3afd9471e539791842877d085f367746 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:45:22 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2800pci.h rt2800pci.h:41: ERROR: Macros with complex values should be enclosed in parenthesis rt2800pci.h:42: ERROR: Macros with complex values should be enclosed in parenthesis rt2800pci.h:43: ERROR: Macros with complex values should be enclosed in parenthesis rt2800pci.h:44: ERROR: Macros with complex values should be enclosed in parenthesis rt2800pci.h:55: ERROR: space prohibited after that open parenthesis '(' rt2800pci.h:55: ERROR: space prohibited before that close parenthesis ')' rt2800pci.h:56: ERROR: space prohibited after that open parenthesis '(' rt2800pci.h:56: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800pci.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 5a8dda9b5b5a..70e050d904c8 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -38,10 +38,10 @@ * Queue register offset macros */ #define TX_QUEUE_REG_OFFSET 0x10 -#define TX_BASE_PTR(__x) TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_MAX_CNT(__x) TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_CTX_IDX(__x) TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) -#define TX_DTX_IDX(__x) TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET) +#define TX_BASE_PTR(__x) (TX_BASE_PTR0 + ((__x) * TX_QUEUE_REG_OFFSET)) +#define TX_MAX_CNT(__x) (TX_MAX_CNT0 + ((__x) * TX_QUEUE_REG_OFFSET)) +#define TX_CTX_IDX(__x) (TX_CTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)) +#define TX_DTX_IDX(__x) (TX_DTX_IDX0 + ((__x) * TX_QUEUE_REG_OFFSET)) /* * 8051 firmware image. @@ -52,8 +52,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 4 * sizeof(__le32) ) -#define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) +#define TXD_DESC_SIZE (4 * sizeof(__le32)) +#define RXD_DESC_SIZE (4 * sizeof(__le32)) /* * TX descriptor format for TX, PRIO and Beacon Ring. -- cgit v1.2.3 From 144b80bc05e76df0acb8b5e86a6e6aaf0c53325e Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:45:41 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2800usb.c rt2800usb.c:48: ERROR: do not initialise statics to 0 or NULL Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 5c31e3350aac..67a994247a30 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -45,7 +45,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt = 0; +static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -- cgit v1.2.3 From 87a46caf920515eb269df0109f0a61a958236568 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:45:58 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2800usb.h rt2800usb.h:43: ERROR: space prohibited after that open parenthesis '(' rt2800usb.h:43: ERROR: space prohibited before that close parenthesis ')' rt2800usb.h:44: ERROR: space prohibited after that open parenthesis '(' rt2800usb.h:44: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h index 0722badccf86..671ea3592610 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.h +++ b/drivers/net/wireless/rt2x00/rt2800usb.h @@ -40,8 +40,8 @@ /* * DMA descriptor defines. */ -#define TXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) -#define RXINFO_DESC_SIZE ( 1 * sizeof(__le32) ) +#define TXINFO_DESC_SIZE (1 * sizeof(__le32)) +#define RXINFO_DESC_SIZE (1 * sizeof(__le32)) /* * TX Info structure -- cgit v1.2.3 From 8a239033c355be998b8985f12f0cc3a9eaeb93e9 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:46:17 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2x00config.c rt2x00config.c:136: ERROR: space required before the open parenthesis '(' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 54ffb5aeb34e..fca8f22896a5 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -133,7 +133,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, */ if (!(ant->flags & ANTENNA_RX_DIVERSITY)) config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); - else if(config.rx == ANTENNA_SW_DIVERSITY) + else if (config.rx == ANTENNA_SW_DIVERSITY) config.rx = active->rx; if (!(ant->flags & ANTENNA_TX_DIVERSITY)) -- cgit v1.2.3 From c2361baec100c6f373107346e3fd98e9b267ac6c Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:46:36 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2x00dev.c rt2x00dev.c:689: ERROR: spaces required around that '=' (ctx:WxV) Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0f34d996975b..5793afef1c08 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -686,7 +686,7 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry, { entry->flags = 0; entry->bitrate = rate->bitrate; - entry->hw_value =index; + entry->hw_value = index; entry->hw_value_short = index; if (rate->flags & DEV_RATE_SHORT_PREAMBLE) -- cgit v1.2.3 From 5f181dc16bbd13b68b54ed5c43c4d2c5ad00297b Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:46:53 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2x00lib.h rt2x00lib.h:60: ERROR: space prohibited after that open parenthesis '(' rt2x00lib.h:60: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 619da23b7b56..983540200096 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -57,7 +57,7 @@ static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value) } #define RATE_MCS(__mode, __mcs) \ - ( (((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff) ) + ((((__mode) & 0x00ff) << 8) | ((__mcs) & 0x00ff)) static inline int rt2x00_get_rate_mcs(const u16 mcs_value) { -- cgit v1.2.3 From 027e8fd105c82956de9dec232bad21b1628ee7c0 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:47:09 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2x00link.c rt2x00link.c:70: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index b971d8798ebf..bfda60eaf4ef 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -67,7 +67,7 @@ (__avg).avg_weight ? \ ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \ ((__val) * (AVG_FACTOR))) / \ - (AVG_SAMPLES) ) : \ + (AVG_SAMPLES)) : \ ((__val) * (AVG_FACTOR)); \ __new.avg = __new.avg_weight / (AVG_FACTOR); \ __new; \ -- cgit v1.2.3 From f8bfbc31794635f6d0b7fd30950d49cecf54e1ce Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:47:25 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt2x00queue.c rt2x00queue.c:804: ERROR: space prohibited after that open parenthesis '(' rt2x00queue.c:805: ERROR: space prohibited before that close parenthesis ')' Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4e2a8c2e014d..32d6a17d5aa0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -801,8 +801,8 @@ static int rt2x00queue_alloc_entries(struct data_queue *queue, return -ENOMEM; #define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \ - ( ((char *)(__base)) + ((__limit) * (__esize)) + \ - ((__index) * (__psize)) ) + (((char *)(__base)) + ((__limit) * (__esize)) + \ + ((__index) * (__psize))) for (i = 0; i < queue->limit; i++) { entries[i].flags = 0; -- cgit v1.2.3 From 821cde63b5bd04bc3ca0f95e2abf17b04e640488 Mon Sep 17 00:00:00 2001 From: Mark Einon Date: Sat, 6 Nov 2010 15:47:46 +0100 Subject: rt2x00: checkpatch.pl error fixes for rt73usb.c rt73usb.c:43: ERROR: do not initialise statics to 0 or NULL Signed-off-by: Mark Einon Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt73usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index dcb9211c4771..29602b5f01f8 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -40,7 +40,7 @@ /* * Allow hardware encryption to be disabled. */ -static int modparam_nohwcrypt = 0; +static int modparam_nohwcrypt; module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -- cgit v1.2.3 From 813f0339dd739c48607f12dac79ec26c61874226 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Nov 2010 15:48:05 +0100 Subject: rt2x00: Rename queue->lock to queue->index_lock The queue->lock is only used to protect the index numbers. Rename the lock accordingly. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00debug.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00queue.c | 18 +++++++++--------- drivers/net/wireless/rt2x00/rt2x00queue.h | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 8296a9d47bbd..64dfb1f6823e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -342,7 +342,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdma done\tdone\n"); queue_for_each(intf->rt2x00dev, queue) { - spin_lock_irqsave(&queue->lock, irqflags); + spin_lock_irqsave(&queue->index_lock, irqflags); temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, queue->count, queue->limit, queue->length, @@ -350,7 +350,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, queue->index[Q_INDEX_DMA_DONE], queue->index[Q_INDEX_DONE]); - spin_unlock_irqrestore(&queue->lock, irqflags); + spin_unlock_irqrestore(&queue->index_lock, irqflags); } size = strlen(data); diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 32d6a17d5aa0..aa4c8f2dc7df 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -641,10 +641,10 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, * it should not be kicked during this run, since it * is part of another TX operation. */ - spin_lock_irqsave(&queue->lock, irqflags); + spin_lock_irqsave(&queue->index_lock, irqflags); index_start = queue->index[start]; index_end = queue->index[end]; - spin_unlock_irqrestore(&queue->lock, irqflags); + spin_unlock_irqrestore(&queue->index_lock, irqflags); /* * Start from the TX done pointer, this guarentees that we will @@ -698,11 +698,11 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, return NULL; } - spin_lock_irqsave(&queue->lock, irqflags); + spin_lock_irqsave(&queue->index_lock, irqflags); entry = &queue->entries[queue->index[index]]; - spin_unlock_irqrestore(&queue->lock, irqflags); + spin_unlock_irqrestore(&queue->index_lock, irqflags); return entry; } @@ -718,7 +718,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) return; } - spin_lock_irqsave(&queue->lock, irqflags); + spin_lock_irqsave(&queue->index_lock, irqflags); queue->index[index]++; if (queue->index[index] >= queue->limit) @@ -733,7 +733,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->count++; } - spin_unlock_irqrestore(&queue->lock, irqflags); + spin_unlock_irqrestore(&queue->index_lock, irqflags); } static void rt2x00queue_reset(struct data_queue *queue) @@ -741,7 +741,7 @@ static void rt2x00queue_reset(struct data_queue *queue) unsigned long irqflags; unsigned int i; - spin_lock_irqsave(&queue->lock, irqflags); + spin_lock_irqsave(&queue->index_lock, irqflags); queue->count = 0; queue->length = 0; @@ -751,7 +751,7 @@ static void rt2x00queue_reset(struct data_queue *queue) queue->last_action[i] = jiffies; } - spin_unlock_irqrestore(&queue->lock, irqflags); + spin_unlock_irqrestore(&queue->index_lock, irqflags); } void rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev) @@ -903,7 +903,7 @@ void rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev) static void rt2x00queue_init(struct rt2x00_dev *rt2x00dev, struct data_queue *queue, enum data_queue_qid qid) { - spin_lock_init(&queue->lock); + spin_lock_init(&queue->index_lock); queue->rt2x00dev = rt2x00dev; queue->qid = qid; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 64c00e2ab716..29b051ac6401 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -398,7 +398,7 @@ enum queue_index { * @entries: Base address of the &struct queue_entry which are * part of this queue. * @qid: The queue identification, see &enum data_queue_qid. - * @lock: Spinlock to protect index handling. Whenever @index, @index_done or + * @index_lock: Spinlock to protect index handling. Whenever @index, @index_done or * @index_crypt needs to be changed this lock should be grabbed to prevent * index corruption due to concurrency. * @count: Number of frames handled in the queue. @@ -422,7 +422,7 @@ struct data_queue { enum data_queue_qid qid; - spinlock_t lock; + spinlock_t index_lock; unsigned int count; unsigned short limit; unsigned short threshold; -- cgit v1.2.3 From 8be4eed0ea7d8ef38692de878043a949e9db16e8 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Nov 2010 15:48:23 +0100 Subject: rt2x00: Fix rt2x00queue_kick_tx_queue arguments The queue_entry argument to rt2x00queue_kick_tx_queue, doesn't make sense due to the function name (it is called kick QUEUE)... But neither do we need the queue_entry, since we need the data_queue. Signed-off-by: Ivo van Doorn Acked-by: Helmut Schaa Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00queue.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index aa4c8f2dc7df..dc543174dfad 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -452,12 +452,9 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry->skb); } -static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, +static void rt2x00queue_kick_tx_queue(struct data_queue *queue, struct txentry_desc *txdesc) { - struct data_queue *queue = entry->queue; - struct rt2x00_dev *rt2x00dev = queue->rt2x00dev; - /* * Check if we need to kick the queue, there are however a few rules * 1) Don't kick unless this is the last in frame in a burst. @@ -469,7 +466,7 @@ static void rt2x00queue_kick_tx_queue(struct queue_entry *entry, */ if (rt2x00queue_threshold(queue) || !test_bit(ENTRY_TXD_BURST, &txdesc->flags)) - rt2x00dev->ops->lib->kick_tx_queue(queue); + queue->rt2x00dev->ops->lib->kick_tx_queue(queue); } int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, @@ -559,7 +556,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, rt2x00queue_index_inc(queue, Q_INDEX); rt2x00queue_write_tx_descriptor(entry, &txdesc); - rt2x00queue_kick_tx_queue(entry, &txdesc); + rt2x00queue_kick_tx_queue(queue, &txdesc); return 0; } -- cgit v1.2.3 From ea175ee26268370ca07aff91cf6ba1e0f1a3bd36 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Nov 2010 15:48:43 +0100 Subject: rt2x00: Remove rt2x00lib_toggle_rx As part of the queue refactoring, the rt2x00lib_toggle_rx can be removed and replaced with the call directly to the set_device_state callback function. We can remove the STATE_RADIO_RX_ON_LINK and STATE_RADIO_RX_OFF_LINK, as it was only used for special behavior inside rt2x00lib rather then the drivers. Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2400pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2500pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2500usb.c | 5 +---- drivers/net/wireless/rt2x00/rt2800pci.c | 5 +---- drivers/net/wireless/rt2x00/rt2800usb.c | 5 +---- drivers/net/wireless/rt2x00/rt2x00config.c | 6 ++++-- drivers/net/wireless/rt2x00/rt2x00dev.c | 23 ++++------------------- drivers/net/wireless/rt2x00/rt2x00lib.h | 1 - drivers/net/wireless/rt2x00/rt2x00mac.c | 4 ++-- drivers/net/wireless/rt2x00/rt2x00reg.h | 2 -- drivers/net/wireless/rt2x00/rt61pci.c | 5 +---- drivers/net/wireless/rt2x00/rt73usb.c | 5 +---- 12 files changed, 17 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index bc1ae1ebfdb0..9ec6691adf0d 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -885,8 +885,7 @@ static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, - (state == STATE_RADIO_RX_OFF) || - (state == STATE_RADIO_RX_OFF_LINK)); + (state == STATE_RADIO_RX_OFF)); rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } @@ -989,9 +988,7 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2400pci_disable_radio(rt2x00dev); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt2400pci_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 54754150250b..3e7f20346243 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -1040,8 +1040,7 @@ static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, RXCSR0, ®); rt2x00_set_field32(®, RXCSR0_DISABLE_RX, - (state == STATE_RADIO_RX_OFF) || - (state == STATE_RADIO_RX_OFF_LINK)); + (state == STATE_RADIO_RX_OFF)); rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); } @@ -1144,9 +1143,7 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500pci_disable_radio(rt2x00dev); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt2500pci_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 10e51f208f07..8152fec31753 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -938,8 +938,7 @@ static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2500usb_register_read(rt2x00dev, TXRX_CSR2, ®); rt2x00_set_field16(®, TXRX_CSR2_DISABLE_RX, - (state == STATE_RADIO_RX_OFF) || - (state == STATE_RADIO_RX_OFF_LINK)); + (state == STATE_RADIO_RX_OFF)); rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg); } @@ -1019,9 +1018,7 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2500usb_disable_radio(rt2x00dev); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt2500usb_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 1db0c3bf2e1f..5f3a018c088d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -328,8 +328,7 @@ static void rt2800pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, - (state == STATE_RADIO_RX_ON) || - (state == STATE_RADIO_RX_ON_LINK)); + (state == STATE_RADIO_RX_ON)); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } @@ -477,9 +476,7 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800pci_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt2800pci_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 67a994247a30..f93337128504 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -114,8 +114,7 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, ®); rt2x00_set_field32(®, MAC_SYS_CTRL_ENABLE_RX, - (state == STATE_RADIO_RX_ON) || - (state == STATE_RADIO_RX_ON_LINK)); + (state == STATE_RADIO_RX_ON)); rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg); } @@ -216,9 +215,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt2800usb_set_state(rt2x00dev, STATE_SLEEP); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt2800usb_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index fca8f22896a5..a238e908c854 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -146,7 +146,8 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, * else the changes will be ignored by the device. */ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_RX_OFF); /* * Write new antenna setup to device and reset the link tuner. @@ -160,7 +161,8 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, memcpy(active, &config, sizeof(config)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, + STATE_RADIO_RX_ON); } void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 5793afef1c08..3afa2a3ebee4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -68,7 +68,8 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Enable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON); + rt2x00link_start_tuner(rt2x00dev); /* * Start watchdog monitoring. @@ -102,7 +103,8 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) /* * Disable RX. */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + rt2x00link_stop_tuner(rt2x00dev); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF); /* * Disable radio. @@ -113,23 +115,6 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) rt2x00leds_led_radio(rt2x00dev, false); } -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) -{ - /* - * When we are disabling the RX, we should also stop the link tuner. - */ - if (state == STATE_RADIO_RX_OFF) - rt2x00link_stop_tuner(rt2x00dev); - - rt2x00dev->ops->lib->set_device_state(rt2x00dev, state); - - /* - * When we are enabling the RX, we should also start the link tuner. - */ - if (state == STATE_RADIO_RX_ON) - rt2x00link_start_tuner(rt2x00dev); -} - static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 983540200096..2cf68f82674b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -69,7 +69,6 @@ static inline int rt2x00_get_rate_mcs(const u16 mcs_value) */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev); -void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state); /* * Initialization handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 36ddee8dc9e2..829bf4be9bc3 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -352,7 +352,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) * if for any reason the link tuner must be reset, this will be * handled by rt2x00lib_config(). */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_OFF); /* * When we've just turned on the radio, we want to reprogram @@ -370,7 +370,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); /* Turn RX back on */ - rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); + rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_RX_ON); return 0; } diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h index cef94621cef7..ed71be95136d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00reg.h +++ b/drivers/net/wireless/rt2x00/rt2x00reg.h @@ -85,8 +85,6 @@ enum dev_state { STATE_RADIO_OFF, STATE_RADIO_RX_ON, STATE_RADIO_RX_OFF, - STATE_RADIO_RX_ON_LINK, - STATE_RADIO_RX_OFF_LINK, STATE_RADIO_IRQ_ON, STATE_RADIO_IRQ_OFF, STATE_RADIO_IRQ_ON_ISR, diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index f01bff7656bc..6b09b01f634f 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1623,8 +1623,7 @@ static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, - (state == STATE_RADIO_RX_OFF) || - (state == STATE_RADIO_RX_OFF_LINK)); + (state == STATE_RADIO_RX_OFF)); rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); } @@ -1745,9 +1744,7 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, rt61pci_disable_radio(rt2x00dev); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt61pci_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 29602b5f01f8..6f04552f5819 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -1331,8 +1331,7 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, - (state == STATE_RADIO_RX_OFF) || - (state == STATE_RADIO_RX_OFF_LINK)); + (state == STATE_RADIO_RX_OFF)); rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } @@ -1403,9 +1402,7 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, rt73usb_disable_radio(rt2x00dev); break; case STATE_RADIO_RX_ON: - case STATE_RADIO_RX_ON_LINK: case STATE_RADIO_RX_OFF: - case STATE_RADIO_RX_OFF_LINK: rt73usb_toggle_rx(rt2x00dev, state); break; case STATE_RADIO_IRQ_ON: -- cgit v1.2.3 From 8c5765fda4b382acce4ff386e18ec11790dff893 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 6 Nov 2010 15:49:01 +0100 Subject: rt2x00: Add watchdog functions for HW queue Add watchdog functions for managing the Queues inside the hardware. Normally the driver doesn't have much to do with these queues directly, but the Ralink drivers did implement watchdog functions for these. These watchdog functions are not triggered that often, compared to the other watchdog functions, but I have at least seen them trigger once or twice during a long stresstest run. v2: Add extra documentation for register fields Signed-off-by: Ivo van Doorn Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800.h | 16 ++++++++++-- drivers/net/wireless/rt2x00/rt2800usb.c | 45 ++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index c2cc126502d6..002224c9bb62 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -412,10 +412,22 @@ #define BCN_OFFSET1_BCN7 FIELD32(0xff000000) /* - * PBF registers - * Most are for debug. Driver doesn't touch PBF register. + * TXRXQ_PCNT: PBF register + * PCNT_TX0Q: Page count for TX hardware queue 0 + * PCNT_TX1Q: Page count for TX hardware queue 1 + * PCNT_TX2Q: Page count for TX hardware queue 2 + * PCNT_RX0Q: Page count for RX hardware queue */ #define TXRXQ_PCNT 0x0438 +#define TXRXQ_PCNT_TX0Q FIELD32(0x000000ff) +#define TXRXQ_PCNT_TX1Q FIELD32(0x0000ff00) +#define TXRXQ_PCNT_TX2Q FIELD32(0x00ff0000) +#define TXRXQ_PCNT_RX0Q FIELD32(0xff000000) + +/* + * PBF register + * Debug. Driver doesn't touch PBF register. + */ #define PBF_DBG 0x043c /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f93337128504..389ecba8e891 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -242,6 +242,49 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev, return retval; } +/* + * Watchdog handlers + */ +static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev) +{ + unsigned int i; + u32 reg; + + rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) { + WARNING(rt2x00dev, "TX HW queue 0 timed out," + " invoke forced kick"); + + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012); + + for (i = 0; i < 10; i++) { + udelay(10); + if (!rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) + break; + } + + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + } + + rt2800_register_read(rt2x00dev, TXRXQ_PCNT, ®); + if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) { + WARNING(rt2x00dev, "TX HW queue 1 timed out," + " invoke forced kick"); + + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a); + + for (i = 0; i < 10; i++) { + udelay(10); + if (!rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) + break; + } + + rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006); + } + + rt2x00usb_watchdog(rt2x00dev); +} + /* * TX descriptor initialization */ @@ -534,7 +577,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .link_stats = rt2800_link_stats, .reset_tuner = rt2800_reset_tuner, .link_tuner = rt2800_link_tuner, - .watchdog = rt2x00usb_watchdog, + .watchdog = rt2800usb_watchdog, .write_tx_desc = rt2800usb_write_tx_desc, .write_tx_data = rt2800_write_tx_data, .write_beacon = rt2800_write_beacon, -- cgit v1.2.3 From 5d882c97e2c958df9f8b78832fa1ecbecef6ea1d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Mon, 8 Nov 2010 10:50:03 -0800 Subject: ath5k: Print stats as unsigned ints. The debugfs code for ath5k was printing some unsigned int stats with %d instead of %u. This meant that you could see negative numbers instead of a clean wrap. Signed-off-by: Ben Greear Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/debug.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index acda56ee521b..54dcf77e9646 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -554,63 +554,63 @@ static ssize_t read_file_frameerrors(struct file *file, char __user *user_buf, len += snprintf(buf+len, sizeof(buf)-len, "RX\n---------------------\n"); - len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "CRC\t%u\t(%u%%)\n", st->rxerr_crc, st->rx_all_count > 0 ? st->rxerr_crc*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "PHY\t%u\t(%u%%)\n", st->rxerr_phy, st->rx_all_count > 0 ? st->rxerr_phy*100/st->rx_all_count : 0); for (i = 0; i < 32; i++) { if (st->rxerr_phy_code[i]) len += snprintf(buf+len, sizeof(buf)-len, - " phy_err[%d]\t%d\n", + " phy_err[%u]\t%u\n", i, st->rxerr_phy_code[i]); } - len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n", st->rxerr_fifo, st->rx_all_count > 0 ? st->rxerr_fifo*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "decrypt\t%u\t(%u%%)\n", st->rxerr_decrypt, st->rx_all_count > 0 ? st->rxerr_decrypt*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "MIC\t%u\t(%u%%)\n", st->rxerr_mic, st->rx_all_count > 0 ? st->rxerr_mic*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "process\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "process\t%u\t(%u%%)\n", st->rxerr_proc, st->rx_all_count > 0 ? st->rxerr_proc*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "jumbo\t%u\t(%u%%)\n", st->rxerr_jumbo, st->rx_all_count > 0 ? st->rxerr_jumbo*100/st->rx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%d]\n", + len += snprintf(buf+len, sizeof(buf)-len, "[RX all\t%u]\n", st->rx_all_count); - len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%d\n", + len += snprintf(buf+len, sizeof(buf)-len, "RX-all-bytes\t%u\n", st->rx_bytes_count); len += snprintf(buf+len, sizeof(buf)-len, "\nTX\n---------------------\n"); - len += snprintf(buf+len, sizeof(buf)-len, "retry\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "retry\t%u\t(%u%%)\n", st->txerr_retry, st->tx_all_count > 0 ? st->txerr_retry*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "FIFO\t%u\t(%u%%)\n", st->txerr_fifo, st->tx_all_count > 0 ? st->txerr_fifo*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "filter\t%d\t(%d%%)\n", + len += snprintf(buf+len, sizeof(buf)-len, "filter\t%u\t(%u%%)\n", st->txerr_filt, st->tx_all_count > 0 ? st->txerr_filt*100/st->tx_all_count : 0); - len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%d]\n", + len += snprintf(buf+len, sizeof(buf)-len, "[TX all\t%u]\n", st->tx_all_count); - len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%d\n", + len += snprintf(buf+len, sizeof(buf)-len, "TX-all-bytes\t%u\n", st->tx_bytes_count); if (len > sizeof(buf)) -- cgit v1.2.3 From 8b37d9f0a1e114a1c7f5082842fb310a81ea3732 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:35 -0800 Subject: iwlagn: update PCI ID for 6000g2b series devices Update the supported PCI ID list for 6000g2b series devices Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 481c993c2491..073e106e58e7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4449,24 +4449,12 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)}, /* 6x00 Series Gen2b */ - {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)}, - {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)}, {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)}, {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)}, {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)}, - {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5327, iwl6000g2b_bg_cfg)}, {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)}, + {IWL_PCI_DEVICE(0x008B, 0x5317, iwl6000g2b_bg_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)}, -- cgit v1.2.3 From fb30eaf38703d7562606e49a5872745d66366a50 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:36 -0800 Subject: iwlagn: update PCI ID for 6000g2a series devices Update the supported PCI ID list for 6000g2a series devices Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 073e106e58e7..cc2683ad7297 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4433,13 +4433,6 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x4239, 0x1316, iwl6000i_2abg_cfg)}, /* 6x00 Series Gen2a */ - {IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)}, - {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)}, {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)}, -- cgit v1.2.3 From 2a21ff446c07b95d08cbb830bd20112f3ee1d76e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:37 -0800 Subject: iwlagn: update PCI ID for 100 series devices Update the supported PCI ID list for 100 series devices Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cc2683ad7297..f7feac22a47c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -4491,10 +4491,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { /* 100 Series WiFi */ {IWL_PCI_DEVICE(0x08AE, 0x1005, iwl100_bgn_cfg)}, + {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)}, {IWL_PCI_DEVICE(0x08AF, 0x1015, iwl100_bgn_cfg)}, + {IWL_PCI_DEVICE(0x08AF, 0x1017, iwl100_bg_cfg)}, {IWL_PCI_DEVICE(0x08AE, 0x1025, iwl100_bgn_cfg)}, - {IWL_PCI_DEVICE(0x08AE, 0x1007, iwl100_bg_cfg)}, - {IWL_PCI_DEVICE(0x08AE, 0x1017, iwl100_bg_cfg)}, + {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl100_bg_cfg)}, /* 130 Series WiFi */ {IWL_PCI_DEVICE(0x0896, 0x5005, iwl130_bgn_cfg)}, -- cgit v1.2.3 From ae79d23d0b2c16998e60f49a16dae53521c76a45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 09:56:38 -0800 Subject: iwlagn: fix non-5000+ build When building 4965 without 5000+ there were a lot of build errors due to functions being used that weren't even compiled in. To fix this move some code around and only compile the HCMD code for 5000+ series as it's not used for 4965. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 4 ++-- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 16 -------------- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 16 ++++++++++++++ drivers/net/wireless/iwlwifi/iwl-agn-sta.c | 32 ++++++++++++++++++++++++++- drivers/net/wireless/iwlwifi/iwl-agn.c | 34 ++++------------------------- drivers/net/wireless/iwlwifi/iwl-agn.h | 5 ++++- 6 files changed, 57 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index ce05c260870e..b85a9c8ed01e 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -12,13 +12,13 @@ CFLAGS_iwl-devtrace.o := -I$(src) # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o -iwlagn-objs += iwl-agn-ucode.o iwl-agn-hcmd.o iwl-agn-tx.o +iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o -iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o +iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3427fc2b7d68..019d4e7d7348 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -1587,22 +1587,6 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) return ret; } -void iwlagn_post_scan(struct iwl_priv *priv) -{ - struct iwl_rxon_context *ctx; - - /* - * Since setting the RXON may have been deferred while - * performing the scan, fire one off if needed - */ - for_each_context(priv, ctx) - if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) - iwlagn_commit_rxon(priv, ctx); - - if (priv->cfg->ops->hcmd->set_pan_params) - priv->cfg->ops->hcmd->set_pan_params(priv); -} - int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 11b3d8888360..f0ddfb1a9c87 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -585,3 +585,19 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } + +void iwlagn_post_scan(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + + /* + * Since setting the RXON may have been deferred while + * performing the scan, fire one off if needed + */ + for_each_context(priv, ctx) + if (memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) + iwlagn_commit_rxon(priv, ctx); + + if (priv->cfg->ops->hcmd->set_pan_params) + priv->cfg->ops->hcmd->set_pan_params(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 35a30d2e0734..35f085ac336b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -684,7 +684,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); } -void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; @@ -714,3 +714,33 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) spin_unlock_irqrestore(&priv->sta_lock, flags); } + +void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int sta_id; + + switch (cmd) { + case STA_NOTIFY_SLEEP: + WARN_ON(!sta_priv->client); + sta_priv->asleep = true; + if (atomic_read(&sta_priv->pending_frames) > 0) + ieee80211_sta_block_awake(hw, sta, true); + break; + case STA_NOTIFY_AWAKE: + WARN_ON(!sta_priv->client); + if (!sta_priv->asleep) + break; + sta_priv->asleep = false; + sta_id = iwl_sta_id(sta); + if (sta_id != IWL_INVALID_STATION) + iwl_sta_modify_ps_wake(priv, sta_id); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f7feac22a47c..573017474610 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3474,36 +3474,6 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, return ret; } -static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - int sta_id; - - switch (cmd) { - case STA_NOTIFY_SLEEP: - WARN_ON(!sta_priv->client); - sta_priv->asleep = true; - if (atomic_read(&sta_priv->pending_frames) > 0) - ieee80211_sta_block_awake(hw, sta, true); - break; - case STA_NOTIFY_AWAKE: - WARN_ON(!sta_priv->client); - if (!sta_priv->asleep) - break; - sta_priv->asleep = false; - sta_id = iwl_sta_id(sta); - if (sta_id != IWL_INVALID_STATION) - iwl_sta_modify_ps_wake(priv, sta_id); - break; - default: - break; - } -} - int iwlagn_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -3903,6 +3873,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv) kfree(priv->scan_cmd); } +#ifdef CONFIG_IWL5000 struct ieee80211_ops iwlagn_hw_ops = { .tx = iwlagn_mac_tx, .start = iwlagn_mac_start, @@ -3925,6 +3896,7 @@ struct ieee80211_ops iwlagn_hw_ops = { .flush = iwlagn_mac_flush, .tx_last_beacon = iwl_mac_tx_last_beacon, }; +#endif static void iwl_hw_detect(struct iwl_priv *priv) { @@ -3992,7 +3964,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (cfg->mod_params->disable_hw_scan) { dev_printk(KERN_DEBUG, &(pdev->dev), "sw scan support is deprecated\n"); +#ifdef CONFIG_IWL5000 iwlagn_hw_ops.hw_scan = NULL; +#endif #ifdef CONFIG_IWL4965 iwl4965_hw_ops.hw_scan = NULL; #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index aca93f4477a8..28837a185a28 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -301,9 +301,12 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, int tid, u16 ssn); int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, int tid); -void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id); void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt); int iwl_update_bcast_stations(struct iwl_priv *priv); +void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, + struct ieee80211_sta *sta); /* rate */ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) -- cgit v1.2.3 From 81baf6ec9c190ae128748cf2a026bff5cb811b70 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:39 -0800 Subject: iwlwifi: Legacy isr only used by legacy devices Move iwl_isr_legacy function to iwl_legacy.c since it only used by legacy devices. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 1 + drivers/net/wireless/iwlwifi/iwl-core.c | 60 ------------------------------ drivers/net/wireless/iwlwifi/iwl-core.h | 1 - drivers/net/wireless/iwlwifi/iwl-legacy.c | 62 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-legacy.h | 2 + 5 files changed, 65 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d9e676480269..a97c09992a73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -51,6 +51,7 @@ #include "iwl-led.h" #include "iwl-3945-led.h" #include "iwl-3945-debugfs.h" +#include "iwl-legacy.h" #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 180d09ec3136..f8d801cc24fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1227,66 +1227,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) } EXPORT_SYMBOL(iwl_set_tx_power); -irqreturn_t iwl_isr_legacy(int irq, void *data) -{ - struct iwl_priv *priv = data; - u32 inta, inta_mask; - u32 inta_fh; - unsigned long flags; - if (!priv) - return IRQ_NONE; - - spin_lock_irqsave(&priv->lock, flags); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the tasklet will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* Discover which interrupts are active/pending */ - inta = iwl_read32(priv, CSR_INT); - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!inta && !inta_fh) { - IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n"); - goto none; - } - - if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { - /* Hardware disappeared. It might have already raised - * an interrupt */ - IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); - goto unplugged; - } - - IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, inta_fh); - - inta &= ~CSR_INT_BIT_SCD; - - /* iwl_irq_tasklet() will service interrupts and re-enable them */ - if (likely(inta || inta_fh)) - tasklet_schedule(&priv->irq_tasklet); - - unplugged: - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; - - none: - /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_NONE; -} -EXPORT_SYMBOL(iwl_isr_legacy); - void iwl_send_bt_config(struct iwl_priv *priv) { struct iwl_bt_cmd bt_cmd = { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 8fb063affac4..7505c16db2a2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -596,7 +596,6 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); /***************************************************** * PCI * *****************************************************/ -irqreturn_t iwl_isr_legacy(int irq, void *data); static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) { diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c index b735fef9ee4b..f49e500cba67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -31,6 +31,7 @@ #include "iwl-dev.h" #include "iwl-core.h" +#include "iwl-helpers.h" #include "iwl-legacy.h" /** @@ -558,3 +559,64 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); } EXPORT_SYMBOL(iwl_legacy_mac_bss_info_changed); + +irqreturn_t iwl_isr_legacy(int irq, void *data) +{ + struct iwl_priv *priv = data; + u32 inta, inta_mask; + u32 inta_fh; + unsigned long flags; + if (!priv) + return IRQ_NONE; + + spin_lock_irqsave(&priv->lock, flags); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(priv, CSR_INT); + inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta && !inta_fh) { + IWL_DEBUG_ISR(priv, + "Ignore interrupt, inta == 0, inta_fh == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared. It might have already raised + * an interrupt */ + IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); + goto unplugged; + } + + IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", + inta, inta_mask, inta_fh); + + inta &= ~CSR_INT_BIT_SCD; + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta || inta_fh)) + tasklet_schedule(&priv->irq_tasklet); + +unplugged: + spin_unlock_irqrestore(&priv->lock, flags); + return IRQ_HANDLED; + +none: + /* re-enable interrupts here since we don't have anything to service. */ + /* only Re-enable if diabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &priv->status)) + iwl_enable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + return IRQ_NONE; +} +EXPORT_SYMBOL(iwl_isr_legacy); diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.h b/drivers/net/wireless/iwlwifi/iwl-legacy.h index 2a746cbc30fe..81d1ccdb0746 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.h +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.h @@ -71,4 +71,6 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changes); +irqreturn_t iwl_isr_legacy(int irq, void *data); + #endif /* __iwl_legacy_h__ */ -- cgit v1.2.3 From e39fdee1d7856817619326fa114438c146d74510 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:40 -0800 Subject: iwlwifi: put all the isr related function under ops There were two type of isr supported by iwlwifi devices. legacy isr - only used by legacy devices (3945 & 4965) ict isr - used by all new generation of iwlwifi devices Move all the isr related functions into ops, the ict type of isr supports only needed for newer devices. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/Makefile | 4 ++-- drivers/net/wireless/iwlwifi/iwl-1000.c | 8 +++++++- drivers/net/wireless/iwlwifi/iwl-3945.c | 4 +++- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +++- drivers/net/wireless/iwlwifi/iwl-5000.c | 16 ++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-6000.c | 16 ++++++++++++++-- drivers/net/wireless/iwlwifi/iwl-agn.c | 18 ++++++++++++------ drivers/net/wireless/iwlwifi/iwl-core.h | 12 +++++++++++- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- 9 files changed, 67 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index b85a9c8ed01e..01aa2468bd69 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -11,14 +11,14 @@ CFLAGS_iwl-devtrace.o := -I$(src) # AGN obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwl-agn-ict.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o iwlagn-objs += iwl-agn-lib.o iwl-agn-rx.o iwl-agn-calib.o iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o -iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o +iwlagn-$(CONFIG_IWL5000) += iwl-agn-rxon.o iwl-agn-hcmd.o iwl-agn-ict.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o iwlagn-$(CONFIG_IWL5000) += iwl-6000.o iwlagn-$(CONFIG_IWL5000) += iwl-1000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index baedea8e4d04..068f1e1e3297 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -211,7 +211,13 @@ static struct iwl_lib_ops iwl1000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr = iwl_isr_ict, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, .temp_ops = { .temperature = iwlagn_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index a97c09992a73..1ab171949021 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2727,7 +2727,9 @@ static struct iwl_lib_ops iwl3945_lib = { }, .send_tx_power = iwl3945_send_tx_power, .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, - .isr = iwl_isr_legacy, + .isr_ops = { + .isr = iwl_isr_legacy, + }, .recover_from_tx_stall = iwl_bg_monitor_recover, .check_plcp_health = iwl3945_good_plcp_health, diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 6d313c817040..a6518caa405c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2561,7 +2561,9 @@ static struct iwl_lib_ops iwl4965_lib = { }, .send_tx_power = iwl4965_send_tx_power, .update_chain_flags = iwl_update_chain_flags, - .isr = iwl_isr_legacy, + .isr_ops = { + .isr = iwl_isr_legacy, + }, .temp_ops = { .temperature = iwl4965_temperature_calib, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e1f412f915ae..ad43f0fdf919 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -385,7 +385,13 @@ static struct iwl_lib_ops iwl5000_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr = iwl_isr_ict, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -449,7 +455,13 @@ static struct iwl_lib_ops iwl5150_lib = { .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, - .isr = iwl_isr_ict, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, .temp_ops = { .temperature = iwl5150_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index b1816900980c..21ac2817722e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -322,7 +322,13 @@ static struct iwl_lib_ops iwl6000_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr = iwl_isr_ict, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, .temp_ops = { .temperature = iwlagn_temperature, }, @@ -389,7 +395,13 @@ static struct iwl_lib_ops iwl6000g2b_lib = { .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, - .isr = iwl_isr_ict, + .isr_ops = { + .isr = iwl_isr_ict, + .free = iwl_free_isr_ict, + .alloc = iwl_alloc_isr_ict, + .reset = iwl_reset_ict, + .disable = iwl_disable_ict, + }, .temp_ops = { .temperature = iwlagn_temperature, }, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 573017474610..007fb20d78ab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2815,7 +2815,8 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_EXIT_PENDING; /* device going down, Stop using ICT table */ - iwl_disable_ict(priv); + if (priv->cfg->ops->lib->isr_ops.disable) + priv->cfg->ops->lib->isr_ops.disable(priv); iwlagn_txq_ctx_stop(priv); iwlagn_rxq_stop(priv); @@ -3038,7 +3039,8 @@ static void iwl_bg_alive_start(struct work_struct *data) return; /* enable dram interrupt */ - iwl_reset_ict(priv); + if (priv->cfg->ops->lib->isr_ops.reset) + priv->cfg->ops->lib->isr_ops.reset(priv); mutex_lock(&priv->mutex); iwl_alive_start(priv); @@ -4172,8 +4174,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_enable_msi(priv->pci_dev); - iwl_alloc_isr_ict(priv); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + if (priv->cfg->ops->lib->isr_ops.alloc) + priv->cfg->ops->lib->isr_ops.alloc(priv); + + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -4220,7 +4224,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) destroy_workqueue(priv->workqueue); priv->workqueue = NULL; free_irq(priv->pci_dev->irq, priv); - iwl_free_isr_ict(priv); + if (priv->cfg->ops->lib->isr_ops.free) + priv->cfg->ops->lib->isr_ops.free(priv); out_disable_msi: pci_disable_msi(priv->pci_dev); iwl_uninit_drv(priv); @@ -4315,7 +4320,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) iwl_uninit_drv(priv); - iwl_free_isr_ict(priv); + if (priv->cfg->ops->lib->isr_ops.free) + priv->cfg->ops->lib->isr_ops.free(priv); dev_kfree_skb(priv->beacon_skb); diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7505c16db2a2..c9723da040fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -120,6 +120,14 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; +struct iwl_isr_ops { + irqreturn_t (*isr) (int irq, void *data); + void (*free)(struct iwl_priv *priv); + int (*alloc)(struct iwl_priv *priv); + int (*reset)(struct iwl_priv *priv); + void (*disable)(struct iwl_priv *priv); +}; + struct iwl_debugfs_ops { ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, size_t count, loff_t *ppos); @@ -193,7 +201,9 @@ struct iwl_lib_ops { /* power */ int (*send_tx_power) (struct iwl_priv *priv); void (*update_chain_flags)(struct iwl_priv *priv); - irqreturn_t (*isr) (int irq, void *data); + + /* isr */ + struct iwl_isr_ops isr_ops; /* eeprom operations (as defined in iwl-eeprom.h) */ struct iwl_eeprom_ops eeprom_ops; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 6152a86c19b5..a55b4623e1c8 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -4120,7 +4120,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_enable_msi(priv->pci_dev); - err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr, + err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr, IRQF_SHARED, DRV_NAME, priv); if (err) { IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); -- cgit v1.2.3 From 708068db4c09f93937a6a83ac8fff8516f482b0f Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:41 -0800 Subject: iwlwifi: legacy tx_cmd_protection function Legacy (4965 and 3945) devices has different tx_cmd_protection routine. Move to iwl-legacy.c Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 34 ------------------------------- drivers/net/wireless/iwlwifi/iwl-core.h | 4 +--- drivers/net/wireless/iwlwifi/iwl-legacy.c | 34 +++++++++++++++++++++++++++++++ drivers/net/wireless/iwlwifi/iwl-legacy.h | 3 +++ 6 files changed, 40 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 1ab171949021..ebac04b7887c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -2749,7 +2749,7 @@ static const struct iwl_legacy_ops iwl3945_legacy_ops = { static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { .get_hcmd_size = iwl3945_get_hcmd_size, .build_addsta_hcmd = iwl3945_build_addsta_hcmd, - .tx_cmd_protection = iwlcore_tx_cmd_protection, + .tx_cmd_protection = iwl_legacy_tx_cmd_protection, .request_scan = iwl3945_request_scan, .post_scan = iwl3945_post_scan, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index a6518caa405c..cd14843878ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -2514,7 +2514,7 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { .build_addsta_hcmd = iwl4965_build_addsta_hcmd, .chain_noise_reset = iwl4965_chain_noise_reset, .gain_computation = iwl4965_gain_computation, - .tx_cmd_protection = iwlcore_tx_cmd_protection, + .tx_cmd_protection = iwl_legacy_tx_cmd_protection, .calc_rssi = iwl4965_calc_rssi, .request_scan = iwlagn_request_scan, .post_scan = iwl4965_post_scan, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index f8d801cc24fc..c884ed385fcf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -288,40 +288,6 @@ void iwlcore_free_geos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwlcore_free_geos); -/* - * iwlcore_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this - * function. - */ -void iwlcore_tx_cmd_protection(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - __le16 fc, __le32 *tx_flags) -{ - if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - *tx_flags |= TX_CMD_FLG_RTS_MSK; - *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - - if (!ieee80211_is_mgmt(fc)) - return; - - switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { - case cpu_to_le16(IEEE80211_STYPE_AUTH): - case cpu_to_le16(IEEE80211_STYPE_DEAUTH): - case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): - case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - break; - } - } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - *tx_flags &= ~TX_CMD_FLG_RTS_MSK; - *tx_flags |= TX_CMD_FLG_CTS_MSK; - *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; - } -} -EXPORT_SYMBOL(iwlcore_tx_cmd_protection); - - static bool iwl_is_channel_extension(struct iwl_priv *priv, enum ieee80211_band band, u16 channel, u8 extension_chan_offset) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index c9723da040fc..6064bc412e07 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -447,9 +447,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, enum nl80211_iftype newtype, bool newp2p); int iwl_alloc_txq_mem(struct iwl_priv *priv); void iwl_free_txq_mem(struct iwl_priv *priv); -void iwlcore_tx_cmd_protection(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - __le16 fc, __le32 *tx_flags); + #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c index f49e500cba67..10d9c4202875 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -620,3 +620,37 @@ none: return IRQ_NONE; } EXPORT_SYMBOL(iwl_isr_legacy); + +/* + * iwl_legacy_tx_cmd_protection: Set rts/cts. 3945 and 4965 only share this + * function. + */ +void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv, + struct ieee80211_tx_info *info, + __le16 fc, __le32 *tx_flags) +{ + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { + *tx_flags |= TX_CMD_FLG_RTS_MSK; + *tx_flags &= ~TX_CMD_FLG_CTS_MSK; + *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + + if (!ieee80211_is_mgmt(fc)) + return; + + switch (fc & cpu_to_le16(IEEE80211_FCTL_STYPE)) { + case cpu_to_le16(IEEE80211_STYPE_AUTH): + case cpu_to_le16(IEEE80211_STYPE_DEAUTH): + case cpu_to_le16(IEEE80211_STYPE_ASSOC_REQ): + case cpu_to_le16(IEEE80211_STYPE_REASSOC_REQ): + *tx_flags &= ~TX_CMD_FLG_RTS_MSK; + *tx_flags |= TX_CMD_FLG_CTS_MSK; + break; + } + } else if (info->control.rates[0].flags & + IEEE80211_TX_RC_USE_CTS_PROTECT) { + *tx_flags &= ~TX_CMD_FLG_RTS_MSK; + *tx_flags |= TX_CMD_FLG_CTS_MSK; + *tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK; + } +} +EXPORT_SYMBOL(iwl_legacy_tx_cmd_protection); diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.h b/drivers/net/wireless/iwlwifi/iwl-legacy.h index 81d1ccdb0746..9f7b2f935964 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.h +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.h @@ -70,6 +70,9 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +void iwl_legacy_tx_cmd_protection(struct iwl_priv *priv, + struct ieee80211_tx_info *info, + __le16 fc, __le32 *tx_flags); irqreturn_t iwl_isr_legacy(int irq, void *data); -- cgit v1.2.3 From fd11743dd25efe7157ff17b03dd2db0cbb6fed05 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Wed, 10 Nov 2010 09:56:42 -0800 Subject: iwlwlifi: update rx write pointer w/o request mac access in the CAM mode In iwl_rx_queue_update_write_ptr function replace iwl_write_direct32 with iwl_write32 when not in power save mode. We don't have to go through grab nic access as the NIC is already awake. Signed-off-by: Tomas Winkler Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index f436270ca39a..baca4cc0073b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -153,7 +153,7 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q } else { /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); + iwl_write32(priv, rx_wrt_ptr_reg, q->write_actual); } q->need_update = 0; -- cgit v1.2.3 From 35a6eb36520b938742d8680fd8d821df20982ced Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:43 -0800 Subject: iwlwifi: resending QoS command when HT changes "mac80211: Fix WMM driver queue configuration" inadvertedly broke iwlwifi, because now mac80211 configures the QoS settings before assoc, and therefore before HT. Thus, iwlwifi no longer told the device about the HT setting, which it needs to -- and thus throughput went down a lot. Fix this by resending the QoS command to the device not only when QoS/WMM settings change, but also when HT changes. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 65 ++++++++++++++++------------- drivers/net/wireless/iwlwifi/iwl-legacy.c | 60 ++++++++++++++------------ 2 files changed, 69 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index f0ddfb1a9c87..02288779a71f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -269,6 +269,34 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } +static void iwlagn_update_qos(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + + if (!ctx->is_active) + return; + + ctx->qos_data.def_qos_parm.qos_flags = 0; + + if (ctx->qos_data.qos_active) + ctx->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (ctx->ht.enabled) + ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + ctx->qos_data.qos_active, + ctx->qos_data.def_qos_parm.qos_flags); + + ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, + sizeof(struct iwl_qosparam_cmd), + &ctx->qos_data.def_qos_parm); + if (ret) + IWL_ERR(priv, "Failed to update QoS\n"); +} + int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; @@ -277,6 +305,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; + bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -324,7 +353,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled != conf_is_ht(conf)) { + ctx->ht.enabled = conf_is_ht(conf); + ht_changed[ctx->ctxid] = true; + } + if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { ctx->ht.extension_chan_offset = @@ -392,40 +425,14 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); + if (ht_changed[ctx->ctxid]) + iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); return ret; } -static void iwlagn_update_qos(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret; - - if (!ctx->is_active) - return; - - ctx->qos_data.def_qos_parm.qos_flags = 0; - - if (ctx->qos_data.qos_active) - ctx->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (ctx->ht.enabled) - ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", - ctx->qos_data.qos_active, - ctx->qos_data.def_qos_parm.qos_flags); - - ret = iwl_send_cmd_pdu(priv, ctx->qos_cmd, - sizeof(struct iwl_qosparam_cmd), - &ctx->qos_data.def_qos_parm); - if (ret) - IWL_ERR(priv, "Failed to update QoS\n"); -} - static void iwlagn_check_needed_chains(struct iwl_priv *priv, struct iwl_rxon_context *ctx, struct ieee80211_bss_conf *bss_conf) diff --git a/drivers/net/wireless/iwlwifi/iwl-legacy.c b/drivers/net/wireless/iwlwifi/iwl-legacy.c index 10d9c4202875..a08b4e56e6b1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-legacy.c +++ b/drivers/net/wireless/iwlwifi/iwl-legacy.c @@ -34,6 +34,32 @@ #include "iwl-helpers.h" #include "iwl-legacy.h" +static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + return; + + if (!ctx->is_active) + return; + + ctx->qos_data.def_qos_parm.qos_flags = 0; + + if (ctx->qos_data.qos_active) + ctx->qos_data.def_qos_parm.qos_flags |= + QOS_PARAM_FLG_UPDATE_EDCA_MSK; + + if (ctx->ht.enabled) + ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; + + IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", + ctx->qos_data.qos_active, + ctx->qos_data.def_qos_parm.qos_flags); + + iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, + sizeof(struct iwl_qosparam_cmd), + &ctx->qos_data.def_qos_parm, NULL); +} + /** * iwl_legacy_mac_config - mac80211 config callback */ @@ -49,6 +75,7 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) int ret = 0; u16 ch; int scan_active = 0; + bool ht_changed[NUM_IWL_RXON_CTX] = {}; if (WARN_ON(!priv->cfg->ops->legacy)) return -EOPNOTSUPP; @@ -100,7 +127,10 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - ctx->ht.enabled = conf_is_ht(conf); + if (ctx->ht.enabled != conf_is_ht(conf)) { + ctx->ht.enabled = conf_is_ht(conf); + ht_changed[ctx->ctxid] = true; + } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { ctx->ht.extension_chan_offset = @@ -177,6 +207,8 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) else IWL_DEBUG_INFO(priv, "Not re-sending same RXON configuration.\n"); + if (ht_changed[ctx->ctxid]) + iwl_update_qos(priv, ctx); } out: @@ -295,32 +327,6 @@ static void iwl_ht_conf(struct iwl_priv *priv, IWL_DEBUG_ASSOC(priv, "leave\n"); } -static void iwl_update_qos(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - if (!ctx->is_active) - return; - - ctx->qos_data.def_qos_parm.qos_flags = 0; - - if (ctx->qos_data.qos_active) - ctx->qos_data.def_qos_parm.qos_flags |= - QOS_PARAM_FLG_UPDATE_EDCA_MSK; - - if (ctx->ht.enabled) - ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; - - IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n", - ctx->qos_data.qos_active, - ctx->qos_data.def_qos_parm.qos_flags); - - iwl_send_cmd_pdu_async(priv, ctx->qos_cmd, - sizeof(struct iwl_qosparam_cmd), - &ctx->qos_data.def_qos_parm, NULL); -} - static inline void iwl_set_no_assoc(struct iwl_priv *priv, struct ieee80211_vif *vif) { -- cgit v1.2.3 From 2e1fea43aa170e18beb8378465e595e18cd08f6e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 09:56:44 -0800 Subject: iwlagn: fix needed chains calculation Garen noticed that this was wrong. Fix the calibration -- default to multiple chains and fall back to single where possible. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 02288779a71f..1fab1bb5f2b4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -458,11 +458,13 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT; maxstreams += 1; + need_multiple = true; + if ((ht_cap->mcs.rx_mask[1] == 0) && (ht_cap->mcs.rx_mask[2] == 0)) need_multiple = false; if (maxstreams <= 1) - need_multiple = true; + need_multiple = false; } else { /* * If at all, this can only happen through a race -- cgit v1.2.3 From 52d980c01353202332ff4322f3f41db0c49816a5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 09:56:45 -0800 Subject: iwlagn: fix RXON issues The RXON rework resulted in a massive loss of throughput because we weren't programming the device completely correctly -- the BSSID has to be programmed into the device before the AP station is uploaded. To fix this, simply always send the unassoc RXON, i.e. even when it was already unassoc so that the BSSID and some other parameters are updated properly. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 50 ++++++++++++----------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 1fab1bb5f2b4..d594a1658a9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -96,7 +96,6 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active = (void *)&ctx->active; - bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK); bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); int ret; @@ -172,37 +171,30 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) ctx->staging.bssid_addr); /* - * If we are currently associated and the new config is also - * going to be associated, OR if the new config is simply not - * associated, clear associated. + * Always clear associated first, but with the correct config. + * This is required as for example station addition for the + * AP station must be done after the BSSID is set to correctly + * set up filters in the device. */ - if ((old_assoc && new_assoc) || !new_assoc) { - struct iwl_rxon_cmd *send = active; - - if (!new_assoc) - send = &ctx->staging; - - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, send); - else - ret = iwlagn_disable_pan(priv, ctx, send); - if (ret) - return ret; + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; - if (send != active) - memcpy(active, send, sizeof(*active)); + memcpy(active, &ctx->staging, sizeof(*active)); - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; } /* RXON timing must be before associated RXON */ -- cgit v1.2.3 From 8da8e62851680772f0422d0f1c4b467190b268e5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 09:56:46 -0800 Subject: iwlagn: re-enable calibration During the RXON rewrite, this code got lost. When we've just associated, we need to enable all calibrations and see if some were already finished. Add back the missing code. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index d594a1658a9e..d9d617fd5078 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -569,6 +569,20 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (force || memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) iwlagn_commit_rxon(priv, ctx); + if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) { + /* + * The chain noise calibration will enable PM upon + * completion. If calibration has already been run + * then we need to enable power management here. + */ + if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE) + iwl_power_update_mode(priv, false); + + /* Enable RX differential gain and sensitivity calibrations */ + iwl_chain_noise_reset(priv); + priv->start_calib = 1; + } + if (changes & BSS_CHANGED_IBSS) { ret = iwlagn_manage_ibss_station(priv, vif, bss_conf->ibss_joined); -- cgit v1.2.3 From b2769b84d86a2d29fa131a763d2b23b112834420 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Nov 2010 09:56:47 -0800 Subject: iwlagn: fix RXON HT When the HT information is changed due to BSS changes (like legacy stations joining) we need to recalculate HT RXON parameters. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index d9d617fd5078..2d927a94074d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -538,6 +538,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, ctx->ht.non_gf_sta_present = !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); iwlagn_check_needed_chains(priv, ctx, bss_conf); + iwl_set_rxon_ht(priv, &priv->current_ht_config); } if (priv->cfg->ops->hcmd->set_rxon_chain) -- cgit v1.2.3 From 3031242b31dcd76e1c6b1c1718cfee872f55d5af Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Wed, 10 Nov 2010 09:56:48 -0800 Subject: iwlwifi: seperate disconnected antenna function Disconnected antenna algorithm is seperated into its own function from chain noise calibration routine for better code management. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-calib.c | 231 ++++++++++++++------------- 1 file changed, 123 insertions(+), 108 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index e2019e756936..b4cfc3c16285 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -732,8 +732,128 @@ static inline u8 find_first_chain(u8 mask) return CHAIN_C; } +/** + * Run disconnected antenna algorithm to find out which antennas are + * disconnected. + */ +static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, + struct iwl_chain_noise_data *data) +{ + u32 active_chains = 0; + u32 max_average_sig; + u16 max_average_sig_antenna_i; + u8 num_tx_chains; + u8 first_chain; + u16 i = 0; + + average_sig[0] = data->chain_signal_a / + priv->cfg->base_params->chain_noise_num_beacons; + average_sig[1] = data->chain_signal_b / + priv->cfg->base_params->chain_noise_num_beacons; + average_sig[2] = data->chain_signal_c / + priv->cfg->base_params->chain_noise_num_beacons; + + if (average_sig[0] >= average_sig[1]) { + max_average_sig = average_sig[0]; + max_average_sig_antenna_i = 0; + active_chains = (1 << max_average_sig_antenna_i); + } else { + max_average_sig = average_sig[1]; + max_average_sig_antenna_i = 1; + active_chains = (1 << max_average_sig_antenna_i); + } + + if (average_sig[2] >= max_average_sig) { + max_average_sig = average_sig[2]; + max_average_sig_antenna_i = 2; + active_chains = (1 << max_average_sig_antenna_i); + } + + IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n", + average_sig[0], average_sig[1], average_sig[2]); + IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n", + max_average_sig, max_average_sig_antenna_i); + + /* Compare signal strengths for all 3 receivers. */ + for (i = 0; i < NUM_RX_CHAINS; i++) { + if (i != max_average_sig_antenna_i) { + s32 rssi_delta = (max_average_sig - average_sig[i]); + + /* If signal is very weak, compared with + * strongest, mark it as disconnected. */ + if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) + data->disconn_array[i] = 1; + else + active_chains |= (1 << i); + IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d " + "disconn_array[i] = %d\n", + i, rssi_delta, data->disconn_array[i]); + } + } + + /* + * The above algorithm sometimes fails when the ucode + * reports 0 for all chains. It's not clear why that + * happens to start with, but it is then causing trouble + * because this can make us enable more chains than the + * hardware really has. + * + * To be safe, simply mask out any chains that we know + * are not on the device. + */ + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { + /* operated as 1x1 in full concurrency mode */ + active_chains &= first_antenna(priv->hw_params.valid_rx_ant); + } else + active_chains &= priv->hw_params.valid_rx_ant; + + num_tx_chains = 0; + for (i = 0; i < NUM_RX_CHAINS; i++) { + /* loops on all the bits of + * priv->hw_setting.valid_tx_ant */ + u8 ant_msk = (1 << i); + if (!(priv->hw_params.valid_tx_ant & ant_msk)) + continue; + + num_tx_chains++; + if (data->disconn_array[i] == 0) + /* there is a Tx antenna connected */ + break; + if (num_tx_chains == priv->hw_params.tx_chains_num && + data->disconn_array[i]) { + /* + * If all chains are disconnected + * connect the first valid tx chain + */ + first_chain = + find_first_chain(priv->cfg->valid_tx_ant); + data->disconn_array[first_chain] = 0; + active_chains |= BIT(first_chain); + IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected \ + W/A - declare %d as connected\n", + first_chain); + break; + } + } + + if (active_chains != priv->hw_params.valid_rx_ant && + active_chains != priv->chain_noise_data.active_chains) + IWL_DEBUG_CALIB(priv, + "Detected that not all antennas are connected! " + "Connected: %#x, valid: %#x.\n", + active_chains, priv->hw_params.valid_rx_ant); + + /* Save for use within RXON, TX, SCAN commands, etc. */ + data->active_chains = active_chains; + IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n", + active_chains); +} + + /* - * Accumulate 20 beacons of signal and noise statistics for each of + * Accumulate 16 beacons of signal and noise statistics for each of * 3 receivers/antennas/rx-chains, then figure out: * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. @@ -750,8 +870,6 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) u32 chain_sig_c; u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE}; - u32 max_average_sig; - u16 max_average_sig_antenna_i; u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE; u16 min_average_noise_antenna_i = INITIALIZATION_VALUE; u16 i = 0; @@ -759,11 +877,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) u16 stat_chnum = INITIALIZATION_VALUE; u8 rxon_band24; u8 stat_band24; - u32 active_chains = 0; - u8 num_tx_chains; unsigned long flags; struct statistics_rx_non_phy *rx_info; - u8 first_chain; + /* * MULTI-FIXME: * When we support multiple interfaces on different channels, @@ -869,108 +985,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) return; /* Analyze signal for disconnected antenna */ - average_sig[0] = data->chain_signal_a / - priv->cfg->base_params->chain_noise_num_beacons; - average_sig[1] = data->chain_signal_b / - priv->cfg->base_params->chain_noise_num_beacons; - average_sig[2] = data->chain_signal_c / - priv->cfg->base_params->chain_noise_num_beacons; - - if (average_sig[0] >= average_sig[1]) { - max_average_sig = average_sig[0]; - max_average_sig_antenna_i = 0; - active_chains = (1 << max_average_sig_antenna_i); - } else { - max_average_sig = average_sig[1]; - max_average_sig_antenna_i = 1; - active_chains = (1 << max_average_sig_antenna_i); - } - - if (average_sig[2] >= max_average_sig) { - max_average_sig = average_sig[2]; - max_average_sig_antenna_i = 2; - active_chains = (1 << max_average_sig_antenna_i); - } - - IWL_DEBUG_CALIB(priv, "average_sig: a %d b %d c %d\n", - average_sig[0], average_sig[1], average_sig[2]); - IWL_DEBUG_CALIB(priv, "max_average_sig = %d, antenna %d\n", - max_average_sig, max_average_sig_antenna_i); - - /* Compare signal strengths for all 3 receivers. */ - for (i = 0; i < NUM_RX_CHAINS; i++) { - if (i != max_average_sig_antenna_i) { - s32 rssi_delta = (max_average_sig - average_sig[i]); - - /* If signal is very weak, compared with - * strongest, mark it as disconnected. */ - if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS) - data->disconn_array[i] = 1; - else - active_chains |= (1 << i); - IWL_DEBUG_CALIB(priv, "i = %d rssiDelta = %d " - "disconn_array[i] = %d\n", - i, rssi_delta, data->disconn_array[i]); - } - } - - /* - * The above algorithm sometimes fails when the ucode - * reports 0 for all chains. It's not clear why that - * happens to start with, but it is then causing trouble - * because this can make us enable more chains than the - * hardware really has. - * - * To be safe, simply mask out any chains that we know - * are not on the device. - */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - priv->bt_full_concurrent) { - /* operated as 1x1 in full concurrency mode */ - active_chains &= first_antenna(priv->hw_params.valid_rx_ant); - } else - active_chains &= priv->hw_params.valid_rx_ant; - - num_tx_chains = 0; - for (i = 0; i < NUM_RX_CHAINS; i++) { - /* loops on all the bits of - * priv->hw_setting.valid_tx_ant */ - u8 ant_msk = (1 << i); - if (!(priv->hw_params.valid_tx_ant & ant_msk)) - continue; - - num_tx_chains++; - if (data->disconn_array[i] == 0) - /* there is a Tx antenna connected */ - break; - if (num_tx_chains == priv->hw_params.tx_chains_num && - data->disconn_array[i]) { - /* - * If all chains are disconnected - * connect the first valid tx chain - */ - first_chain = - find_first_chain(priv->cfg->valid_tx_ant); - data->disconn_array[first_chain] = 0; - active_chains |= BIT(first_chain); - IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected W/A - declare %d as connected\n", - first_chain); - break; - } - } - - if (active_chains != priv->hw_params.valid_rx_ant && - active_chains != priv->chain_noise_data.active_chains) - IWL_DEBUG_CALIB(priv, - "Detected that not all antennas are connected! " - "Connected: %#x, valid: %#x.\n", - active_chains, priv->hw_params.valid_rx_ant); - - /* Save for use within RXON, TX, SCAN commands, etc. */ - priv->chain_noise_data.active_chains = active_chains; - IWL_DEBUG_CALIB(priv, "active_chains (bitwise) = 0x%x\n", - active_chains); + iwl_find_disconn_antenna(priv, average_sig, data); /* Analyze noise for rx balance */ average_noise[0] = data->chain_noise_a / -- cgit v1.2.3 From 6fe8efb2211fe61caa7b0e1c36c521670b8a10a9 Mon Sep 17 00:00:00 2001 From: Shanyu Zhao Date: Wed, 10 Nov 2010 09:56:49 -0800 Subject: iwlwifi: disable disconnected antenna for advanced bt coex Disconnected antenna algorithm is used to find out which antennas are disconnected. It should be disabled for devices that support advanced bluetooth coexist. Signed-off-by: Shanyu Zhao Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-calib.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index b4cfc3c16285..d16bb5ede014 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -801,13 +801,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * To be safe, simply mask out any chains that we know * are not on the device. */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - priv->bt_full_concurrent) { - /* operated as 1x1 in full concurrency mode */ - active_chains &= first_antenna(priv->hw_params.valid_rx_ant); - } else - active_chains &= priv->hw_params.valid_rx_ant; + active_chains &= priv->hw_params.valid_rx_ant; num_tx_chains = 0; for (i = 0; i < NUM_RX_CHAINS; i++) { @@ -985,7 +979,16 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp) return; /* Analyze signal for disconnected antenna */ - iwl_find_disconn_antenna(priv, average_sig, data); + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + /* Disable disconnected antenna algorithm for advanced + bt coex, assuming valid antennas are connected */ + data->active_chains = priv->hw_params.valid_rx_ant; + for (i = 0; i < NUM_RX_CHAINS; i++) + if (!(data->active_chains & (1<disconn_array[i] = 1; + } else + iwl_find_disconn_antenna(priv, average_sig, data); /* Analyze noise for rx balance */ average_noise[0] = data->chain_noise_a / -- cgit v1.2.3 From f81c1f48384d398dbe8f6c5b10377c7158086791 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 10 Nov 2010 09:56:50 -0800 Subject: iwlagn: enable shadow register For 6000 series devices and up, enable automatic update MAC's register for better power usage in PSP mode Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-6000.c | 3 ++ drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 6 ++++ drivers/net/wireless/iwlwifi/iwl-core.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-csr.h | 2 ++ drivers/net/wireless/iwlwifi/iwl-rx.c | 45 +++++++++++++++----------- drivers/net/wireless/iwlwifi/iwl-tx.c | 51 ++++++++++++++++++------------ 6 files changed, 70 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 21ac2817722e..c7ff1bdf42cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -487,6 +487,7 @@ static struct iwl_base_params iwl6000_base_params = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, }; static struct iwl_base_params iwl6050_base_params = { @@ -510,6 +511,7 @@ static struct iwl_base_params iwl6050_base_params = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, }; static struct iwl_base_params iwl6000_coex_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE, @@ -532,6 +534,7 @@ static struct iwl_base_params iwl6000_coex_base_params = { .ucode_tracing = true, .sensitivity_calib_by_driver = true, .chain_noise_calib_by_driver = true, + .shadow_reg_enable = true, }; static struct iwl_ht_params iwl6000_ht_params = { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 019d4e7d7348..ca3530c4295a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -753,6 +753,12 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv) } else iwlagn_txq_ctx_reset(priv); + if (priv->cfg->base_params->shadow_reg_enable) { + /* enable shadow regs in HW */ + iwl_set_bit(priv, CSR_MAC_SHADOW_REG_CTRL, + 0x800FFFFF); + } + set_bit(STATUS_INIT, &priv->status); return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 6064bc412e07..ee8cf240d65d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -290,6 +290,7 @@ struct iwl_mod_params { * sensitivity calibration operation * @chain_noise_calib_by_driver: driver has the capability to perform * chain noise calibration operation + * @shadow_reg_enable: HW shadhow register bit */ struct iwl_base_params { int eeprom_size; @@ -320,6 +321,7 @@ struct iwl_base_params { const bool ucode_tracing; const bool sensitivity_calib_by_driver; const bool chain_noise_calib_by_driver; + const bool shadow_reg_enable; }; /* * @advanced_bt_coexist: support advanced bt coexist diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 2aa15ab13892..b80bf7dff55b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -132,6 +132,8 @@ #define CSR_LED_REG (CSR_BASE+0x094) #define CSR_DRAM_INT_TBL_REG (CSR_BASE+0x0A0) +#define CSR_MAC_SHADOW_REG_CTRL (CSR_BASE+0x0A8) /* 6000 and up */ + /* GIO Chicken Bits (PCI Express bus link power management) */ #define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index baca4cc0073b..87a6fd84d4d2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -134,28 +134,37 @@ void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q if (q->need_update == 0) goto exit_unlock; - /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, "Rx queue requesting wakeup, GP1 = 0x%x\n", - reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; - } - - q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual); - - /* Else device is assumed to be awake */ - } else { + if (priv->cfg->base_params->shadow_reg_enable) { + /* shadow register enabled */ /* Device expects a multiple of 8 */ q->write_actual = (q->write & ~0x7); iwl_write32(priv, rx_wrt_ptr_reg, q->write_actual); - } + } else { + /* If power-saving is in use, make sure device is awake */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(priv, + "Rx queue requesting wakeup," + " GP1 = 0x%x\n", reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, + q->write_actual); + + /* Else device is assumed to be awake */ + } else { + /* Device expects a multiple of 8 */ + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(priv, rx_wrt_ptr_reg, + q->write_actual); + } + } q->need_update = 0; exit_unlock: diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 7261ee49f282..feaa3670c6bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -49,30 +49,39 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) if (txq->need_update == 0) return; - /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - /* wake up nic if it's powered down ... - * uCode will wake up, and interrupt us again, so next - * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", - txq_id, reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - return; - } - - iwl_write_direct32(priv, HBUS_TARG_WRPTR, - txq->q.write_ptr | (txq_id << 8)); - - /* else not in power-save mode, uCode will never sleep when we're - * trying to tx (during RFKILL, we're not trying to tx). */ - } else + if (priv->cfg->base_params->shadow_reg_enable) { + /* shadow register enabled */ iwl_write32(priv, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); + } else { + /* if we're trying to save power */ + if (test_bit(STATUS_POWER_PMI, &priv->status)) { + /* wake up nic if it's powered down ... + * uCode will wake up, and interrupt us again, so next + * time we'll skip this part. */ + reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(priv, + "Tx queue %d requesting wakeup," + " GP1 = 0x%x\n", txq_id, reg); + iwl_set_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + return; + } + + iwl_write_direct32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + /* + * else not in power-save mode, + * uCode will never sleep when we're + * trying to tx (during RFKILL, we're not trying to tx). + */ + } else + iwl_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + } txq->need_update = 0; } EXPORT_SYMBOL(iwl_txq_update_write_ptr); -- cgit v1.2.3 From cb7bbc7a5535ab2333915b83391e1d846a0914df Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 4 Nov 2010 00:13:47 +0200 Subject: wl1251: add power callback to wl1251_if_operations Call interface specific power callback before calling board specific one. Also allow that callback to fail. This is how it's done for wl1271 and will be used for runtime_pm support. Signed-off-by: Grazvydas Ignotas Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl1251/main.c | 15 +++++++++------ drivers/net/wireless/wl1251/sdio.c | 8 ++++++-- drivers/net/wireless/wl1251/spi.c | 9 +++++++++ drivers/net/wireless/wl1251/wl1251.h | 1 + 4 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index 7a8762553cdc..012e1a4016fe 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -52,14 +52,14 @@ void wl1251_disable_interrupts(struct wl1251 *wl) wl->if_ops->disable_irq(wl); } -static void wl1251_power_off(struct wl1251 *wl) +static int wl1251_power_off(struct wl1251 *wl) { - wl->set_power(false); + return wl->if_ops->power(wl, false); } -static void wl1251_power_on(struct wl1251 *wl) +static int wl1251_power_on(struct wl1251 *wl) { - wl->set_power(true); + return wl->if_ops->power(wl, true); } static int wl1251_fetch_firmware(struct wl1251 *wl) @@ -152,9 +152,12 @@ static void wl1251_fw_wakeup(struct wl1251 *wl) static int wl1251_chip_wakeup(struct wl1251 *wl) { - int ret = 0; + int ret; + + ret = wl1251_power_on(wl); + if (ret < 0) + return ret; - wl1251_power_on(wl); msleep(WL1251_POWER_ON_SLEEP); wl->if_ops->reset(wl); diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index 74ba9ced5393..02851901677e 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -171,8 +171,12 @@ static void wl1251_disable_line_irq(struct wl1251 *wl) return disable_irq(wl->irq); } -static void wl1251_sdio_set_power(bool enable) +static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) { + if (wl->set_power) + wl->set_power(enable); + + return 0; } static struct wl1251_if_operations wl1251_sdio_ops = { @@ -181,6 +185,7 @@ static struct wl1251_if_operations wl1251_sdio_ops = { .write_elp = wl1251_sdio_write_elp, .read_elp = wl1251_sdio_read_elp, .reset = wl1251_sdio_reset, + .power = wl1251_sdio_set_power, }; static int wl1251_platform_probe(struct platform_device *pdev) @@ -239,7 +244,6 @@ static int wl1251_sdio_probe(struct sdio_func *func, wl_sdio->func = func; wl->if_priv = wl_sdio; wl->if_ops = &wl1251_sdio_ops; - wl->set_power = wl1251_sdio_set_power; if (wl12xx_board_data != NULL) { wl->set_power = wl12xx_board_data->set_power; diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index 88fa8e69d0d1..ac872b38960f 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -215,12 +215,21 @@ static void wl1251_spi_disable_irq(struct wl1251 *wl) return disable_irq(wl->irq); } +static int wl1251_spi_set_power(struct wl1251 *wl, bool enable) +{ + if (wl->set_power) + wl->set_power(enable); + + return 0; +} + static const struct wl1251_if_operations wl1251_spi_ops = { .read = wl1251_spi_read, .write = wl1251_spi_write, .reset = wl1251_spi_reset_wake, .enable_irq = wl1251_spi_enable_irq, .disable_irq = wl1251_spi_disable_irq, + .power = wl1251_spi_set_power, }; static int __devinit wl1251_spi_probe(struct spi_device *spi) diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h index e113d4c1fb35..13fbeeccf609 100644 --- a/drivers/net/wireless/wl1251/wl1251.h +++ b/drivers/net/wireless/wl1251/wl1251.h @@ -256,6 +256,7 @@ struct wl1251_if_operations { void (*write)(struct wl1251 *wl, int addr, void *buf, size_t len); void (*read_elp)(struct wl1251 *wl, int addr, u32 *val); void (*write_elp)(struct wl1251 *wl, int addr, u32 val); + int (*power)(struct wl1251 *wl, bool enable); void (*reset)(struct wl1251 *wl); void (*enable_irq)(struct wl1251 *wl); void (*disable_irq)(struct wl1251 *wl); -- cgit v1.2.3 From 1d4b89f2970f9ea0902d0a3bc1090f3c770b5080 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Mon, 8 Nov 2010 15:29:36 +0200 Subject: wl1251: add runtime PM support for SDIO Add runtime PM support, similar to how it's done for wl1271. This allows to power down the card when the driver is loaded but network is not in use. Cc: Ohad Ben-Cohen Signed-off-by: Grazvydas Ignotas Acked-by: Kalle Valo Signed-off-by: John W. Linville --- drivers/net/wireless/wl1251/sdio.c | 64 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index 02851901677e..f3e185efe124 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "wl1251.h" @@ -173,10 +174,40 @@ static void wl1251_disable_line_irq(struct wl1251 *wl) static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable) { - if (wl->set_power) - wl->set_power(enable); + struct sdio_func *func = wl_to_func(wl); + int ret; - return 0; + if (enable) { + /* + * Power is controlled by runtime PM, but we still call board + * callback in case it wants to do any additional setup, + * for example enabling clock buffer for the module. + */ + if (wl->set_power) + wl->set_power(true); + + ret = pm_runtime_get_sync(&func->dev); + if (ret < 0) + goto out; + + sdio_claim_host(func); + sdio_enable_func(func); + sdio_release_host(func); + } else { + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + ret = pm_runtime_put_sync(&func->dev); + if (ret < 0) + goto out; + + if (wl->set_power) + wl->set_power(false); + } + +out: + return ret; } static struct wl1251_if_operations wl1251_sdio_ops = { @@ -277,6 +308,10 @@ static int wl1251_sdio_probe(struct sdio_func *func, goto out_free_irq; sdio_set_drvdata(func, wl); + + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + return ret; out_free_irq: @@ -298,6 +333,9 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func) struct wl1251 *wl = sdio_get_drvdata(func); struct wl1251_sdio *wl_sdio = wl->if_priv; + /* Undo decrement done above in wl1251_probe */ + pm_runtime_get_noresume(&func->dev); + if (wl->irq) free_irq(wl->irq, wl); kfree(wl_sdio); @@ -309,11 +347,31 @@ static void __devexit wl1251_sdio_remove(struct sdio_func *func) sdio_release_host(func); } +static int wl1251_suspend(struct device *dev) +{ + /* + * Tell MMC/SDIO core it's OK to power down the card + * (if it isn't already), but not to remove it completely. + */ + return 0; +} + +static int wl1251_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops wl1251_sdio_pm_ops = { + .suspend = wl1251_suspend, + .resume = wl1251_resume, +}; + static struct sdio_driver wl1251_sdio_driver = { .name = "wl1251_sdio", .id_table = wl1251_devices, .probe = wl1251_sdio_probe, .remove = __devexit_p(wl1251_sdio_remove), + .drv.pm = &wl1251_sdio_pm_ops, }; static int __init wl1251_sdio_init(void) -- cgit v1.2.3 From e4b3fdb80021bc0a3239bfc2a873a6d7c6ac52a1 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Thu, 4 Nov 2010 00:13:49 +0200 Subject: wl1251: use wl12xx_platform_data to pass data Make use the newly added method to pass platform data for wl1251 too. This allows to eliminate some redundant code. Cc: Ohad Ben-Cohen Signed-off-by: Grazvydas Ignotas Acked-by: Kalle Valo Acked-by: Luciano Coelho Acked-by: Tony Lindgren Signed-off-by: John W. Linville --- arch/arm/mach-omap2/board-omap3pandora.c | 32 ++++++++--------------------- drivers/net/wireless/wl1251/sdio.c | 35 ++------------------------------ drivers/net/wireless/wl12xx/Kconfig | 2 +- 3 files changed, 12 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c index 89ed1be2d62e..8be261506056 100644 --- a/arch/arm/mach-omap2/board-omap3pandora.c +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -642,31 +642,13 @@ static void __init omap3pandora_init_irq(void) omap_gpio_init(); } -static void pandora_wl1251_set_power(bool enable) -{ - /* - * Keep power always on until wl1251_sdio driver learns to re-init - * the chip after powering it down and back up. - */ -} - -static struct wl12xx_platform_data pandora_wl1251_pdata = { - .set_power = pandora_wl1251_set_power, - .use_eeprom = true, -}; - -static struct platform_device pandora_wl1251_data = { - .name = "wl1251_data", - .id = -1, - .dev = { - .platform_data = &pandora_wl1251_pdata, - }, -}; - -static void pandora_wl1251_init(void) +static void __init pandora_wl1251_init(void) { + struct wl12xx_platform_data pandora_wl1251_pdata; int ret; + memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); + ret = gpio_request(PANDORA_WIFI_IRQ_GPIO, "wl1251 irq"); if (ret < 0) goto fail; @@ -679,6 +661,11 @@ static void pandora_wl1251_init(void) if (pandora_wl1251_pdata.irq < 0) goto fail_irq; + pandora_wl1251_pdata.use_eeprom = true; + ret = wl12xx_set_platform_data(&pandora_wl1251_pdata); + if (ret < 0) + goto fail_irq; + return; fail_irq: @@ -691,7 +678,6 @@ static struct platform_device *omap3pandora_devices[] __initdata = { &pandora_leds_gpio, &pandora_keys_gpio, &pandora_dss_device, - &pandora_wl1251_data, &pandora_vwlan_device, }; diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index f3e185efe124..596d90ecba33 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -43,8 +43,6 @@ struct wl1251_sdio { u32 elp_val; }; -static struct wl12xx_platform_data *wl12xx_board_data; - static struct sdio_func *wl_to_func(struct wl1251 *wl) { struct wl1251_sdio *wl_sdio = wl->if_priv; @@ -219,30 +217,6 @@ static struct wl1251_if_operations wl1251_sdio_ops = { .power = wl1251_sdio_set_power, }; -static int wl1251_platform_probe(struct platform_device *pdev) -{ - if (pdev->id != -1) { - wl1251_error("can only handle single device"); - return -ENODEV; - } - - wl12xx_board_data = pdev->dev.platform_data; - return 0; -} - -/* - * Dummy platform_driver for passing platform_data to this driver, - * until we have a way to pass this through SDIO subsystem or - * some other way. - */ -static struct platform_driver wl1251_platform_driver = { - .driver = { - .name = "wl1251_data", - .owner = THIS_MODULE, - }, - .probe = wl1251_platform_probe, -}; - static int wl1251_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -250,6 +224,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, struct wl1251 *wl; struct ieee80211_hw *hw; struct wl1251_sdio *wl_sdio; + const struct wl12xx_platform_data *wl12xx_board_data; hw = wl1251_alloc_hw(); if (IS_ERR(hw)) @@ -276,6 +251,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, wl->if_priv = wl_sdio; wl->if_ops = &wl1251_sdio_ops; + wl12xx_board_data = wl12xx_get_platform_data(); if (wl12xx_board_data != NULL) { wl->set_power = wl12xx_board_data->set_power; wl->irq = wl12xx_board_data->irq; @@ -378,12 +354,6 @@ static int __init wl1251_sdio_init(void) { int err; - err = platform_driver_register(&wl1251_platform_driver); - if (err) { - wl1251_error("failed to register platform driver: %d", err); - return err; - } - err = sdio_register_driver(&wl1251_sdio_driver); if (err) wl1251_error("failed to register sdio driver: %d", err); @@ -393,7 +363,6 @@ static int __init wl1251_sdio_init(void) static void __exit wl1251_sdio_exit(void) { sdio_unregister_driver(&wl1251_sdio_driver); - platform_driver_unregister(&wl1251_platform_driver); wl1251_notice("unloaded"); } diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 1b3b7bdd6a19..02ad4bc15976 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -52,5 +52,5 @@ config WL1271_SDIO config WL12XX_PLATFORM_DATA bool - depends on WL1271_SDIO != n + depends on WL1271_SDIO != n || WL1251_SDIO != n default y -- cgit v1.2.3 From 7919a57bc608140aa8614c19eac40c6916fb61d2 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Mon, 30 Aug 2010 19:04:01 +0000 Subject: bitops: Provide generic sign_extend32 function This patch moves code out from wireless drivers where two different functions are defined in three code locations for the same purpose and provides a common function to sign extend a 32-bit value. Signed-off-by: Andreas Herrmann Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/phy.c | 8 +------- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 12 ++++++------ drivers/net/wireless/ath/ath9k/ar9002_phy.c | 8 ++++---- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 12 ++++++------ drivers/net/wireless/ath/ath9k/hw.h | 6 ------ drivers/net/wireless/iwlwifi/iwl-4965.c | 20 ++------------------ include/linux/bitops.h | 11 +++++++++++ 7 files changed, 30 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 219367884e64..6b43f535ff53 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -1102,18 +1102,12 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) PHY calibration \*****************/ -static int sign_extend(int val, const int nbits) -{ - int order = BIT(nbits-1); - return (val ^ order) - order; -} - static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah) { s32 val; val = ath5k_hw_reg_read(ah, AR5K_PHY_NF); - return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9); + return sign_extend32(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 8); } void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 777a602176f2..c83a22cfbe1e 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1490,25 +1490,25 @@ static void ar5008_hw_do_getnf(struct ath_hw *ah, int16_t nf; nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - nfarray[0] = sign_extend(nf, 9); + nfarray[0] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR_PHY_CH1_MINCCA_PWR); - nfarray[1] = sign_extend(nf, 9); + nfarray[1] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), AR_PHY_CH2_MINCCA_PWR); - nfarray[2] = sign_extend(nf, 9); + nfarray[2] = sign_extend32(nf, 8); if (!IS_CHAN_HT40(ah->curchan)) return; nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); - nfarray[3] = sign_extend(nf, 9); + nfarray[3] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR_PHY_CH1_EXT_MINCCA_PWR); - nfarray[4] = sign_extend(nf, 9); + nfarray[4] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), AR_PHY_CH2_EXT_MINCCA_PWR); - nfarray[5] = sign_extend(nf, 9); + nfarray[5] = sign_extend32(nf, 8); } /* diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index c00cdc67b55b..3fb97fdc1240 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -473,21 +473,21 @@ static void ar9002_hw_do_getnf(struct ath_hw *ah, int16_t nf; nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - nfarray[0] = sign_extend(nf, 9); + nfarray[0] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR9280_PHY_EXT_MINCCA_PWR); if (IS_CHAN_HT40(ah->curchan)) - nfarray[3] = sign_extend(nf, 9); + nfarray[3] = sign_extend32(nf, 8); if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) return; nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR); - nfarray[1] = sign_extend(nf, 9); + nfarray[1] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), AR9280_PHY_CH1_EXT_MINCCA_PWR); if (IS_CHAN_HT40(ah->curchan)) - nfarray[4] = sign_extend(nf, 9); + nfarray[4] = sign_extend32(nf, 8); } static void ar9002_hw_set_nf_limits(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 06a9c4cd2f44..44c5454b2ad8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1023,25 +1023,25 @@ static void ar9003_hw_do_getnf(struct ath_hw *ah, int16_t nf; nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR); - nfarray[0] = sign_extend(nf, 9); + nfarray[0] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR); - nfarray[1] = sign_extend(nf, 9); + nfarray[1] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR); - nfarray[2] = sign_extend(nf, 9); + nfarray[2] = sign_extend32(nf, 8); if (!IS_CHAN_HT40(ah->curchan)) return; nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR); - nfarray[3] = sign_extend(nf, 9); + nfarray[3] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR); - nfarray[4] = sign_extend(nf, 9); + nfarray[4] = sign_extend32(nf, 8); nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR); - nfarray[5] = sign_extend(nf, 9); + nfarray[5] = sign_extend32(nf, 8); } static void ar9003_hw_set_nf_limits(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index e5b72262fd96..f821a28bcda3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -825,12 +825,6 @@ static inline struct ath_hw_ops *ath9k_hw_ops(struct ath_hw *ah) return &ah->ops; } -static inline int sign_extend(int val, const int nbits) -{ - int order = BIT(nbits-1); - return (val ^ order) - order; -} - /* Initialization, Detach, Reset */ const char *ath9k_hw_probe(u16 vendorid, u16 devid); void ath9k_hw_deinit(struct ath_hw *ah); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index cd14843878ae..4748d067eb1d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -1686,22 +1686,6 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } -/** - * sign_extend - Sign extend a value using specified bit as sign-bit - * - * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1 - * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7. - * - * @param oper value to sign extend - * @param index 0 based bit index (0<=index<32) to sign bit - */ -static s32 sign_extend(u32 oper, int index) -{ - u8 shift = 31 - index; - - return (s32)(oper << shift) >> shift; -} - /** * iwl4965_hw_get_temperature - return the calibrated temperature (in Kelvin) * @statistics: Provides the temperature reading from the uCode @@ -1739,9 +1723,9 @@ static int iwl4965_hw_get_temperature(struct iwl_priv *priv) * "initialize" ALIVE response. */ if (!test_bit(STATUS_TEMPERATURE, &priv->status)) - vt = sign_extend(R4, 23); + vt = sign_extend32(R4, 23); else - vt = sign_extend(le32_to_cpu(priv->_agn.statistics. + vt = sign_extend32(le32_to_cpu(priv->_agn.statistics. general.common.temperature), 23); IWL_DEBUG_TEMP(priv, "Calib values R[1-3]: %d %d %d R4: %d\n", R1, R2, R3, vt); diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 827cc95711ef..2184c6b97aeb 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -109,6 +109,17 @@ static inline __u8 ror8(__u8 word, unsigned int shift) return (word >> shift) | (word << (8 - shift)); } +/** + * sign_extend32 - sign extend a 32-bit value using specified bit as sign-bit + * @value: value to sign extend + * @index: 0 based bit index (0<=index<32) to sign bit + */ +static inline __s32 sign_extend32(__u32 value, int index) +{ + __u8 shift = 31 - index; + return (__s32)(value << shift) >> shift; +} + static inline unsigned fls_long(unsigned long l) { if (sizeof(l) == 4) -- cgit v1.2.3 From b1d771ee33c6e4006676002b9d74abf45b71d3d6 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 29 Oct 2010 23:11:23 +0200 Subject: carl9170: use generic sign_extend32 This patch replaces the handcrafted sign extension cruft with a generic bitop function. Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/phy.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index 89deca37a988..82bc81c4c930 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -1554,15 +1554,6 @@ static int carl9170_set_power_cal(struct ar9170 *ar, u32 freq, return carl9170_regwrite_result(); } -/* TODO: replace this with sign_extend32(noise, 8) */ -static int carl9170_calc_noise_dbm(u32 raw_noise) -{ - if (raw_noise & 0x100) - return ~0x1ff | raw_noise; - else - return raw_noise; -} - int carl9170_get_noisefloor(struct ar9170 *ar) { static const u32 phy_regs[] = { @@ -1578,11 +1569,11 @@ int carl9170_get_noisefloor(struct ar9170 *ar) return err; for (i = 0; i < 2; i++) { - ar->noise[i] = carl9170_calc_noise_dbm( - (phy_res[i] >> 19) & 0x1ff); + ar->noise[i] = sign_extend32(GET_VAL( + AR9170_PHY_CCA_MIN_PWR, phy_res[i]), 8); - ar->noise[i + 2] = carl9170_calc_noise_dbm( - (phy_res[i + 2] >> 23) & 0x1ff); + ar->noise[i + 2] = sign_extend32(GET_VAL( + AR9170_PHY_EXT_CCA_MIN_PWR, phy_res[i + 2]), 8); } return 0; -- cgit v1.2.3 From ad65ffd12dccf6d1031298eacc060327751084da Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 17:04:26 +0000 Subject: drivers/isdn: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/isdn/hardware/mISDN/mISDNinfineon.c | 4 ++-- drivers/isdn/hardware/mISDN/mISDNisar.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c index e90db8870b6c..bc0529ac88a1 100644 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -420,7 +420,7 @@ enable_hwirq(struct inf_hw *hw) break; case INF_NICCY: val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); - val |= NICCY_IRQ_ENABLE;; + val |= NICCY_IRQ_ENABLE; outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG); break; case INF_SCT_1: @@ -924,7 +924,7 @@ setup_instance(struct inf_hw *card) mISDNipac_init(&card->ipac, card); if (card->ipac.isac.dch.dev.Bprotocols == 0) - goto error_setup;; + goto error_setup; err = mISDN_register_device(&card->ipac.isac.dch.dev, &card->pdev->dev, card->name); diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c index 38eb31439a73..d13fa5b119f5 100644 --- a/drivers/isdn/hardware/mISDN/mISDNisar.c +++ b/drivers/isdn/hardware/mISDN/mISDNisar.c @@ -264,7 +264,7 @@ load_firmware(struct isar_hw *isar, const u8 *buf, int size) while (noc) { val = le16_to_cpu(*sp++); *mp++ = val >> 8; - *mp++ = val & 0xFF;; + *mp++ = val & 0xFF; noc--; } spin_lock_irqsave(isar->hwlock, flags); -- cgit v1.2.3 From 6f38ad93e4882e84c1cc113736db7dc9252dcf11 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 17:04:31 +0000 Subject: drivers/net/bnx2x: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 4 ++-- drivers/net/bnx2x/bnx2x_main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 580919619252..38aeffef2a83 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -3904,7 +3904,7 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) - return 0;; + return 0; msleep(1); } return -EINVAL; @@ -3988,7 +3988,7 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) - return 0;; + return 0; msleep(1); } diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index e9ad16f00b56..7ffcb086cb6f 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -8078,7 +8078,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) int port = BP_PORT(bp); u32 val, val2; u32 config; - u32 ext_phy_type, ext_phy_config;; + u32 ext_phy_type, ext_phy_config; bp->link_params.bp = bp; bp->link_params.port = port; -- cgit v1.2.3 From 1d51c4185bb369cb39ed8cc20b331508e47b35b2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 17:04:32 +0000 Subject: drivers/net/e1000e: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/e1000e/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index c4ca1629f532..a6d54e460001 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4595,7 +4595,7 @@ dma_error: i += tx_ring->count; i--; buffer_info = &tx_ring->buffer_info[i]; - e1000_put_txbuf(adapter, buffer_info);; + e1000_put_txbuf(adapter, buffer_info); } return 0; -- cgit v1.2.3 From e81a1ba815666ec02ef5bf0e17cf256c88d233b3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 17:04:33 +0000 Subject: drivers/net/ixgbe: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 5428153af8f3..93f40bcf683c 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -68,7 +68,7 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter, * addresses */ for (i = 0; i < entries; i++) { - vfinfo->vf_mc_hashes[i] = hash_list[i];; + vfinfo->vf_mc_hashes[i] = hash_list[i]; } for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) { -- cgit v1.2.3 From 779bb41d4bd111d5631d58d1bf2d00b5c4389c80 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Nov 2010 17:04:37 +0000 Subject: drivers/net/cnic.c: Remove unnecessary semicolons Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/cnic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index 92bac19ad60a..594ca9c2c10a 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -1695,7 +1695,7 @@ static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[], *work = num; return -EINVAL; } - *work = 2 + req2->num_additional_wqes;; + *work = 2 + req2->num_additional_wqes; l5_cid = req1->iscsi_conn_id; if (l5_cid >= MAX_ISCSI_TBL_SZ) -- cgit v1.2.3 From ce5a121304af02d02489e86efb6ae26a67f95e52 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 15 Nov 2010 07:30:42 +0000 Subject: hso: Fix unused variable warning Fallout from the TIOCGICOUNT work Signed-off-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index b154a94de03e..be8cc2a8e213 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1745,7 +1745,6 @@ static int hso_serial_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct hso_serial *serial = get_serial_by_tty(tty); - void __user *uarg = (void __user *)arg; int ret = 0; D4("IOCTL cmd: %d, arg: %ld", cmd, arg); -- cgit v1.2.3 From 1f4f067f99cbb2af7af7a67bd025a9fb58b5156c Mon Sep 17 00:00:00 2001 From: Vasanthy Kolluri Date: Mon, 15 Nov 2010 08:09:55 +0000 Subject: enic: Fix build warnings Fix data type of argument passed to pci_alloc_consistent and pci_free_consistent routines. Signed-off-by: Vasanthy Kolluri Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: David S. Miller --- drivers/net/enic/enic.h | 2 +- drivers/net/enic/enic_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index c91d364c5527..70672541364e 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "1.4.1.6" +#define DRV_VERSION "1.4.1.7" #define DRV_COPYRIGHT "Copyright 2008-2010 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index a466ef91dd43..9f293fa24768 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -2042,7 +2042,7 @@ static int enic_dev_hang_reset(struct enic *enic) static int enic_set_rsskey(struct enic *enic) { - u64 rss_key_buf_pa; + dma_addr_t rss_key_buf_pa; union vnic_rss_key *rss_key_buf_va = NULL; union vnic_rss_key rss_key = { .key[0].b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}, @@ -2073,7 +2073,7 @@ static int enic_set_rsskey(struct enic *enic) static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits) { - u64 rss_cpu_buf_pa; + dma_addr_t rss_cpu_buf_pa; union vnic_rss_cpu *rss_cpu_buf_va = NULL; unsigned int i; int err; -- cgit v1.2.3 From 96f8d864afd646e4a52ea55462b7d83e3b94fd5c Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 16 Nov 2010 14:00:24 +0900 Subject: fbdev: move udlfb out of staging. udlfb has undergone a fair bit of cleanup recently and is effectively at the point where it can be liberated from staging purgatory and promoted to a real driver. The outstanding cleanups are all minor, with some of them dependent on drivers/video headers, so these will be done incrementally from udlfb's new home. Requested-by: Bernie Thompson Signed-off-by: Paul Mundt --- Documentation/fb/udlfb.txt | 144 +++ drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/udlfb/Kconfig | 14 - drivers/staging/udlfb/Makefile | 1 - drivers/staging/udlfb/udlfb.c | 1916 --------------------------------------- drivers/staging/udlfb/udlfb.h | 117 --- drivers/staging/udlfb/udlfb.txt | 144 --- drivers/video/Kconfig | 14 + drivers/video/Makefile | 1 + drivers/video/udlfb.c | 1915 ++++++++++++++++++++++++++++++++++++++ include/video/udlfb.h | 117 +++ 12 files changed, 2191 insertions(+), 2195 deletions(-) create mode 100644 Documentation/fb/udlfb.txt delete mode 100644 drivers/staging/udlfb/Kconfig delete mode 100644 drivers/staging/udlfb/Makefile delete mode 100644 drivers/staging/udlfb/udlfb.c delete mode 100644 drivers/staging/udlfb/udlfb.h delete mode 100644 drivers/staging/udlfb/udlfb.txt create mode 100644 drivers/video/udlfb.c create mode 100644 include/video/udlfb.h (limited to 'drivers') diff --git a/Documentation/fb/udlfb.txt b/Documentation/fb/udlfb.txt new file mode 100644 index 000000000000..7fdde2a02a27 --- /dev/null +++ b/Documentation/fb/udlfb.txt @@ -0,0 +1,144 @@ + +What is udlfb? +=============== + +This is a driver for DisplayLink USB 2.0 era graphics chips. + +DisplayLink chips provide simple hline/blit operations with some compression, +pairing that with a hardware framebuffer (16MB) on the other end of the +USB wire. That hardware framebuffer is able to drive the VGA, DVI, or HDMI +monitor with no CPU involvement until a pixel has to change. + +The CPU or other local resource does all the rendering; optinally compares the +result with a local shadow of the remote hardware framebuffer to identify +the minimal set of pixels that have changed; and compresses and sends those +pixels line-by-line via USB bulk transfers. + +Because of the efficiency of bulk transfers and a protocol on top that +does not require any acks - the effect is very low latency that +can support surprisingly high resolutions with good performance for +non-gaming and non-video applications. + +Mode setting, EDID read, etc are other bulk or control transfers. Mode +setting is very flexible - able to set nearly arbitrary modes from any timing. + +Advantages of USB graphics in general: + + * Ability to add a nearly arbitrary number of displays to any USB 2.0 + capable system. On Linux, number of displays is limited by fbdev interface + (FB_MAX is currently 32). Of course, all USB devices on the same + host controller share the same 480Mbs USB 2.0 interface. + +Advantages of supporting DisplayLink chips with kernel framebuffer interface: + + * The actual hardware functionality of DisplayLink chips matches nearly + one-to-one with the fbdev interface, making the driver quite small and + tight relative to the functionality it provides. + * X servers and other applications can use the standard fbdev interface + from user mode to talk to the device, without needing to know anything + about USB or DisplayLink's protocol at all. A "displaylink" X driver + and a slightly modified "fbdev" X driver are among those that already do. + +Disadvantages: + + * Fbdev's mmap interface assumes a real hardware framebuffer is mapped. + In the case of USB graphics, it is just an allocated (virtual) buffer. + Writes need to be detected and encoded into USB bulk transfers by the CPU. + Accurate damage/changed area notifications work around this problem. + In the future, hopefully fbdev will be enhanced with an small standard + interface to allow mmap clients to report damage, for the benefit + of virtual or remote framebuffers. + * Fbdev does not arbitrate client ownership of the framebuffer well. + * Fbcon assumes the first framebuffer it finds should be consumed for console. + * It's not clear what the future of fbdev is, given the rise of KMS/DRM. + +How to use it? +============== + +Udlfb, when loaded as a module, will match against all USB 2.0 generation +DisplayLink chips (Alex and Ollie family). It will then attempt to read the EDID +of the monitor, and set the best common mode between the DisplayLink device +and the monitor's capabilities. + +If the DisplayLink device is successful, it will paint a "green screen" which +means that from a hardware and fbdev software perspective, everything is good. + +At that point, a /dev/fb? interface will be present for user-mode applications +to open and begin writing to the framebuffer of the DisplayLink device using +standard fbdev calls. Note that if mmap() is used, by default the user mode +application must send down damage notifcations to trigger repaints of the +changed regions. Alternatively, udlfb can be recompiled with experimental +defio support enabled, to support a page-fault based detection mechanism +that can work without explicit notifcation. + +The most common client of udlfb is xf86-video-displaylink or a modified +xf86-video-fbdev X server. These servers have no real DisplayLink specific +code. They write to the standard framebuffer interface and rely on udlfb +to do its thing. The one extra feature they have is the ability to report +rectangles from the X DAMAGE protocol extension down to udlfb via udlfb's +damage interface (which will hopefully be standardized for all virtual +framebuffers that need damage info). These damage notifications allow +udlfb to efficiently process the changed pixels. + +Module Options +============== + +Special configuration for udlfb is usually unnecessary. There are a few +options, however. + +From the command line, pass options to modprobe +modprobe udlfb defio=1 console=1 + +Or for permanent option, create file like /etc/modprobe.d/options with text +options udlfb defio=1 console=1 + +Accepted options: + +fb_defio Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel + module to track changed areas of the framebuffer by page faults. + Standard fbdev applications that use mmap but that do not + report damage, may be able to work with this enabled. + Disabled by default because of overhead and other issues. + +console Allow fbcon to attach to udlfb provided framebuffers. This + is disabled by default because fbcon will aggressively consume + the first framebuffer it finds, which isn't usually what the + user wants in the case of USB displays. + +Sysfs Attributes +================ + +Udlfb creates several files in /sys/class/graphics/fb? +Where ? is the sequential framebuffer id of the particular DisplayLink device + +edid If a valid EDID blob is written to this file (typically + by a udev rule), then udlfb will use this EDID as a + backup in case reading the actual EDID of the monitor + attached to the DisplayLink device fails. This is + especially useful for fixed panels, etc. that cannot + communicate their capabilities via EDID. Reading + this file returns the current EDID of the attached + monitor (or last backup value written). This is + useful to get the EDID of the attached monitor, + which can be passed to utilities like parse-edid. + +metrics_bytes_rendered 32-bit count of pixel bytes rendered + +metrics_bytes_identical 32-bit count of how many of those bytes were found to be + unchanged, based on a shadow framebuffer check + +metrics_bytes_sent 32-bit count of how many bytes were transferred over + USB to communicate the resulting changed pixels to the + hardware. Includes compression and protocol overhead + +metrics_cpu_kcycles_used 32-bit count of CPU cycles used in processing the + above pixels (in thousands of cycles). + +metrics_reset Write-only. Any write to this file resets all metrics + above to zero. Note that the 32-bit counters above + roll over very quickly. To get reliable results, design + performance tests to start and finish in a very short + period of time (one minute or less is safe). + +-- +Bernie Thompson diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 5eafdf435550..df31a7228079 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -111,8 +111,6 @@ source "drivers/staging/vt6655/Kconfig" source "drivers/staging/vt6656/Kconfig" -source "drivers/staging/udlfb/Kconfig" - source "drivers/staging/hv/Kconfig" source "drivers/staging/vme/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a97a955c094b..7a15c0c82b69 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -38,7 +38,6 @@ obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6656) += vt6656/ -obj-$(CONFIG_FB_UDL) += udlfb/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ diff --git a/drivers/staging/udlfb/Kconfig b/drivers/staging/udlfb/Kconfig deleted file mode 100644 index 65bd5db4ca56..000000000000 --- a/drivers/staging/udlfb/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config FB_UDL - tristate "Displaylink USB Framebuffer support" - depends on FB && USB - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - ---help--- - This is a kernel framebuffer driver for DisplayLink USB devices. - Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and - mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. - To compile as a module, choose M here: the module name is udlfb. diff --git a/drivers/staging/udlfb/Makefile b/drivers/staging/udlfb/Makefile deleted file mode 100644 index 30d9e675b10f..000000000000 --- a/drivers/staging/udlfb/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_FB_UDL) += udlfb.o diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c deleted file mode 100644 index fed25105970a..000000000000 --- a/drivers/staging/udlfb/udlfb.c +++ /dev/null @@ -1,1916 +0,0 @@ -/* - * udlfb.c -- Framebuffer driver for DisplayLink USB controller - * - * Copyright (C) 2009 Roberto De Ioris - * Copyright (C) 2009 Jaya Kumar - * Copyright (C) 2009 Bernie Thompson - * - * This file is subject to the terms and conditions of the GNU General Public - * License v2. See the file COPYING in the main directory of this archive for - * more details. - * - * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven, - * usb-skeleton by GregKH. - * - * Device-specific portions based on information from Displaylink, with work - * from Florian Echtler, Henrik Bjerregaard Pedersen, and others. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udlfb.h" - -static struct fb_fix_screeninfo dlfb_fix = { - .id = "udlfb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, -}; - -static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST | -#ifdef FBINFO_VIRTFB - FBINFO_VIRTFB | -#endif - FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR; - -/* - * There are many DisplayLink-based products, all with unique PIDs. We are able - * to support all volume ones (circa 2009) with a single driver, so we match - * globally on VID. TODO: Probe() needs to detect when we might be running - * "future" chips, and bail on those, so a compatible driver can match. - */ -static struct usb_device_id id_table[] = { - {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, - {}, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* module options */ -static int console; /* Optionally allow fbcon to consume first framebuffer */ -static int fb_defio; /* Optionally enable experimental fb_defio mmap support */ - -/* dlfb keeps a list of urbs for efficient bulk transfers */ -static void dlfb_urb_completion(struct urb *urb); -static struct urb *dlfb_get_urb(struct dlfb_data *dev); -static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len); -static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size); -static void dlfb_free_urb_list(struct dlfb_data *dev); - -/* - * All DisplayLink bulk operations start with 0xAF, followed by specific code - * All operations are written to buffers which then later get sent to device - */ -static char *dlfb_set_register(char *buf, u8 reg, u8 val) -{ - *buf++ = 0xAF; - *buf++ = 0x20; - *buf++ = reg; - *buf++ = val; - return buf; -} - -static char *dlfb_vidreg_lock(char *buf) -{ - return dlfb_set_register(buf, 0xFF, 0x00); -} - -static char *dlfb_vidreg_unlock(char *buf) -{ - return dlfb_set_register(buf, 0xFF, 0xFF); -} - -/* - * On/Off for driving the DisplayLink framebuffer to the display - * 0x00 H and V sync on - * 0x01 H and V sync off (screen blank but powered) - * 0x07 DPMS powerdown (requires modeset to come back) - */ -static char *dlfb_enable_hvsync(char *buf, bool enable) -{ - if (enable) - return dlfb_set_register(buf, 0x1F, 0x00); - else - return dlfb_set_register(buf, 0x1F, 0x07); -} - -static char *dlfb_set_color_depth(char *buf, u8 selection) -{ - return dlfb_set_register(buf, 0x00, selection); -} - -static char *dlfb_set_base16bpp(char *wrptr, u32 base) -{ - /* the base pointer is 16 bits wide, 0x20 is hi byte. */ - wrptr = dlfb_set_register(wrptr, 0x20, base >> 16); - wrptr = dlfb_set_register(wrptr, 0x21, base >> 8); - return dlfb_set_register(wrptr, 0x22, base); -} - -/* - * DisplayLink HW has separate 16bpp and 8bpp framebuffers. - * In 24bpp modes, the low 323 RGB bits go in the 8bpp framebuffer - */ -static char *dlfb_set_base8bpp(char *wrptr, u32 base) -{ - wrptr = dlfb_set_register(wrptr, 0x26, base >> 16); - wrptr = dlfb_set_register(wrptr, 0x27, base >> 8); - return dlfb_set_register(wrptr, 0x28, base); -} - -static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value) -{ - wrptr = dlfb_set_register(wrptr, reg, value >> 8); - return dlfb_set_register(wrptr, reg+1, value); -} - -/* - * This is kind of weird because the controller takes some - * register values in a different byte order than other registers. - */ -static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value) -{ - wrptr = dlfb_set_register(wrptr, reg, value); - return dlfb_set_register(wrptr, reg+1, value >> 8); -} - -/* - * LFSR is linear feedback shift register. The reason we have this is - * because the display controller needs to minimize the clock depth of - * various counters used in the display path. So this code reverses the - * provided value into the lfsr16 value by counting backwards to get - * the value that needs to be set in the hardware comparator to get the - * same actual count. This makes sense once you read above a couple of - * times and think about it from a hardware perspective. - */ -static u16 dlfb_lfsr16(u16 actual_count) -{ - u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */ - - while (actual_count--) { - lv = ((lv << 1) | - (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1)) - & 0xFFFF; - } - - return (u16) lv; -} - -/* - * This does LFSR conversion on the value that is to be written. - * See LFSR explanation above for more detail. - */ -static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value) -{ - return dlfb_set_register_16(wrptr, reg, dlfb_lfsr16(value)); -} - -/* - * This takes a standard fbdev screeninfo struct and all of its monitor mode - * details and converts them into the DisplayLink equivalent register commands. - */ -static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var) -{ - u16 xds, yds; - u16 xde, yde; - u16 yec; - - /* x display start */ - xds = var->left_margin + var->hsync_len; - wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds); - /* x display end */ - xde = xds + var->xres; - wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde); - - /* y display start */ - yds = var->upper_margin + var->vsync_len; - wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds); - /* y display end */ - yde = yds + var->yres; - wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde); - - /* x end count is active + blanking - 1 */ - wrptr = dlfb_set_register_lfsr16(wrptr, 0x09, - xde + var->right_margin - 1); - - /* libdlo hardcodes hsync start to 1 */ - wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1); - - /* hsync end is width of sync pulse + 1 */ - wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1); - - /* hpixels is active pixels */ - wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres); - - /* yendcount is vertical active + vertical blanking */ - yec = var->yres + var->upper_margin + var->lower_margin + - var->vsync_len; - wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec); - - /* libdlo hardcodes vsync start to 0 */ - wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0); - - /* vsync end is width of vsync pulse */ - wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len); - - /* vpixels is active pixels */ - wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres); - - /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */ - wrptr = dlfb_set_register_16be(wrptr, 0x1B, - 200*1000*1000/var->pixclock); - - return wrptr; -} - -/* - * This takes a standard fbdev screeninfo struct that was fetched or prepared - * and then generates the appropriate command sequence that then drives the - * display controller. - */ -static int dlfb_set_video_mode(struct dlfb_data *dev, - struct fb_var_screeninfo *var) -{ - char *buf; - char *wrptr; - int retval = 0; - int writesize; - struct urb *urb; - - if (!atomic_read(&dev->usb_active)) - return -EPERM; - - urb = dlfb_get_urb(dev); - if (!urb) - return -ENOMEM; - - buf = (char *) urb->transfer_buffer; - - /* - * This first section has to do with setting the base address on the - * controller * associated with the display. There are 2 base - * pointers, currently, we only * use the 16 bpp segment. - */ - wrptr = dlfb_vidreg_lock(buf); - wrptr = dlfb_set_color_depth(wrptr, 0x00); - /* set base for 16bpp segment to 0 */ - wrptr = dlfb_set_base16bpp(wrptr, 0); - /* set base for 8bpp segment to end of fb */ - wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len); - - wrptr = dlfb_set_vid_cmds(wrptr, var); - wrptr = dlfb_enable_hvsync(wrptr, true); - wrptr = dlfb_vidreg_unlock(wrptr); - - writesize = wrptr - buf; - - retval = dlfb_submit_urb(dev, urb, writesize); - - return retval; -} - -static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long page, pos; - - if (offset + size > info->fix.smem_len) - return -EINVAL; - - pos = (unsigned long)info->fix.smem_start + offset; - - dl_notice("mmap() framebuffer addr:%lu size:%lu\n", - pos, size); - - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - return 0; -} - -/* - * Trims identical data from front and back of line - * Sets new front buffer address and width - * And returns byte count of identical pixels - * Assumes CPU natural alignment (unsigned long) - * for back and front buffer ptrs and width - */ -static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) -{ - int j, k; - const unsigned long *back = (const unsigned long *) bback; - const unsigned long *front = (const unsigned long *) *bfront; - const int width = *width_bytes / sizeof(unsigned long); - int identical = width; - int start = width; - int end = width; - - prefetch((void *) front); - prefetch((void *) back); - - for (j = 0; j < width; j++) { - if (back[j] != front[j]) { - start = j; - break; - } - } - - for (k = width - 1; k > j; k--) { - if (back[k] != front[k]) { - end = k+1; - break; - } - } - - identical = start + (width - end); - *bfront = (u8 *) &front[start]; - *width_bytes = (end - start) * sizeof(unsigned long); - - return identical * sizeof(unsigned long); -} - -/* - * Render a command stream for an encoded horizontal line segment of pixels. - * - * A command buffer holds several commands. - * It always begins with a fresh command header - * (the protocol doesn't require this, but we enforce it to allow - * multiple buffers to be potentially encoded and sent in parallel). - * A single command encodes one contiguous horizontal line of pixels - * - * The function relies on the client to do all allocation, so that - * rendering can be done directly to output buffers (e.g. USB URBs). - * The function fills the supplied command buffer, providing information - * on where it left off, so the client may call in again with additional - * buffers if the line will take several buffers to complete. - * - * A single command can transmit a maximum of 256 pixels, - * regardless of the compression ratio (protocol design limit). - * To the hardware, 0 for a size byte means 256 - * - * Rather than 256 pixel commands which are either rl or raw encoded, - * the rlx command simply assumes alternating raw and rl spans within one cmd. - * This has a slightly larger header overhead, but produces more even results. - * It also processes all data (read and write) in a single pass. - * Performance benchmarks of common cases show it having just slightly better - * compression than 256 pixel raw or rle commands, with similar CPU consumpion. - * But for very rl friendly data, will compress not quite as well. - */ -static void dlfb_compress_hline( - const uint16_t **pixel_start_ptr, - const uint16_t *const pixel_end, - uint32_t *device_address_ptr, - uint8_t **command_buffer_ptr, - const uint8_t *const cmd_buffer_end) -{ - const uint16_t *pixel = *pixel_start_ptr; - uint32_t dev_addr = *device_address_ptr; - uint8_t *cmd = *command_buffer_ptr; - const int bpp = 2; - - while ((pixel_end > pixel) && - (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) { - uint8_t *raw_pixels_count_byte = 0; - uint8_t *cmd_pixels_count_byte = 0; - const uint16_t *raw_pixel_start = 0; - const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0; - - prefetchw((void *) cmd); /* pull in one cache line at least */ - - *cmd++ = 0xAF; - *cmd++ = 0x6B; - *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF); - *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF); - *cmd++ = (uint8_t) ((dev_addr) & 0xFF); - - cmd_pixels_count_byte = cmd++; /* we'll know this later */ - cmd_pixel_start = pixel; - - raw_pixels_count_byte = cmd++; /* we'll know this later */ - raw_pixel_start = pixel; - - cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1, - min((int)(pixel_end - pixel), - (int)(cmd_buffer_end - cmd) / bpp)); - - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); - - while (pixel < cmd_pixel_end) { - const uint16_t * const repeating_pixel = pixel; - - *(uint16_t *)cmd = cpu_to_be16p(pixel); - cmd += 2; - pixel++; - - if (unlikely((pixel < cmd_pixel_end) && - (*pixel == *repeating_pixel))) { - /* go back and fill in raw pixel count */ - *raw_pixels_count_byte = ((repeating_pixel - - raw_pixel_start) + 1) & 0xFF; - - while ((pixel < cmd_pixel_end) - && (*pixel == *repeating_pixel)) { - pixel++; - } - - /* immediately after raw data is repeat byte */ - *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF; - - /* Then start another raw pixel span */ - raw_pixel_start = pixel; - raw_pixels_count_byte = cmd++; - } - } - - if (pixel > raw_pixel_start) { - /* finalize last RAW span */ - *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF; - } - - *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF; - dev_addr += (pixel - cmd_pixel_start) * bpp; - } - - if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { - /* Fill leftover bytes with no-ops */ - if (cmd_buffer_end > cmd) - memset(cmd, 0xAF, cmd_buffer_end - cmd); - cmd = (uint8_t *) cmd_buffer_end; - } - - *command_buffer_ptr = cmd; - *pixel_start_ptr = pixel; - *device_address_ptr = dev_addr; - - return; -} - -/* - * There are 3 copies of every pixel: The front buffer that the fbdev - * client renders to, the actual framebuffer across the USB bus in hardware - * (that we can only write to, slowly, and can never read), and (optionally) - * our shadow copy that tracks what's been sent to that hardware buffer. - */ -static int dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr, - const char *front, char **urb_buf_ptr, - u32 byte_offset, u32 byte_width, - int *ident_ptr, int *sent_ptr) -{ - const u8 *line_start, *line_end, *next_pixel; - u32 dev_addr = dev->base16 + byte_offset; - struct urb *urb = *urb_ptr; - u8 *cmd = *urb_buf_ptr; - u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; - - line_start = (u8 *) (front + byte_offset); - next_pixel = line_start; - line_end = next_pixel + byte_width; - - if (dev->backing_buffer) { - int offset; - const u8 *back_start = (u8 *) (dev->backing_buffer - + byte_offset); - - *ident_ptr += dlfb_trim_hline(back_start, &next_pixel, - &byte_width); - - offset = next_pixel - line_start; - line_end = next_pixel + byte_width; - dev_addr += offset; - back_start += offset; - line_start += offset; - - memcpy((char *)back_start, (char *) line_start, - byte_width); - } - - while (next_pixel < line_end) { - - dlfb_compress_hline((const uint16_t **) &next_pixel, - (const uint16_t *) line_end, &dev_addr, - (u8 **) &cmd, (u8 *) cmd_end); - - if (cmd >= cmd_end) { - int len = cmd - (u8 *) urb->transfer_buffer; - if (dlfb_submit_urb(dev, urb, len)) - return 1; /* lost pixels is set */ - *sent_ptr += len; - urb = dlfb_get_urb(dev); - if (!urb) - return 1; /* lost_pixels is set */ - *urb_ptr = urb; - cmd = urb->transfer_buffer; - cmd_end = &cmd[urb->transfer_buffer_length]; - } - } - - *urb_buf_ptr = cmd; - - return 0; -} - -int dlfb_handle_damage(struct dlfb_data *dev, int x, int y, - int width, int height, char *data) -{ - int i, ret; - char *cmd; - cycles_t start_cycles, end_cycles; - int bytes_sent = 0; - int bytes_identical = 0; - struct urb *urb; - int aligned_x; - - start_cycles = get_cycles(); - - aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long)); - width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long)); - x = aligned_x; - - if ((width <= 0) || - (x + width > dev->info->var.xres) || - (y + height > dev->info->var.yres)) - return -EINVAL; - - if (!atomic_read(&dev->usb_active)) - return 0; - - urb = dlfb_get_urb(dev); - if (!urb) - return 0; - cmd = urb->transfer_buffer; - - for (i = y; i < y + height ; i++) { - const int line_offset = dev->info->fix.line_length * i; - const int byte_offset = line_offset + (x * BPP); - - if (dlfb_render_hline(dev, &urb, - (char *) dev->info->fix.smem_start, - &cmd, byte_offset, width * BPP, - &bytes_identical, &bytes_sent)) - goto error; - } - - if (cmd > (char *) urb->transfer_buffer) { - /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; - ret = dlfb_submit_urb(dev, urb, len); - bytes_sent += len; - } else - dlfb_urb_completion(urb); - -error: - atomic_add(bytes_sent, &dev->bytes_sent); - atomic_add(bytes_identical, &dev->bytes_identical); - atomic_add(width*height*2, &dev->bytes_rendered); - end_cycles = get_cycles(); - atomic_add(((unsigned int) ((end_cycles - start_cycles) - >> 10)), /* Kcycles */ - &dev->cpu_kcycles_used); - - return 0; -} - -static ssize_t dlfb_ops_read(struct fb_info *info, char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t result = -ENOSYS; - -#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE - result = fb_sys_read(info, buf, count, ppos); -#endif - - return result; -} - -/* - * Path triggered by usermode clients who write to filesystem - * e.g. cat filename > /dev/fb1 - * Not used by X Windows or text-mode console. But useful for testing. - * Slow because of extra copy and we must assume all pixels dirty. - */ -static ssize_t dlfb_ops_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t result = -ENOSYS; - struct dlfb_data *dev = info->par; - u32 offset = (u32) *ppos; - -#if defined CONFIG_FB_SYS_FOPS || defined CONFIG_FB_SYS_FOPS_MODULE - - result = fb_sys_write(info, buf, count, ppos); - - if (result > 0) { - int start = max((int)(offset / info->fix.line_length) - 1, 0); - int lines = min((u32)((result / info->fix.line_length) + 1), - (u32)info->var.yres); - - dlfb_handle_damage(dev, 0, start, info->var.xres, - lines, info->screen_base); - } -#endif - - return result; -} - -/* hardware has native COPY command (see libdlo), but not worth it for fbcon */ -static void dlfb_ops_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - - struct dlfb_data *dev = info->par; - -#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE - - sys_copyarea(info, area); - - dlfb_handle_damage(dev, area->dx, area->dy, - area->width, area->height, info->screen_base); -#endif - -} - -static void dlfb_ops_imageblit(struct fb_info *info, - const struct fb_image *image) -{ - struct dlfb_data *dev = info->par; - -#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE - - sys_imageblit(info, image); - - dlfb_handle_damage(dev, image->dx, image->dy, - image->width, image->height, info->screen_base); - -#endif - -} - -static void dlfb_ops_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct dlfb_data *dev = info->par; - -#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE - - sys_fillrect(info, rect); - - dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width, - rect->height, info->screen_base); -#endif - -} - -#ifdef CONFIG_FB_DEFERRED_IO -/* - * NOTE: fb_defio.c is holding info->fbdefio.mutex - * Touching ANY framebuffer memory that triggers a page fault - * in fb_defio will cause a deadlock, when it also tries to - * grab the same mutex. - */ -static void dlfb_dpy_deferred_io(struct fb_info *info, - struct list_head *pagelist) -{ - struct page *cur; - struct fb_deferred_io *fbdefio = info->fbdefio; - struct dlfb_data *dev = info->par; - struct urb *urb; - char *cmd; - cycles_t start_cycles, end_cycles; - int bytes_sent = 0; - int bytes_identical = 0; - int bytes_rendered = 0; - - if (!fb_defio) - return; - - if (!atomic_read(&dev->usb_active)) - return; - - start_cycles = get_cycles(); - - urb = dlfb_get_urb(dev); - if (!urb) - return; - - cmd = urb->transfer_buffer; - - /* walk the written page list and render each to device */ - list_for_each_entry(cur, &fbdefio->pagelist, lru) { - - if (dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start, - &cmd, cur->index << PAGE_SHIFT, - PAGE_SIZE, &bytes_identical, &bytes_sent)) - goto error; - bytes_rendered += PAGE_SIZE; - } - - if (cmd > (char *) urb->transfer_buffer) { - /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; - dlfb_submit_urb(dev, urb, len); - bytes_sent += len; - } else - dlfb_urb_completion(urb); - -error: - atomic_add(bytes_sent, &dev->bytes_sent); - atomic_add(bytes_identical, &dev->bytes_identical); - atomic_add(bytes_rendered, &dev->bytes_rendered); - end_cycles = get_cycles(); - atomic_add(((unsigned int) ((end_cycles - start_cycles) - >> 10)), /* Kcycles */ - &dev->cpu_kcycles_used); -} - -#endif - -static int dlfb_get_edid(struct dlfb_data *dev, char *edid, int len) -{ - int i; - int ret; - char *rbuf; - - rbuf = kmalloc(2, GFP_KERNEL); - if (!rbuf) - return 0; - - for (i = 0; i < len; i++) { - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), (0x02), - (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2, - HZ); - if (ret < 1) { - dl_err("Read EDID byte %d failed err %x\n", i, ret); - i--; - break; - } - edid[i] = rbuf[1]; - } - - kfree(rbuf); - - return i; -} - -static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd, - unsigned long arg) -{ - - struct dlfb_data *dev = info->par; - struct dloarea *area = NULL; - - if (!atomic_read(&dev->usb_active)) - return 0; - - /* TODO: Update X server to get this from sysfs instead */ - if (cmd == DLFB_IOCTL_RETURN_EDID) { - char *edid = (char *)arg; - if (copy_to_user(edid, dev->edid, dev->edid_size)) - return -EFAULT; - return 0; - } - - /* TODO: Help propose a standard fb.h ioctl to report mmap damage */ - if (cmd == DLFB_IOCTL_REPORT_DAMAGE) { - - /* - * If we have a damage-aware client, turn fb_defio "off" - * To avoid perf imact of unecessary page fault handling. - * Done by resetting the delay for this fb_info to a very - * long period. Pages will become writable and stay that way. - * Reset to normal value when all clients have closed this fb. - */ - if (info->fbdefio) - info->fbdefio->delay = DL_DEFIO_WRITE_DISABLE; - - area = (struct dloarea *)arg; - - if (area->x < 0) - area->x = 0; - - if (area->x > info->var.xres) - area->x = info->var.xres; - - if (area->y < 0) - area->y = 0; - - if (area->y > info->var.yres) - area->y = info->var.yres; - - dlfb_handle_damage(dev, area->x, area->y, area->w, area->h, - info->screen_base); - } - - return 0; -} - -/* taken from vesafb */ -static int -dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, struct fb_info *info) -{ - int err = 0; - - if (regno >= info->cmap.len) - return 1; - - if (regno < 16) { - if (info->var.red.offset == 10) { - /* 1:5:5:5 */ - ((u32 *) (info->pseudo_palette))[regno] = - ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11); - } else { - /* 0:5:6:5 */ - ((u32 *) (info->pseudo_palette))[regno] = - ((red & 0xf800)) | - ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); - } - } - - return err; -} - -/* - * It's common for several clients to have framebuffer open simultaneously. - * e.g. both fbcon and X. Makes things interesting. - * Assumes caller is holding info->lock (for open and release at least) - */ -static int dlfb_ops_open(struct fb_info *info, int user) -{ - struct dlfb_data *dev = info->par; - - /* - * fbcon aggressively connects to first framebuffer it finds, - * preventing other clients (X) from working properly. Usually - * not what the user wants. Fail by default with option to enable. - */ - if ((user == 0) & (!console)) - return -EBUSY; - - /* If the USB device is gone, we don't accept new opens */ - if (dev->virtualized) - return -ENODEV; - - dev->fb_count++; - - kref_get(&dev->kref); - -#ifdef CONFIG_FB_DEFERRED_IO - if (fb_defio && (info->fbdefio == NULL)) { - /* enable defio at last moment if not disabled by client */ - - struct fb_deferred_io *fbdefio; - - fbdefio = kmalloc(sizeof(struct fb_deferred_io), GFP_KERNEL); - - if (fbdefio) { - fbdefio->delay = DL_DEFIO_WRITE_DELAY; - fbdefio->deferred_io = dlfb_dpy_deferred_io; - } - - info->fbdefio = fbdefio; - fb_deferred_io_init(info); - } -#endif - - dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n", - info->node, user, info, dev->fb_count); - - return 0; -} - -/* - * Called when all client interfaces to start transactions have been disabled, - * and all references to our device instance (dlfb_data) are released. - * Every transaction must have a reference, so we know are fully spun down - */ -static void dlfb_free(struct kref *kref) -{ - struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref); - - /* this function will wait for all in-flight urbs to complete */ - if (dev->urbs.count > 0) - dlfb_free_urb_list(dev); - - if (dev->backing_buffer) - vfree(dev->backing_buffer); - - kfree(dev->edid); - - dl_warn("freeing dlfb_data %p\n", dev); - - kfree(dev); -} - -static void dlfb_release_urb_work(struct work_struct *work) -{ - struct urb_node *unode = container_of(work, struct urb_node, - release_urb_work.work); - - up(&unode->dev->urbs.limit_sem); -} - -static void dlfb_free_framebuffer_work(struct work_struct *work) -{ - struct dlfb_data *dev = container_of(work, struct dlfb_data, - free_framebuffer_work.work); - struct fb_info *info = dev->info; - int node = info->node; - - unregister_framebuffer(info); - - if (info->cmap.len != 0) - fb_dealloc_cmap(&info->cmap); - if (info->monspecs.modedb) - fb_destroy_modedb(info->monspecs.modedb); - if (info->screen_base) - vfree(info->screen_base); - - fb_destroy_modelist(&info->modelist); - - dev->info = 0; - - /* Assume info structure is freed after this point */ - framebuffer_release(info); - - dl_warn("fb_info for /dev/fb%d has been freed\n", node); - - /* ref taken in probe() as part of registering framebfufer */ - kref_put(&dev->kref, dlfb_free); -} - -/* - * Assumes caller is holding info->lock mutex (for open and release at least) - */ -static int dlfb_ops_release(struct fb_info *info, int user) -{ - struct dlfb_data *dev = info->par; - - dev->fb_count--; - - /* We can't free fb_info here - fbmem will touch it when we return */ - if (dev->virtualized && (dev->fb_count == 0)) - schedule_delayed_work(&dev->free_framebuffer_work, HZ); - -#ifdef CONFIG_FB_DEFERRED_IO - if ((dev->fb_count == 0) && (info->fbdefio)) { - fb_deferred_io_cleanup(info); - kfree(info->fbdefio); - info->fbdefio = NULL; - info->fbops->fb_mmap = dlfb_ops_mmap; - } -#endif - - dl_warn("released /dev/fb%d user=%d count=%d\n", - info->node, user, dev->fb_count); - - kref_put(&dev->kref, dlfb_free); - - return 0; -} - -/* - * Check whether a video mode is supported by the DisplayLink chip - * We start from monitor's modes, so don't need to filter that here - */ -static int dlfb_is_valid_mode(struct fb_videomode *mode, - struct fb_info *info) -{ - struct dlfb_data *dev = info->par; - - if (mode->xres * mode->yres > dev->sku_pixel_limit) { - dl_warn("%dx%d beyond chip capabilities\n", - mode->xres, mode->yres); - return 0; - } - - dl_info("%dx%d valid mode\n", mode->xres, mode->yres); - - return 1; -} - -static void dlfb_var_color_format(struct fb_var_screeninfo *var) -{ - const struct fb_bitfield red = { 11, 5, 0 }; - const struct fb_bitfield green = { 5, 6, 0 }; - const struct fb_bitfield blue = { 0, 5, 0 }; - - var->bits_per_pixel = 16; - var->red = red; - var->green = green; - var->blue = blue; -} - -static int dlfb_ops_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - struct fb_videomode mode; - - /* TODO: support dynamically changing framebuffer size */ - if ((var->xres * var->yres * 2) > info->fix.smem_len) - return -EINVAL; - - /* set device-specific elements of var unrelated to mode */ - dlfb_var_color_format(var); - - fb_var_to_videomode(&mode, var); - - if (!dlfb_is_valid_mode(&mode, info)) - return -EINVAL; - - return 0; -} - -static int dlfb_ops_set_par(struct fb_info *info) -{ - struct dlfb_data *dev = info->par; - int result; - u16 *pix_framebuffer; - int i; - - dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres); - - result = dlfb_set_video_mode(dev, &info->var); - - if ((result == 0) && (dev->fb_count == 0)) { - - /* paint greenscreen */ - - pix_framebuffer = (u16 *) info->screen_base; - for (i = 0; i < info->fix.smem_len / 2; i++) - pix_framebuffer[i] = 0x37e6; - - dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres, - info->screen_base); - } - - return result; -} - -/* - * In order to come back from full DPMS off, we need to set the mode again - */ -static int dlfb_ops_blank(int blank_mode, struct fb_info *info) -{ - struct dlfb_data *dev = info->par; - - if (blank_mode != FB_BLANK_UNBLANK) { - char *bufptr; - struct urb *urb; - - urb = dlfb_get_urb(dev); - if (!urb) - return 0; - - bufptr = (char *) urb->transfer_buffer; - bufptr = dlfb_vidreg_lock(bufptr); - bufptr = dlfb_enable_hvsync(bufptr, false); - bufptr = dlfb_vidreg_unlock(bufptr); - - dlfb_submit_urb(dev, urb, bufptr - - (char *) urb->transfer_buffer); - } else { - dlfb_set_video_mode(dev, &info->var); - } - - return 0; -} - -static struct fb_ops dlfb_ops = { - .owner = THIS_MODULE, - .fb_read = dlfb_ops_read, - .fb_write = dlfb_ops_write, - .fb_setcolreg = dlfb_ops_setcolreg, - .fb_fillrect = dlfb_ops_fillrect, - .fb_copyarea = dlfb_ops_copyarea, - .fb_imageblit = dlfb_ops_imageblit, - .fb_mmap = dlfb_ops_mmap, - .fb_ioctl = dlfb_ops_ioctl, - .fb_open = dlfb_ops_open, - .fb_release = dlfb_ops_release, - .fb_blank = dlfb_ops_blank, - .fb_check_var = dlfb_ops_check_var, - .fb_set_par = dlfb_ops_set_par, -}; - - -/* - * Assumes &info->lock held by caller - * Assumes no active clients have framebuffer open - */ -static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info) -{ - int retval = -ENOMEM; - int old_len = info->fix.smem_len; - int new_len; - unsigned char *old_fb = info->screen_base; - unsigned char *new_fb; - unsigned char *new_back; - - dl_warn("Reallocating framebuffer. Addresses will change!\n"); - - new_len = info->fix.line_length * info->var.yres; - - if (PAGE_ALIGN(new_len) > old_len) { - /* - * Alloc system memory for virtual framebuffer - */ - new_fb = vmalloc(new_len); - if (!new_fb) { - dl_err("Virtual framebuffer alloc failed\n"); - goto error; - } - - if (info->screen_base) { - memcpy(new_fb, old_fb, old_len); - vfree(info->screen_base); - } - - info->screen_base = new_fb; - info->fix.smem_len = PAGE_ALIGN(new_len); - info->fix.smem_start = (unsigned long) new_fb; - info->flags = udlfb_info_flags; - - /* - * Second framebuffer copy to mirror the framebuffer state - * on the physical USB device. We can function without this. - * But with imperfect damage info we may send pixels over USB - * that were, in fact, unchanged - wasting limited USB bandwidth - */ - new_back = vmalloc(new_len); - if (!new_back) - dl_info("No shadow/backing buffer allcoated\n"); - else { - if (dev->backing_buffer) - vfree(dev->backing_buffer); - dev->backing_buffer = new_back; - memset(dev->backing_buffer, 0, new_len); - } - } - - retval = 0; - -error: - return retval; -} - -/* - * 1) Get EDID from hw, or use sw default - * 2) Parse into various fb_info structs - * 3) Allocate virtual framebuffer memory to back highest res mode - * - * Parses EDID into three places used by various parts of fbdev: - * fb_var_screeninfo contains the timing of the monitor's preferred mode - * fb_info.monspecs is full parsed EDID info, including monspecs.modedb - * fb_info.modelist is a linked list of all monitor & VESA modes which work - * - * If EDID is not readable/valid, then modelist is all VESA modes, - * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode - * Returns 0 if successful - */ -static int dlfb_setup_modes(struct dlfb_data *dev, - struct fb_info *info, - char *default_edid, size_t default_edid_size) -{ - int i; - const struct fb_videomode *default_vmode = NULL; - int result = 0; - char *edid; - int tries = 3; - - if (info->dev) /* only use mutex if info has been registered */ - mutex_lock(&info->lock); - - edid = kmalloc(MAX_EDID_SIZE, GFP_KERNEL); - if (!edid) { - result = -ENOMEM; - goto error; - } - - fb_destroy_modelist(&info->modelist); - memset(&info->monspecs, 0, sizeof(info->monspecs)); - - /* - * Try to (re)read EDID from hardware first - * EDID data may return, but not parse as valid - * Try again a few times, in case of e.g. analog cable noise - */ - while (tries--) { - - i = dlfb_get_edid(dev, edid, MAX_EDID_SIZE); - - if (i >= MIN_EDID_SIZE) - fb_edid_to_monspecs(edid, &info->monspecs); - - if (info->monspecs.modedb_len > 0) { - dev->edid = edid; - dev->edid_size = i; - break; - } - } - - /* If that fails, use a previously returned EDID if available */ - if (info->monspecs.modedb_len == 0) { - - dl_err("Unable to get valid EDID from device/display\n"); - - if (dev->edid) { - fb_edid_to_monspecs(dev->edid, &info->monspecs); - if (info->monspecs.modedb_len > 0) - dl_err("Using previously queried EDID\n"); - } - } - - /* If that fails, use the default EDID we were handed */ - if (info->monspecs.modedb_len == 0) { - if (default_edid_size >= MIN_EDID_SIZE) { - fb_edid_to_monspecs(default_edid, &info->monspecs); - if (info->monspecs.modedb_len > 0) { - memcpy(edid, default_edid, default_edid_size); - dev->edid = edid; - dev->edid_size = default_edid_size; - dl_err("Using default/backup EDID\n"); - } - } - } - - /* If we've got modes, let's pick a best default mode */ - if (info->monspecs.modedb_len > 0) { - - for (i = 0; i < info->monspecs.modedb_len; i++) { - if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info)) - fb_add_videomode(&info->monspecs.modedb[i], - &info->modelist); - else /* if we've removed top/best mode */ - info->monspecs.misc &= ~FB_MISC_1ST_DETAIL; - } - - default_vmode = fb_find_best_display(&info->monspecs, - &info->modelist); - } - - /* If everything else has failed, fall back to safe default mode */ - if (default_vmode == NULL) { - - struct fb_videomode fb_vmode = {0}; - - /* - * Add the standard VESA modes to our modelist - * Since we don't have EDID, there may be modes that - * overspec monitor and/or are incorrect aspect ratio, etc. - * But at least the user has a chance to choose - */ - for (i = 0; i < VESA_MODEDB_SIZE; i++) { - if (dlfb_is_valid_mode((struct fb_videomode *) - &vesa_modes[i], info)) - fb_add_videomode(&vesa_modes[i], - &info->modelist); - } - - /* - * default to resolution safe for projectors - * (since they are most common case without EDID) - */ - fb_vmode.xres = 800; - fb_vmode.yres = 600; - fb_vmode.refresh = 60; - default_vmode = fb_find_nearest_mode(&fb_vmode, - &info->modelist); - } - - /* If we have good mode and no active clients*/ - if ((default_vmode != NULL) && (dev->fb_count == 0)) { - - fb_videomode_to_var(&info->var, default_vmode); - dlfb_var_color_format(&info->var); - - /* - * with mode size info, we can now alloc our framebuffer. - */ - memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix)); - info->fix.line_length = info->var.xres * - (info->var.bits_per_pixel / 8); - - result = dlfb_realloc_framebuffer(dev, info); - - } else - result = -EINVAL; - -error: - if (edid && (dev->edid != edid)) - kfree(edid); - - if (info->dev) - mutex_unlock(&info->lock); - - return result; -} - -static ssize_t metrics_bytes_rendered_show(struct device *fbdev, - struct device_attribute *a, char *buf) { - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_rendered)); -} - -static ssize_t metrics_bytes_identical_show(struct device *fbdev, - struct device_attribute *a, char *buf) { - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_identical)); -} - -static ssize_t metrics_bytes_sent_show(struct device *fbdev, - struct device_attribute *a, char *buf) { - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->bytes_sent)); -} - -static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev, - struct device_attribute *a, char *buf) { - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - return snprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&dev->cpu_kcycles_used)); -} - -static ssize_t edid_show( - struct file *filp, - struct kobject *kobj, struct bin_attribute *a, - char *buf, loff_t off, size_t count) { - struct device *fbdev = container_of(kobj, struct device, kobj); - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - - if (dev->edid == NULL) - return 0; - - if ((off >= dev->edid_size) || (count > dev->edid_size)) - return 0; - - if (off + count > dev->edid_size) - count = dev->edid_size - off; - - dl_info("sysfs edid copy %p to %p, %d bytes\n", - dev->edid, buf, (int) count); - - memcpy(buf, dev->edid, count); - - return count; -} - -static ssize_t edid_store( - struct file *filp, - struct kobject *kobj, struct bin_attribute *a, - char *src, loff_t src_off, size_t src_size) { - struct device *fbdev = container_of(kobj, struct device, kobj); - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - - /* We only support write of entire EDID at once, no offset*/ - if ((src_size < MIN_EDID_SIZE) || - (src_size > MAX_EDID_SIZE) || - (src_off != 0)) - return 0; - - dlfb_setup_modes(dev, fb_info, src, src_size); - - if (dev->edid && (memcmp(src, dev->edid, src_size) == 0)) { - dl_info("sysfs written EDID is new default\n"); - dlfb_ops_set_par(fb_info); - return src_size; - } else - return 0; -} - -static ssize_t metrics_reset_store(struct device *fbdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fb_info *fb_info = dev_get_drvdata(fbdev); - struct dlfb_data *dev = fb_info->par; - - atomic_set(&dev->bytes_rendered, 0); - atomic_set(&dev->bytes_identical, 0); - atomic_set(&dev->bytes_sent, 0); - atomic_set(&dev->cpu_kcycles_used, 0); - - return count; -} - -static struct bin_attribute edid_attr = { - .attr.name = "edid", - .attr.mode = 0666, - .size = MAX_EDID_SIZE, - .read = edid_show, - .write = edid_store -}; - -static struct device_attribute fb_device_attrs[] = { - __ATTR_RO(metrics_bytes_rendered), - __ATTR_RO(metrics_bytes_identical), - __ATTR_RO(metrics_bytes_sent), - __ATTR_RO(metrics_cpu_kcycles_used), - __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store), -}; - -/* - * This is necessary before we can communicate with the display controller. - */ -static int dlfb_select_std_channel(struct dlfb_data *dev) -{ - int ret; - u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7, - 0x1C, 0x88, 0x5E, 0x15, - 0x60, 0xFE, 0xC6, 0x97, - 0x16, 0x3D, 0x47, 0xF2 }; - - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - NR_USB_REQUEST_CHANNEL, - (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0, - set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT); - return ret; -} - -static int dlfb_parse_vendor_descriptor(struct dlfb_data *dev, - struct usb_device *usbdev) -{ - char *desc; - char *buf; - char *desc_end; - - u8 total_len = 0; - - buf = kzalloc(MAX_VENDOR_DESCRIPTOR_SIZE, GFP_KERNEL); - if (!buf) - return false; - desc = buf; - - total_len = usb_get_descriptor(usbdev, 0x5f, /* vendor specific */ - 0, desc, MAX_VENDOR_DESCRIPTOR_SIZE); - if (total_len > 5) { - dl_info("vendor descriptor length:%x data:%02x %02x %02x %02x" \ - "%02x %02x %02x %02x %02x %02x %02x\n", - total_len, desc[0], - desc[1], desc[2], desc[3], desc[4], desc[5], desc[6], - desc[7], desc[8], desc[9], desc[10]); - - if ((desc[0] != total_len) || /* descriptor length */ - (desc[1] != 0x5f) || /* vendor descriptor type */ - (desc[2] != 0x01) || /* version (2 bytes) */ - (desc[3] != 0x00) || - (desc[4] != total_len - 2)) /* length after type */ - goto unrecognized; - - desc_end = desc + total_len; - desc += 5; /* the fixed header we've already parsed */ - - while (desc < desc_end) { - u8 length; - u16 key; - - key = *((u16 *) desc); - desc += sizeof(u16); - length = *desc; - desc++; - - switch (key) { - case 0x0200: { /* max_area */ - u32 max_area; - max_area = le32_to_cpu(*((u32 *)desc)); - dl_warn("DL chip limited to %d pixel modes\n", - max_area); - dev->sku_pixel_limit = max_area; - break; - } - default: - break; - } - desc += length; - } - } - - goto success; - -unrecognized: - /* allow udlfb to load for now even if firmware unrecognized */ - dl_err("Unrecognized vendor firmware descriptor\n"); - -success: - kfree(buf); - return true; -} -static int dlfb_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - struct dlfb_data *dev = 0; - struct fb_info *info = 0; - int retval = -ENOMEM; - int i; - - /* usb initialization */ - - usbdev = interface_to_usbdev(interface); - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - err("dlfb_usb_probe: failed alloc of dev struct\n"); - goto error; - } - - /* we need to wait for both usb and fbdev to spin down on disconnect */ - kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */ - kref_get(&dev->kref); /* matching kref_put in free_framebuffer_work */ - - dev->udev = usbdev; - dev->gdev = &usbdev->dev; /* our generic struct device * */ - usb_set_intfdata(interface, dev); - - dl_info("%s %s - serial #%s\n", - usbdev->manufacturer, usbdev->product, usbdev->serial); - dl_info("vid_%04x&pid_%04x&rev_%04x driver's dlfb_data struct at %p\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, - usbdev->descriptor.bcdDevice, dev); - dl_info("console enable=%d\n", console); - dl_info("fb_defio enable=%d\n", fb_defio); - - dev->sku_pixel_limit = 2048 * 1152; /* default to maximum */ - - if (!dlfb_parse_vendor_descriptor(dev, usbdev)) { - dl_err("firmware not recognized. Assume incompatible device\n"); - goto error; - } - - if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) { - retval = -ENOMEM; - dl_err("dlfb_alloc_urb_list failed\n"); - goto error; - } - - /* We don't register a new USB class. Our client interface is fbdev */ - - /* allocates framebuffer driver structure, not framebuffer memory */ - info = framebuffer_alloc(0, &usbdev->dev); - if (!info) { - retval = -ENOMEM; - dl_err("framebuffer_alloc failed\n"); - goto error; - } - - dev->info = info; - info->par = dev; - info->pseudo_palette = dev->pseudo_palette; - info->fbops = &dlfb_ops; - - retval = fb_alloc_cmap(&info->cmap, 256, 0); - if (retval < 0) { - dl_err("fb_alloc_cmap failed %x\n", retval); - goto error; - } - - INIT_DELAYED_WORK(&dev->free_framebuffer_work, - dlfb_free_framebuffer_work); - - INIT_LIST_HEAD(&info->modelist); - - retval = dlfb_setup_modes(dev, info, NULL, 0); - if (retval != 0) { - dl_err("unable to find common mode for display and adapter\n"); - goto error; - } - - /* ready to begin using device */ - - atomic_set(&dev->usb_active, 1); - dlfb_select_std_channel(dev); - - dlfb_ops_check_var(&info->var, info); - dlfb_ops_set_par(info); - - retval = register_framebuffer(info); - if (retval < 0) { - dl_err("register_framebuffer failed %d\n", retval); - goto error; - } - - for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) - device_create_file(info->dev, &fb_device_attrs[i]); - - device_create_bin_file(info->dev, &edid_attr); - - dl_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution." - " Using %dK framebuffer memory\n", info->node, - info->var.xres, info->var.yres, - ((dev->backing_buffer) ? - info->fix.smem_len * 2 : info->fix.smem_len) >> 10); - return 0; - -error: - if (dev) { - - if (info) { - if (info->cmap.len != 0) - fb_dealloc_cmap(&info->cmap); - if (info->monspecs.modedb) - fb_destroy_modedb(info->monspecs.modedb); - if (info->screen_base) - vfree(info->screen_base); - - fb_destroy_modelist(&info->modelist); - - framebuffer_release(info); - } - - if (dev->backing_buffer) - vfree(dev->backing_buffer); - - kref_put(&dev->kref, dlfb_free); /* ref for framebuffer */ - kref_put(&dev->kref, dlfb_free); /* last ref from kref_init */ - - /* dev has been deallocated. Do not dereference */ - } - - return retval; -} - -static void dlfb_usb_disconnect(struct usb_interface *interface) -{ - struct dlfb_data *dev; - struct fb_info *info; - int i; - - dev = usb_get_intfdata(interface); - info = dev->info; - - dl_info("USB disconnect starting\n"); - - /* we virtualize until all fb clients release. Then we free */ - dev->virtualized = true; - - /* When non-active we'll update virtual framebuffer, but no new urbs */ - atomic_set(&dev->usb_active, 0); - - /* remove udlfb's sysfs interfaces */ - for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) - device_remove_file(info->dev, &fb_device_attrs[i]); - device_remove_bin_file(info->dev, &edid_attr); - - usb_set_intfdata(interface, NULL); - - /* if clients still have us open, will be freed on last close */ - if (dev->fb_count == 0) - schedule_delayed_work(&dev->free_framebuffer_work, 0); - - /* release reference taken by kref_init in probe() */ - kref_put(&dev->kref, dlfb_free); - - /* consider dlfb_data freed */ - - return; -} - -static struct usb_driver dlfb_driver = { - .name = "udlfb", - .probe = dlfb_usb_probe, - .disconnect = dlfb_usb_disconnect, - .id_table = id_table, -}; - -static int __init dlfb_module_init(void) -{ - int res; - - res = usb_register(&dlfb_driver); - if (res) - err("usb_register failed. Error number %d", res); - - return res; -} - -static void __exit dlfb_module_exit(void) -{ - usb_deregister(&dlfb_driver); -} - -module_init(dlfb_module_init); -module_exit(dlfb_module_exit); - -static void dlfb_urb_completion(struct urb *urb) -{ - struct urb_node *unode = urb->context; - struct dlfb_data *dev = unode->dev; - unsigned long flags; - - /* sync/async unlink faults aren't errors */ - if (urb->status) { - if (!(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) { - dl_err("%s - nonzero write bulk status received: %d\n", - __func__, urb->status); - atomic_set(&dev->lost_pixels, 1); - } - } - - urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */ - - spin_lock_irqsave(&dev->urbs.lock, flags); - list_add_tail(&unode->entry, &dev->urbs.list); - dev->urbs.available++; - spin_unlock_irqrestore(&dev->urbs.lock, flags); - - /* - * When using fb_defio, we deadlock if up() is called - * while another is waiting. So queue to another process. - */ - if (fb_defio) - schedule_delayed_work(&unode->release_urb_work, 0); - else - up(&dev->urbs.limit_sem); -} - -static void dlfb_free_urb_list(struct dlfb_data *dev) -{ - int count = dev->urbs.count; - struct list_head *node; - struct urb_node *unode; - struct urb *urb; - int ret; - unsigned long flags; - - dl_notice("Waiting for completes and freeing all render urbs\n"); - - /* keep waiting and freeing, until we've got 'em all */ - while (count--) { - - /* Getting interrupted means a leak, but ok at shutdown*/ - ret = down_interruptible(&dev->urbs.limit_sem); - if (ret) - break; - - spin_lock_irqsave(&dev->urbs.lock, flags); - - node = dev->urbs.list.next; /* have reserved one with sem */ - list_del_init(node); - - spin_unlock_irqrestore(&dev->urbs.lock, flags); - - unode = list_entry(node, struct urb_node, entry); - urb = unode->urb; - - /* Free each separately allocated piece */ - usb_free_coherent(urb->dev, dev->urbs.size, - urb->transfer_buffer, urb->transfer_dma); - usb_free_urb(urb); - kfree(node); - } - -} - -static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size) -{ - int i = 0; - struct urb *urb; - struct urb_node *unode; - char *buf; - - spin_lock_init(&dev->urbs.lock); - - dev->urbs.size = size; - INIT_LIST_HEAD(&dev->urbs.list); - - while (i < count) { - unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL); - if (!unode) - break; - unode->dev = dev; - - INIT_DELAYED_WORK(&unode->release_urb_work, - dlfb_release_urb_work); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - kfree(unode); - break; - } - unode->urb = urb; - - buf = usb_alloc_coherent(dev->udev, MAX_TRANSFER, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - kfree(unode); - usb_free_urb(urb); - break; - } - - /* urb->transfer_buffer_length set to actual before submit */ - usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1), - buf, size, dlfb_urb_completion, unode); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - list_add_tail(&unode->entry, &dev->urbs.list); - - i++; - } - - sema_init(&dev->urbs.limit_sem, i); - dev->urbs.count = i; - dev->urbs.available = i; - - dl_notice("allocated %d %d byte urbs\n", i, (int) size); - - return i; -} - -static struct urb *dlfb_get_urb(struct dlfb_data *dev) -{ - int ret = 0; - struct list_head *entry; - struct urb_node *unode; - struct urb *urb = NULL; - unsigned long flags; - - /* Wait for an in-flight buffer to complete and get re-queued */ - ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT); - if (ret) { - atomic_set(&dev->lost_pixels, 1); - dl_warn("wait for urb interrupted: %x available: %d\n", - ret, dev->urbs.available); - goto error; - } - - spin_lock_irqsave(&dev->urbs.lock, flags); - - BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */ - entry = dev->urbs.list.next; - list_del_init(entry); - dev->urbs.available--; - - spin_unlock_irqrestore(&dev->urbs.lock, flags); - - unode = list_entry(entry, struct urb_node, entry); - urb = unode->urb; - -error: - return urb; -} - -static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len) -{ - int ret; - - BUG_ON(len > dev->urbs.size); - - urb->transfer_buffer_length = len; /* set to actual payload len */ - ret = usb_submit_urb(urb, GFP_KERNEL); - if (ret) { - dlfb_urb_completion(urb); /* because no one else will */ - atomic_set(&dev->lost_pixels, 1); - dl_err("usb_submit_urb error %x\n", ret); - } - return ret; -} - -module_param(console, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); -MODULE_PARM_DESC(console, "Allow fbcon to consume first framebuffer found"); - -module_param(fb_defio, bool, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); -MODULE_PARM_DESC(fb_defio, "Enable fb_defio mmap support. *Experimental*"); - -MODULE_AUTHOR("Roberto De Ioris , " - "Jaya Kumar , " - "Bernie Thompson "); -MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/udlfb/udlfb.h b/drivers/staging/udlfb/udlfb.h deleted file mode 100644 index 6f9785e9d62e..000000000000 --- a/drivers/staging/udlfb/udlfb.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef UDLFB_H -#define UDLFB_H - -/* - * TODO: Propose standard fb.h ioctl for reporting damage, - * using _IOWR() and one of the existing area structs from fb.h - * Consider these ioctls deprecated, but they're still used by the - * DisplayLink X server as yet - need both to be modified in tandem - * when new ioctl(s) are ready. - */ -#define DLFB_IOCTL_RETURN_EDID 0xAD -#define DLFB_IOCTL_REPORT_DAMAGE 0xAA -struct dloarea { - int x, y; - int w, h; - int x2, y2; -}; - -struct urb_node { - struct list_head entry; - struct dlfb_data *dev; - struct delayed_work release_urb_work; - struct urb *urb; -}; - -struct urb_list { - struct list_head list; - spinlock_t lock; - struct semaphore limit_sem; - int available; - int count; - size_t size; -}; - -struct dlfb_data { - struct usb_device *udev; - struct device *gdev; /* &udev->dev */ - struct fb_info *info; - struct urb_list urbs; - struct kref kref; - char *backing_buffer; - int fb_count; - bool virtualized; /* true when physical usb device not present */ - struct delayed_work free_framebuffer_work; - atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */ - atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */ - char *edid; /* null until we read edid from hw or get from sysfs */ - size_t edid_size; - int sku_pixel_limit; - int base16; - int base8; - u32 pseudo_palette[256]; - /* blit-only rendering path metrics, exposed through sysfs */ - atomic_t bytes_rendered; /* raw pixel-bytes driver asked to render */ - atomic_t bytes_identical; /* saved effort with backbuffer comparison */ - atomic_t bytes_sent; /* to usb, after compression including overhead */ - atomic_t cpu_kcycles_used; /* transpired during pixel processing */ -}; - -#define NR_USB_REQUEST_I2C_SUB_IO 0x02 -#define NR_USB_REQUEST_CHANNEL 0x12 - -/* -BULK_SIZE as per usb-skeleton. Can we get full page and avoid overhead? */ -#define BULK_SIZE 512 -#define MAX_TRANSFER (PAGE_SIZE*16 - BULK_SIZE) -#define WRITES_IN_FLIGHT (4) - -#define MIN_EDID_SIZE 128 -#define MAX_EDID_SIZE 128 - -#define MAX_VENDOR_DESCRIPTOR_SIZE 256 - -#define GET_URB_TIMEOUT HZ -#define FREE_URB_TIMEOUT (HZ*2) - -#define BPP 2 -#define MAX_CMD_PIXELS 255 - -#define RLX_HEADER_BYTES 7 -#define MIN_RLX_PIX_BYTES 4 -#define MIN_RLX_CMD_BYTES (RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES) - -#define RLE_HEADER_BYTES 6 -#define MIN_RLE_PIX_BYTES 3 -#define MIN_RLE_CMD_BYTES (RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES) - -#define RAW_HEADER_BYTES 6 -#define MIN_RAW_PIX_BYTES 2 -#define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES) - -#define DL_DEFIO_WRITE_DELAY 5 /* fb_deferred_io.delay in jiffies */ -#define DL_DEFIO_WRITE_DISABLE (HZ*60) /* "disable" with long delay */ - -/* remove these once align.h patch is taken into kernel */ -#define DL_ALIGN_UP(x, a) ALIGN(x, a) -#define DL_ALIGN_DOWN(x, a) ALIGN(x-(a-1), a) - -/* remove once this gets added to sysfs.h */ -#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store) - -/* - * udlfb is both a usb device, and a framebuffer device. - * They may exist at the same time, but during various stages - * inactivity, teardown, or "virtual" operation, only one or the - * other will exist (one will outlive the other). So we can't - * call the dev_*() macros, because we don't have a stable dev object. - */ -#define dl_err(format, arg...) \ - pr_err("udlfb: " format, ## arg) -#define dl_warn(format, arg...) \ - pr_warning("udlfb: " format, ## arg) -#define dl_notice(format, arg...) \ - pr_notice("udlfb: " format, ## arg) -#define dl_info(format, arg...) \ - pr_info("udlfb: " format, ## arg) - -#endif diff --git a/drivers/staging/udlfb/udlfb.txt b/drivers/staging/udlfb/udlfb.txt deleted file mode 100644 index 7fdde2a02a27..000000000000 --- a/drivers/staging/udlfb/udlfb.txt +++ /dev/null @@ -1,144 +0,0 @@ - -What is udlfb? -=============== - -This is a driver for DisplayLink USB 2.0 era graphics chips. - -DisplayLink chips provide simple hline/blit operations with some compression, -pairing that with a hardware framebuffer (16MB) on the other end of the -USB wire. That hardware framebuffer is able to drive the VGA, DVI, or HDMI -monitor with no CPU involvement until a pixel has to change. - -The CPU or other local resource does all the rendering; optinally compares the -result with a local shadow of the remote hardware framebuffer to identify -the minimal set of pixels that have changed; and compresses and sends those -pixels line-by-line via USB bulk transfers. - -Because of the efficiency of bulk transfers and a protocol on top that -does not require any acks - the effect is very low latency that -can support surprisingly high resolutions with good performance for -non-gaming and non-video applications. - -Mode setting, EDID read, etc are other bulk or control transfers. Mode -setting is very flexible - able to set nearly arbitrary modes from any timing. - -Advantages of USB graphics in general: - - * Ability to add a nearly arbitrary number of displays to any USB 2.0 - capable system. On Linux, number of displays is limited by fbdev interface - (FB_MAX is currently 32). Of course, all USB devices on the same - host controller share the same 480Mbs USB 2.0 interface. - -Advantages of supporting DisplayLink chips with kernel framebuffer interface: - - * The actual hardware functionality of DisplayLink chips matches nearly - one-to-one with the fbdev interface, making the driver quite small and - tight relative to the functionality it provides. - * X servers and other applications can use the standard fbdev interface - from user mode to talk to the device, without needing to know anything - about USB or DisplayLink's protocol at all. A "displaylink" X driver - and a slightly modified "fbdev" X driver are among those that already do. - -Disadvantages: - - * Fbdev's mmap interface assumes a real hardware framebuffer is mapped. - In the case of USB graphics, it is just an allocated (virtual) buffer. - Writes need to be detected and encoded into USB bulk transfers by the CPU. - Accurate damage/changed area notifications work around this problem. - In the future, hopefully fbdev will be enhanced with an small standard - interface to allow mmap clients to report damage, for the benefit - of virtual or remote framebuffers. - * Fbdev does not arbitrate client ownership of the framebuffer well. - * Fbcon assumes the first framebuffer it finds should be consumed for console. - * It's not clear what the future of fbdev is, given the rise of KMS/DRM. - -How to use it? -============== - -Udlfb, when loaded as a module, will match against all USB 2.0 generation -DisplayLink chips (Alex and Ollie family). It will then attempt to read the EDID -of the monitor, and set the best common mode between the DisplayLink device -and the monitor's capabilities. - -If the DisplayLink device is successful, it will paint a "green screen" which -means that from a hardware and fbdev software perspective, everything is good. - -At that point, a /dev/fb? interface will be present for user-mode applications -to open and begin writing to the framebuffer of the DisplayLink device using -standard fbdev calls. Note that if mmap() is used, by default the user mode -application must send down damage notifcations to trigger repaints of the -changed regions. Alternatively, udlfb can be recompiled with experimental -defio support enabled, to support a page-fault based detection mechanism -that can work without explicit notifcation. - -The most common client of udlfb is xf86-video-displaylink or a modified -xf86-video-fbdev X server. These servers have no real DisplayLink specific -code. They write to the standard framebuffer interface and rely on udlfb -to do its thing. The one extra feature they have is the ability to report -rectangles from the X DAMAGE protocol extension down to udlfb via udlfb's -damage interface (which will hopefully be standardized for all virtual -framebuffers that need damage info). These damage notifications allow -udlfb to efficiently process the changed pixels. - -Module Options -============== - -Special configuration for udlfb is usually unnecessary. There are a few -options, however. - -From the command line, pass options to modprobe -modprobe udlfb defio=1 console=1 - -Or for permanent option, create file like /etc/modprobe.d/options with text -options udlfb defio=1 console=1 - -Accepted options: - -fb_defio Make use of the fb_defio (CONFIG_FB_DEFERRED_IO) kernel - module to track changed areas of the framebuffer by page faults. - Standard fbdev applications that use mmap but that do not - report damage, may be able to work with this enabled. - Disabled by default because of overhead and other issues. - -console Allow fbcon to attach to udlfb provided framebuffers. This - is disabled by default because fbcon will aggressively consume - the first framebuffer it finds, which isn't usually what the - user wants in the case of USB displays. - -Sysfs Attributes -================ - -Udlfb creates several files in /sys/class/graphics/fb? -Where ? is the sequential framebuffer id of the particular DisplayLink device - -edid If a valid EDID blob is written to this file (typically - by a udev rule), then udlfb will use this EDID as a - backup in case reading the actual EDID of the monitor - attached to the DisplayLink device fails. This is - especially useful for fixed panels, etc. that cannot - communicate their capabilities via EDID. Reading - this file returns the current EDID of the attached - monitor (or last backup value written). This is - useful to get the EDID of the attached monitor, - which can be passed to utilities like parse-edid. - -metrics_bytes_rendered 32-bit count of pixel bytes rendered - -metrics_bytes_identical 32-bit count of how many of those bytes were found to be - unchanged, based on a shadow framebuffer check - -metrics_bytes_sent 32-bit count of how many bytes were transferred over - USB to communicate the resulting changed pixels to the - hardware. Includes compression and protocol overhead - -metrics_cpu_kcycles_used 32-bit count of CPU cycles used in processing the - above pixels (in thousands of cycles). - -metrics_reset Write-only. Any write to this file resets all metrics - above to zero. Note that the 32-bit counters above - roll over very quickly. To get reliable results, design - performance tests to start and finish in a very short - period of time (one minute or less is safe). - --- -Bernie Thompson diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 27c1fb4b1e0d..37771d0916ef 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2034,6 +2034,20 @@ config FB_SM501 If unsure, say N. +config FB_UDL + tristate "Displaylink USB Framebuffer support" + depends on FB && USB + select FB_MODE_HELPERS + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select FB_DEFERRED_IO + ---help--- + This is a kernel framebuffer driver for DisplayLink USB devices. + Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and + mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. + To compile as a module, choose M here: the module name is udlfb. config FB_PNX4008_DUM tristate "Display Update Module support on Philips PNX4008 board" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 485e8ed1318c..03678e3021ab 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -122,6 +122,7 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o obj-$(CONFIG_FB_SM501) += sm501fb.o +obj-$(CONFIG_FB_UDL) += udlfb.o obj-$(CONFIG_FB_XILINX) += xilinxfb.o obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c new file mode 100644 index 000000000000..0cca4873d490 --- /dev/null +++ b/drivers/video/udlfb.c @@ -0,0 +1,1915 @@ +/* + * udlfb.c -- Framebuffer driver for DisplayLink USB controller + * + * Copyright (C) 2009 Roberto De Ioris + * Copyright (C) 2009 Jaya Kumar + * Copyright (C) 2009 Bernie Thompson + * + * This file is subject to the terms and conditions of the GNU General Public + * License v2. See the file COPYING in the main directory of this archive for + * more details. + * + * Layout is based on skeletonfb by James Simmons and Geert Uytterhoeven, + * usb-skeleton by GregKH. + * + * Device-specific portions based on information from Displaylink, with work + * from Florian Echtler, Henrik Bjerregaard Pedersen, and others. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include