From 892b6f90db81cccb723d5d92f4fddc2d68b206e1 Mon Sep 17 00:00:00 2001 From: Martin K. Petersen Date: Wed, 13 Oct 2010 21:18:03 +0200 Subject: block: Ensure physical block size is unsigned int From: Martin K. Petersen commit 892b6f90db81cccb723d5d92f4fddc2d68b206e1 upstream. Physical block size was declared unsigned int to accomodate the maximum size reported by READ CAPACITY(16). Make sure we use the right type in the related functions. Signed-off-by: Martin K. Petersen Acked-by: Mike Snitzer Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-settings.c | 2 +- include/linux/blkdev.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -343,7 +343,7 @@ EXPORT_SYMBOL(blk_queue_logical_block_si * hardware can operate on without reverting to read-modify-write * operations. */ -void blk_queue_physical_block_size(struct request_queue *q, unsigned short size) +void blk_queue_physical_block_size(struct request_queue *q, unsigned int size) { q->limits.physical_block_size = size; --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -851,7 +851,7 @@ extern void blk_queue_max_segment_size(s extern void blk_queue_max_discard_sectors(struct request_queue *q, unsigned int max_discard_sectors); extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); -extern void blk_queue_physical_block_size(struct request_queue *, unsigned short); +extern void blk_queue_physical_block_size(struct request_queue *, unsigned int); extern void blk_queue_alignment_offset(struct request_queue *q, unsigned int alignment); extern void blk_limits_io_min(struct queue_limits *limits, unsigned int min); @@ -1004,7 +1004,7 @@ static inline unsigned int queue_physica return q->limits.physical_block_size; } -static inline int bdev_physical_block_size(struct block_device *bdev) +static inline unsigned int bdev_physical_block_size(struct block_device *bdev) { return queue_physical_block_size(bdev_get_queue(bdev)); } From 7681bfeeccff5efa9eb29bf09249a3c400b15327 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Tue, 19 Oct 2010 09:05:00 +0200 Subject: block: fix accounting bug on cross partition merges From: Yasuaki Ishimatsu commit 7681bfeeccff5efa9eb29bf09249a3c400b15327 upstream. /proc/diskstats would display a strange output as follows. $ cat /proc/diskstats |grep sda 8 0 sda 90524 7579 102154 20464 0 0 0 0 0 14096 20089 8 1 sda1 19085 1352 21841 4209 0 0 0 0 4294967064 15689 4293424691 ~~~~~~~~~~ 8 2 sda2 71252 3624 74891 15950 0 0 0 0 232 23995 1562390 8 3 sda3 54 487 2188 92 0 0 0 0 0 88 92 8 4 sda4 4 0 8 0 0 0 0 0 0 0 0 8 5 sda5 81 2027 2130 138 0 0 0 0 0 87 137 Its reason is the wrong way of accounting hd_struct->in_flight. When a bio is merged into a request belongs to different partition by ELEVATOR_FRONT_MERGE. The detailed root cause is as follows. Assuming that there are two partition, sda1 and sda2. 1. A request for sda2 is in request_queue. Hence sda1's hd_struct->in_flight is 0 and sda2's one is 1. | hd_struct->in_flight --------------------------- sda1 | 0 sda2 | 1 --------------------------- 2. A bio belongs to sda1 is issued and is merged into the request mentioned on step1 by ELEVATOR_BACK_MERGE. The first sector of the request is changed from sda2 region to sda1 region. However the two partition's hd_struct->in_flight are not changed. | hd_struct->in_flight --------------------------- sda1 | 0 sda2 | 1 --------------------------- 3. The request is finished and blk_account_io_done() is called. In this case, sda2's hd_struct->in_flight, not a sda1's one, is decremented. | hd_struct->in_flight --------------------------- sda1 | -1 sda2 | 1 --------------------------- The patch fixes the problem by caching the partition lookup inside the request structure, hence making sure that the increment and decrement will always happen on the same partition struct. This also speeds up IO with accounting enabled, since it cuts down on the number of lookups we have to do. When reloading partition tables, quiesce IO to ensure that no request references to the partition struct exists. When it is safe to free the partition table, the IO for that device is restarted again. Signed-off-by: Yasuaki Ishimatsu Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-core.c | 24 ++++++++++++++++-------- block/blk-merge.c | 2 +- block/blk.h | 4 ---- block/genhd.c | 14 ++++++++++++++ fs/partitions/check.c | 12 ++++++++++++ include/linux/blkdev.h | 1 + include/linux/elevator.h | 2 ++ include/linux/genhd.h | 1 + 8 files changed, 47 insertions(+), 13 deletions(-) --- a/block/blk-core.c +++ b/block/blk-core.c @@ -64,13 +64,15 @@ static void drive_stat_acct(struct reque return; cpu = part_stat_lock(); - part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); - if (!new_io) + if (!new_io) { + part = rq->part; part_stat_inc(cpu, part, merges[rw]); - else { + } else { + part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); part_round_stats(cpu, part); part_inc_in_flight(part, rw); + rq->part = part; } part_stat_unlock(); @@ -128,6 +130,7 @@ void blk_rq_init(struct request_queue *q rq->ref_count = 1; rq->start_time = jiffies; set_start_time_ns(rq); + rq->part = NULL; } EXPORT_SYMBOL(blk_rq_init); @@ -796,11 +799,16 @@ static struct request *get_request(struc rl->starved[is_sync] = 0; priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags); - if (priv) + if (priv) { rl->elvpriv++; - if (blk_queue_io_stat(q)) - rw_flags |= REQ_IO_STAT; + /* + * Don't do stats for non-priv requests + */ + if (blk_queue_io_stat(q)) + rw_flags |= REQ_IO_STAT; + } + spin_unlock_irq(q->queue_lock); rq = blk_alloc_request(q, rw_flags, priv, gfp_mask); @@ -1759,7 +1767,7 @@ static void blk_account_io_completion(st int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); + part = req->part; part_stat_add(cpu, part, sectors[rw], bytes >> 9); part_stat_unlock(); } @@ -1779,7 +1787,7 @@ static void blk_account_io_done(struct r int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); + part = req->part; part_stat_inc(cpu, part, ios[rw]); part_stat_add(cpu, part, ticks[rw], duration); --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -343,7 +343,7 @@ static void blk_account_io_merge(struct int cpu; cpu = part_stat_lock(); - part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req)); + part = req->part; part_round_stats(cpu, part); part_dec_in_flight(part, rq_data_dir(req)); --- a/block/blk.h +++ b/block/blk.h @@ -110,10 +110,6 @@ void blk_queue_congestion_threshold(stru int blk_dev_init(void); -void elv_quiesce_start(struct request_queue *q); -void elv_quiesce_end(struct request_queue *q); - - /* * Return the threshold (number of used requests) at which the queue is * considered to be congested. It include a little hysteresis to keep the --- a/block/genhd.c +++ b/block/genhd.c @@ -925,8 +925,15 @@ static void disk_free_ptbl_rcu_cb(struct { struct disk_part_tbl *ptbl = container_of(head, struct disk_part_tbl, rcu_head); + struct gendisk *disk = ptbl->disk; + struct request_queue *q = disk->queue; + unsigned long flags; kfree(ptbl); + + spin_lock_irqsave(q->queue_lock, flags); + elv_quiesce_end(q); + spin_unlock_irqrestore(q->queue_lock, flags); } /** @@ -944,11 +951,17 @@ static void disk_replace_part_tbl(struct struct disk_part_tbl *new_ptbl) { struct disk_part_tbl *old_ptbl = disk->part_tbl; + struct request_queue *q = disk->queue; rcu_assign_pointer(disk->part_tbl, new_ptbl); if (old_ptbl) { rcu_assign_pointer(old_ptbl->last_lookup, NULL); + + spin_lock_irq(q->queue_lock); + elv_quiesce_start(q); + spin_unlock_irq(q->queue_lock); + call_rcu(&old_ptbl->rcu_head, disk_free_ptbl_rcu_cb); } } @@ -989,6 +1002,7 @@ int disk_expand_part_tbl(struct gendisk return -ENOMEM; new_ptbl->len = target; + new_ptbl->disk = disk; for (i = 0; i < len; i++) rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]); --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -364,17 +364,25 @@ struct device_type part_type = { static void delete_partition_rcu_cb(struct rcu_head *head) { struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); + struct gendisk *disk = part_to_disk(part); + struct request_queue *q = disk->queue; + unsigned long flags; part->start_sect = 0; part->nr_sects = 0; part_stat_set_all(part, 0); put_device(part_to_dev(part)); + + spin_lock_irqsave(q->queue_lock, flags); + elv_quiesce_end(q); + spin_unlock_irqrestore(q->queue_lock, flags); } void delete_partition(struct gendisk *disk, int partno) { struct disk_part_tbl *ptbl = disk->part_tbl; struct hd_struct *part; + struct request_queue *q = disk->queue; if (partno >= ptbl->len) return; @@ -389,6 +397,10 @@ void delete_partition(struct gendisk *di kobject_put(part->holder_dir); device_del(part_to_dev(part)); + spin_lock_irq(q->queue_lock); + elv_quiesce_start(q); + spin_unlock_irq(q->queue_lock); + call_rcu(&part->rcu_head, delete_partition_rcu_cb); } --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -115,6 +115,7 @@ struct request { void *elevator_private3; struct gendisk *rq_disk; + struct hd_struct *part; unsigned long start_time; #ifdef CONFIG_BLK_CGROUP unsigned long long start_time_ns; --- a/include/linux/elevator.h +++ b/include/linux/elevator.h @@ -122,6 +122,8 @@ extern void elv_completed_request(struct extern int elv_set_request(struct request_queue *, struct request *, gfp_t); extern void elv_put_request(struct request_queue *, struct request *); extern void elv_drain_elevator(struct request_queue *); +extern void elv_quiesce_start(struct request_queue *); +extern void elv_quiesce_end(struct request_queue *); /* * io scheduler registration --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -130,6 +130,7 @@ struct disk_part_tbl { struct rcu_head rcu_head; int len; struct hd_struct *last_lookup; + struct gendisk *disk; struct hd_struct *part[]; }; From 01ea50638bc04ca5259f5711fcdedefcdde1cf43 Mon Sep 17 00:00:00 2001 From: Signed-off-by: Jan Kara Date: Thu, 16 Sep 2010 20:36:36 +0200 Subject: block: Fix race during disk initialization From: Signed-off-by: Jan Kara commit 01ea50638bc04ca5259f5711fcdedefcdde1cf43 upstream. When a new disk is being discovered, add_disk() first ties the bdev to gendisk (via register_disk()->blkdev_get()) and only after that calls bdi_register_bdev(). Because register_disk() also creates disk's kobject, it can happen that userspace manages to open and modify the device's data (or inode) before its BDI is properly initialized leading to a warning in __mark_inode_dirty(). Fix the problem by registering BDI early enough. This patch addresses https://bugzilla.kernel.org/show_bug.cgi?id=16312 Reported-by: Larry Finger Signed-off-by: Jan Kara Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) --- a/block/genhd.c +++ b/block/genhd.c @@ -541,13 +541,15 @@ void add_disk(struct gendisk *disk) disk->major = MAJOR(devt); disk->first_minor = MINOR(devt); + /* Register BDI before referencing it from bdev */ + bdi = &disk->queue->backing_dev_info; + bdi_register_dev(bdi, disk_devt(disk)); + blk_register_region(disk_devt(disk), disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); - bdi = &disk->queue->backing_dev_info; - bdi_register_dev(bdi, disk_devt(disk)); retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, "bdi"); WARN_ON(retval); From f3f63c1c28bc861a931fac283b5bc3585efb8967 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 29 Oct 2010 11:46:56 -0600 Subject: block: limit vec count in bio_kmalloc() and bio_alloc_map_data() From: Jens Axboe commit f3f63c1c28bc861a931fac283b5bc3585efb8967 upstream. Reported-by: Dan Rosenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- fs/bio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) --- a/fs/bio.c +++ b/fs/bio.c @@ -370,6 +370,9 @@ struct bio *bio_kmalloc(gfp_t gfp_mask, { struct bio *bio; + if (nr_iovecs > UIO_MAXIOV) + return NULL; + bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec), gfp_mask); if (unlikely(!bio)) @@ -697,8 +700,12 @@ static void bio_free_map_data(struct bio static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count, gfp_t gfp_mask) { - struct bio_map_data *bmd = kmalloc(sizeof(*bmd), gfp_mask); + struct bio_map_data *bmd; + + if (iov_count > UIO_MAXIOV) + return NULL; + bmd = kmalloc(sizeof(*bmd), gfp_mask); if (!bmd) return NULL; From 9f864c80913467312c7b8690e41fb5ebd1b50e92 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 29 Oct 2010 11:31:42 -0600 Subject: block: take care not to overflow when calculating total iov length From: Jens Axboe commit 9f864c80913467312c7b8690e41fb5ebd1b50e92 upstream. Reported-by: Dan Rosenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/scsi_ioctl.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -321,33 +321,47 @@ static int sg_io(struct request_queue *q if (hdr->iovec_count) { const int size = sizeof(struct sg_iovec) * hdr->iovec_count; size_t iov_data_len; - struct sg_iovec *iov; + struct sg_iovec *sg_iov; + struct iovec *iov; + int i; - iov = kmalloc(size, GFP_KERNEL); - if (!iov) { + sg_iov = kmalloc(size, GFP_KERNEL); + if (!sg_iov) { ret = -ENOMEM; goto out; } - if (copy_from_user(iov, hdr->dxferp, size)) { - kfree(iov); + if (copy_from_user(sg_iov, hdr->dxferp, size)) { + kfree(sg_iov); ret = -EFAULT; goto out; } + /* + * Sum up the vecs, making sure they don't overflow + */ + iov = (struct iovec *) sg_iov; + iov_data_len = 0; + for (i = 0; i < hdr->iovec_count; i++) { + if (iov_data_len + iov[i].iov_len < iov_data_len) { + kfree(sg_iov); + ret = -EINVAL; + goto out; + } + iov_data_len += iov[i].iov_len; + } + /* SG_IO howto says that the shorter of the two wins */ - iov_data_len = iov_length((struct iovec *)iov, - hdr->iovec_count); if (hdr->dxfer_len < iov_data_len) { - hdr->iovec_count = iov_shorten((struct iovec *)iov, + hdr->iovec_count = iov_shorten(iov, hdr->iovec_count, hdr->dxfer_len); iov_data_len = hdr->dxfer_len; } - ret = blk_rq_map_user_iov(q, rq, NULL, iov, hdr->iovec_count, + ret = blk_rq_map_user_iov(q, rq, NULL, sg_iov, hdr->iovec_count, iov_data_len, GFP_KERNEL); - kfree(iov); + kfree(sg_iov); } else if (hdr->dxfer_len) ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, GFP_KERNEL); From 9284bcf4e335e5f18a8bc7b26461c33ab60d0689 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 29 Oct 2010 08:10:18 -0600 Subject: block: check for proper length of iov entries in blk_rq_map_user_iov() From: Jens Axboe commit 9284bcf4e335e5f18a8bc7b26461c33ab60d0689 upstream. Ensure that we pass down properly validated iov segments before calling into the mapping or copy functions. Reported-by: Dan Rosenberg Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-map.c | 2 ++ 1 file changed, 2 insertions(+) --- a/block/blk-map.c +++ b/block/blk-map.c @@ -205,6 +205,8 @@ int blk_rq_map_user_iov(struct request_q unaligned = 1; break; } + if (!iov[i].iov_len) + return -EINVAL; } if (unaligned || (q->dma_pad_mask & len) || map_data) From a0ae5864d42b41c411368bd689462bf063c029c8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 2 Nov 2010 05:26:48 +0000 Subject: drm/radeon/kms: don't disable shared encoders on pre-DCE3 display blocks From: Alex Deucher commit a0ae5864d42b41c411368bd689462bf063c029c8 upstream. The A/B links aren't independantly useable on these blocks so when we disable the encoders, make sure to only disable the encoder when there is no connector using it. Should fix: https://bugs.freedesktop.org/show_bug.cgi?id=18564 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_encoders.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1547,6 +1547,23 @@ static void radeon_atom_encoder_disable( struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig; + + /* check for pre-DCE3 cards with shared encoders; + * can't really use the links individually, so don't disable + * the encoder if it's in use by another connector + */ + if (!ASIC_IS_DCE3(rdev)) { + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + other_radeon_encoder = to_radeon_encoder(other_encoder); + if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && + drm_helper_encoder_in_use(other_encoder)) + goto disable_done; + } + } + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); switch (radeon_encoder->encoder_id) { @@ -1586,6 +1603,7 @@ static void radeon_atom_encoder_disable( break; } +disable_done: if (radeon_encoder_is_digital(encoder)) { if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) r600_hdmi_disable(encoder); From c8a8684d5cfb0f110a962c93586630c0bf91ebc1 Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Mon, 18 Oct 2010 14:10:40 +0000 Subject: jme: Fix PHY power-off error From: Guo-Fu Tseng commit c8a8684d5cfb0f110a962c93586630c0bf91ebc1 upstream. Adding phy_on in opposition to phy_off. Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/jme.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1575,6 +1575,16 @@ jme_free_irq(struct jme_adapter *jme) } } +static inline void +jme_phy_on(struct jme_adapter *jme) +{ + u32 bmcr; + + bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR); + bmcr &= ~BMCR_PDOWN; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr); +} + static int jme_open(struct net_device *netdev) { @@ -1595,10 +1605,12 @@ jme_open(struct net_device *netdev) jme_start_irq(jme); - if (test_bit(JME_FLAG_SSET, &jme->flags)) + if (test_bit(JME_FLAG_SSET, &jme->flags)) { + jme_phy_on(jme); jme_set_settings(netdev, &jme->old_ecmd); - else + } else { jme_reset_phy_processor(jme); + } jme_reset_link(jme); @@ -3006,10 +3018,12 @@ jme_resume(struct pci_dev *pdev) jme_clear_pm(jme); pci_restore_state(pdev); - if (test_bit(JME_FLAG_SSET, &jme->flags)) + if (test_bit(JME_FLAG_SSET, &jme->flags)) { + jme_phy_on(jme); jme_set_settings(netdev, &jme->old_ecmd); - else + } else { jme_reset_phy_processor(jme); + } jme_start_irq(jme); netif_device_attach(netdev); From efc463eb508798da4243625b08c7396462cabf9f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 11 Oct 2010 01:17:56 +0200 Subject: irda: Fix parameter extraction stack overflow From: Samuel Ortiz commit efc463eb508798da4243625b08c7396462cabf9f upstream. Reported-by: Ilja Van Sprundel Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- net/irda/parameters.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) --- a/net/irda/parameters.c +++ b/net/irda/parameters.c @@ -298,6 +298,8 @@ static int irda_extract_string(void *sel p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract length of value */ + if (p.pl > 32) + p.pl = 32; IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__, p.pi, p.pl); @@ -318,7 +320,7 @@ static int irda_extract_string(void *sel (__u8) str[0], (__u8) str[1]); /* Null terminate string */ - str[p.pl+1] = '\0'; + str[p.pl] = '\0'; p.pv.c = str; /* Handler will need to take a copy */ From 37f9fc452d138dfc4da2ee1ce5ae85094efc3606 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Oct 2010 01:03:12 +0200 Subject: irda: Fix heap memory corruption in iriap.c From: Samuel Ortiz commit 37f9fc452d138dfc4da2ee1ce5ae85094efc3606 upstream. While parsing the GetValuebyClass command frame, we could potentially write passed the skb->data pointer. Reported-by: Ilja Van Sprundel Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- net/irda/iriap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -502,7 +502,8 @@ static void iriap_getvaluebyclass_confir IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len); /* Make sure the string is null-terminated */ - fp[n+value_len] = 0x00; + if (n + value_len < skb->len) + fp[n + value_len] = 0x00; IRDA_DEBUG(4, "Got string %s\n", fp+n); /* Will truncate to IAS_MAX_STRING bytes */ From e2269308359d5863b6aa1fcb95a425a2ab255f1f Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 14 Oct 2010 17:41:53 +0000 Subject: r6040: Fix multicast filter some more From: Ben Hutchings commit e2269308359d5863b6aa1fcb95a425a2ab255f1f upstream. This code has been broken forever, but in several different and creative ways. So far as I can work out, the R6040 MAC filter has 4 exact-match entries, the first of which the driver uses for its assigned unicast address, plus a 64-entry hash-based filter for multicast addresses (maybe unicast as well?). The original version of this code would write the first 4 multicast addresses as exact-match entries from offset 1 (bug #1: there is no entry 4 so this could write to some PHY registers). It would fill the remainder of the exact-match entries with the broadcast address (bug #2: this would overwrite the last used entry). If more than 4 multicast addresses were configured, it would set up the hash table, write some random crap to the MAC control register (bug #3) and finally walk off the end of the list when filling the exact-match entries (bug #4). All of this seems to be pointless, since it sets the promiscuous bit when the interface is made promiscuous or if >4 multicast addresses are enabled, and never clears it (bug #5, masking bug #2). The recent(ish) changes to the multicast list fixed bug #4, but completely removed the limit on iteration over the exact-match entries (bug #6). Bug #4 was reported as and more recently as . Florian Fainelli attempted to fix these in commit 3bcf8229a8c49769e48d3e0bd1e20d8e003f8106, but that actually dealt with bugs #1-3, bug #4 having been fixed in mainline at that point. That commit fixes the most important current bug #6. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/r6040.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -893,16 +893,18 @@ static void r6040_multicast_list(struct /* Multicast Address 1~4 case */ i = 0; netdev_for_each_mc_addr(ha, dev) { - if (i < MCAST_MAX) { - adrp = (u16 *) ha->addr; - iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); - iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); - iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); - } else { - iowrite16(0xffff, ioaddr + MID_1L + 8 * i); - iowrite16(0xffff, ioaddr + MID_1M + 8 * i); - iowrite16(0xffff, ioaddr + MID_1H + 8 * i); - } + if (i >= MCAST_MAX) + break; + adrp = (u16 *) ha->addr; + iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); + iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); + iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); + i++; + } + while (i < MCAST_MAX) { + iowrite16(0xffff, ioaddr + MID_1L + 8 * i); + iowrite16(0xffff, ioaddr + MID_1M + 8 * i); + iowrite16(0xffff, ioaddr + MID_1H + 8 * i); i++; } } From 354da653233898ed1e51f20cebac9705456bf9b1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Oct 2010 23:45:39 -0400 Subject: drm/radeon/kms: fix 2D tile height alignment in the r600 CS checker From: Alex Deucher commit 354da653233898ed1e51f20cebac9705456bf9b1 upstream. macro tile heights are aligned to num channels, not num banks. Noticed by Dave Airlie. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r600_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -228,7 +228,7 @@ static inline int r600_cs_track_validate __func__, __LINE__, pitch); return -EINVAL; } - if (!IS_ALIGNED((height / 8), track->nbanks)) { + if (!IS_ALIGNED((height / 8), track->npipes)) { dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", __func__, __LINE__, height); return -EINVAL; @@ -367,7 +367,7 @@ static int r600_cs_track_check(struct ra __func__, __LINE__, pitch); return -EINVAL; } - if ((height / 8) & (track->nbanks - 1)) { + if (!IS_ALIGNED((height / 8), track->npipes)) { dev_warn(p->dev, "%s:%d db height (%d) invalid\n", __func__, __LINE__, height); return -EINVAL; From a8909cfb1832ac623142898df2a9374722cfe68f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:51:54 +0200 Subject: ath9k: built-in rate control A-MPDU fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= commit a8909cfb1832ac623142898df2a9374722cfe68f upstream. This patch attempts to ensure that ath9k's built-in rate control algorithm does not rely on the value of the ampdu_len and ampdu_ack_len tx status fields unless the IEEE80211_TX_STAT_AMPDU flag is set. This patch has not been tested. Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/rc.c | 6 ++++++ 1 file changed, 6 insertions(+) --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1359,6 +1359,12 @@ static void ath_tx_status(void *priv, st if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) return; + if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { + tx_info->status.ampdu_ack_len = + (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); + tx_info->status.ampdu_len = 1; + } + /* * If an underrun error is seen assume it as an excessive retry only * if max frame trigger level has been reached (2 KB for singel stream, From f209f5298217cf54cd5a9163e18b08d093faf8d9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 1 Oct 2010 01:06:53 +0200 Subject: ath9k: fix channel flag / regd issues with multiple cards From: Felix Fietkau commit f209f5298217cf54cd5a9163e18b08d093faf8d9 upstream. Since the regulatory code touches the channel array, it needs to be copied for each device instance. That way the original channel array can also be made const. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/init.c | 37 ++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -56,7 +56,7 @@ MODULE_PARM_DESC(blink, "Enable LED blin * on 5 MHz steps, we support the channels which we know * we have calibration data for all cards though to make * this static */ -static struct ieee80211_channel ath9k_2ghz_chantable[] = { +static const struct ieee80211_channel ath9k_2ghz_chantable[] = { CHAN2G(2412, 0), /* Channel 1 */ CHAN2G(2417, 1), /* Channel 2 */ CHAN2G(2422, 2), /* Channel 3 */ @@ -77,7 +77,7 @@ static struct ieee80211_channel ath9k_2g * on 5 MHz steps, we support the channels which we know * we have calibration data for all cards though to make * this static */ -static struct ieee80211_channel ath9k_5ghz_chantable[] = { +static const struct ieee80211_channel ath9k_5ghz_chantable[] = { /* _We_ call this UNII 1 */ CHAN5G(5180, 14), /* Channel 36 */ CHAN5G(5200, 15), /* Channel 40 */ @@ -477,10 +477,17 @@ err: return -EIO; } -static void ath9k_init_channels_rates(struct ath_softc *sc) +static int ath9k_init_channels_rates(struct ath_softc *sc) { + void *channels; + if (test_bit(ATH9K_MODE_11G, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_2GHZ].channels = ath9k_2ghz_chantable; + channels = kmemdup(ath9k_2ghz_chantable, + sizeof(ath9k_2ghz_chantable), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + sc->sbands[IEEE80211_BAND_2GHZ].channels = channels; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; sc->sbands[IEEE80211_BAND_2GHZ].n_channels = ARRAY_SIZE(ath9k_2ghz_chantable); @@ -490,7 +497,15 @@ static void ath9k_init_channels_rates(st } if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes)) { - sc->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_chantable; + channels = kmemdup(ath9k_5ghz_chantable, + sizeof(ath9k_5ghz_chantable), GFP_KERNEL); + if (!channels) { + if (sc->sbands[IEEE80211_BAND_2GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); + return -ENOMEM; + } + + sc->sbands[IEEE80211_BAND_5GHZ].channels = channels; sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; sc->sbands[IEEE80211_BAND_5GHZ].n_channels = ARRAY_SIZE(ath9k_5ghz_chantable); @@ -499,6 +514,7 @@ static void ath9k_init_channels_rates(st sc->sbands[IEEE80211_BAND_5GHZ].n_bitrates = ARRAY_SIZE(ath9k_legacy_rates) - 4; } + return 0; } static void ath9k_init_misc(struct ath_softc *sc) @@ -593,8 +609,11 @@ static int ath9k_init_softc(u16 devid, s if (ret) goto err_btcoex; + ret = ath9k_init_channels_rates(sc); + if (ret) + goto err_btcoex; + ath9k_init_crypto(sc); - ath9k_init_channels_rates(sc); ath9k_init_misc(sc); return 0; @@ -751,6 +770,12 @@ static void ath9k_deinit_softc(struct at { int i = 0; + if (sc->sbands[IEEE80211_BAND_2GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_2GHZ].channels); + + if (sc->sbands[IEEE80211_BAND_5GHZ].channels) + kfree(sc->sbands[IEEE80211_BAND_5GHZ].channels); + if ((sc->btcoex.no_stomp_timer) && sc->sc_ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); From ebd022873aa61937603d2c4dfea19ce63ea1a3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:44:39 +0200 Subject: ath9k: A-MPDU rate control info fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= commit ebd022873aa61937603d2c4dfea19ce63ea1a3c8 upstream. This patch fixes the following problems with the rate control feedback generated by ath9k for A-MPDU frames: 1. Rate control feedback is carried on the first frame of an aggregate that is either ACKed, or has execeeded the software retry count and is considered failed. However, ath9k would incorrectly assume the aggregate had the length 1 if one of these conditions did not apply to the first frame of the aggregate, but instead a later frame. This fix therefor copies the bf_nframes field of the buffer in the same manner as the rates field of the tx status. 2. Sometimes the ampdu_len and ampdu_ack_len fields of the tx status was left uninitialized eventhough the IEEE80211_TX_STAT_AMPDU flag was set. This is now avoid by setting flag and fields in the same place. 3. Even if a frame has been selected for aggregation by mac80211 and marked with the IEEE80211_TX_CTL_AMPDU flag it can sometimes happen that ath9k transmits the frame without aggregation. In these cases the ampdu_ack_len field could be incorrectly computed because the nbad parameter to ath_tx_rc_status was incorrect. Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -312,6 +312,7 @@ static void ath_tx_complete_aggr(struct int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; bool rc_update = true; struct ieee80211_tx_rate rates[4]; + int nframes; skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -320,6 +321,7 @@ static void ath_tx_complete_aggr(struct hw = bf->aphy->hw; memcpy(rates, tx_info->control.rates, sizeof(rates)); + nframes = bf->bf_nframes; rcu_read_lock(); @@ -337,7 +339,7 @@ static void ath_tx_complete_aggr(struct !bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_rc_status(bf, ts, 0, 0, false); + ath_tx_rc_status(bf, ts, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -442,6 +444,7 @@ static void ath_tx_complete_aggr(struct if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { memcpy(tx_info->control.rates, rates, sizeof(rates)); + bf->bf_nframes = nframes; ath_tx_rc_status(bf, ts, nbad, txok, true); rc_update = false; } else { @@ -2024,9 +2027,15 @@ static void ath_tx_rc_status(struct ath_ if (ts->ts_status & ATH9K_TXERR_FILT) tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + BUG_ON(nbad > bf->bf_nframes); + + tx_info->status.ampdu_len = bf->bf_nframes; + tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; + } + if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { if (ieee80211_is_data(hdr->frame_control)) { @@ -2036,8 +2045,6 @@ static void ath_tx_rc_status(struct ath_ if ((ts->ts_status & ATH9K_TXERR_XRETRY) || (ts->ts_status & ATH9K_TXERR_FIFO)) tx_info->pad[0] |= ATH_TX_INFO_XRETRY; - tx_info->status.ampdu_len = bf->bf_nframes; - tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad; } } @@ -2159,7 +2166,7 @@ static void ath_tx_processq(struct ath_s */ if (ts.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &ts, 0, txok, true); + ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) @@ -2288,7 +2295,7 @@ void ath_tx_edma_tasklet(struct ath_soft if (!bf_isampdu(bf)) { if (txs.ts_status & ATH9K_TXERR_XRETRY) bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(bf, &txs, 0, txok, true); + ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true); } if (bf_isampdu(bf)) From 9094537c3a9ef9e127e844254a74186735c9a90b Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Mon, 20 Sep 2010 22:54:46 -0700 Subject: ath9k: Fix tx struck state with paprd From: Vasanthakumar Thiagarajan commit 9094537c3a9ef9e127e844254a74186735c9a90b upstream. Paprd needs to be done only on active chains(not for all the chains that hw can support). The paprd training frames which are sent for inactive chains would be hanging on the hw queue without getting transmitted and would make the connection so unstable. This issue happens only with the hw which supports paprd cal(ar9003). Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -269,6 +269,7 @@ static void ath_paprd_activate(struct at { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath_common *common = ath9k_hw_common(ah); int chain; if (!caldata || !caldata->paprd_done) @@ -277,7 +278,7 @@ static void ath_paprd_activate(struct at ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->caps.tx_chainmask & BIT(chain))) + if (!(common->tx_chainmask & BIT(chain))) continue; ar9003_paprd_populate_single_table(ah, caldata, chain); @@ -299,6 +300,7 @@ void ath_paprd_calibrate(struct work_str struct ieee80211_supported_band *sband = &sc->sbands[band]; 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 chain_ok = 0; int chain; @@ -332,7 +334,7 @@ void ath_paprd_calibrate(struct work_str ath9k_ps_wakeup(sc); ar9003_paprd_init_table(ah); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(ah->caps.tx_chainmask & BIT(chain))) + if (!(common->tx_chainmask & BIT(chain))) continue; chain_ok = 0; From 90fa539ca3f07323da5a90f5c8f4e5cd952875e7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Sep 2010 13:45:38 +0200 Subject: ath9k: clean up / fix aggregation session flush From: Felix Fietkau commit 90fa539ca3f07323da5a90f5c8f4e5cd952875e7 upstream. The tid aggregation cleanup is a bit fragile, as it discards failed subframes in some places, and retransmits them in others. This could block the cleanup of an existing aggregation session, if a retransmission for a tid is issued, yet the tid is never scheduled again because of the cleanup state. Fix this by getting rid of as many subframes as possible, as early as possible, and immediately transmitting pending subframes as regular HT frames instead of waiting for the cleanup to complete. Drop all pending subframes while keeping track of the Block ACK window during aggregate tx completion to prevent sending out stale subframes, which could confuse the receiver side. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 63 ++++++++++++++-------------------- 1 file changed, 26 insertions(+), 37 deletions(-) --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -61,6 +61,8 @@ static int ath_tx_num_badfrms(struct ath struct ath_tx_status *ts, int txok); static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts, int nbad, int txok, bool update_rc); +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + int seqno); enum { MCS_HT20, @@ -143,18 +145,23 @@ static void ath_tx_flush_tid(struct ath_ struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; - INIT_LIST_HEAD(&bf_head); + struct ath_tx_status ts; - WARN_ON(!tid->paused); + INIT_LIST_HEAD(&bf_head); + memset(&ts, 0, sizeof(ts)); spin_lock_bh(&txq->axq_lock); - tid->paused = false; while (!list_empty(&tid->buf_q)) { bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - BUG_ON(bf_isretried(bf)); list_move_tail(&bf->list, &bf_head); - ath_tx_send_ht_normal(sc, txq, tid, &bf_head); + + if (bf_isretried(bf)) { + ath_tx_update_baw(sc, tid, bf->bf_seqno); + ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); + } else { + ath_tx_send_ht_normal(sc, txq, tid, &bf_head); + } } spin_unlock_bh(&txq->axq_lock); @@ -433,7 +440,7 @@ static void ath_tx_complete_aggr(struct list_move_tail(&bf->list, &bf_head); } - if (!txpending) { + if (!txpending || (tid->state & AGGR_CLEANUP)) { /* * complete the acked-ones/xretried ones; update * block-ack window @@ -513,15 +520,12 @@ static void ath_tx_complete_aggr(struct } if (tid->state & AGGR_CLEANUP) { + ath_tx_flush_tid(sc, tid); + if (tid->baw_head == tid->baw_tail) { tid->state &= ~AGGR_ADDBA_COMPLETE; tid->state &= ~AGGR_CLEANUP; - - /* send buffered frames as singles */ - ath_tx_flush_tid(sc, tid); } - rcu_read_unlock(); - return; } rcu_read_unlock(); @@ -806,12 +810,6 @@ void ath_tx_aggr_stop(struct ath_softc * 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_tx_status ts; - struct ath_buf *bf; - struct list_head bf_head; - - memset(&ts, 0, sizeof(ts)); - INIT_LIST_HEAD(&bf_head); if (txtid->state & AGGR_CLEANUP) return; @@ -821,31 +819,22 @@ void ath_tx_aggr_stop(struct ath_softc * return; } - /* drop all software retried frames and mark this TID */ spin_lock_bh(&txq->axq_lock); txtid->paused = true; - while (!list_empty(&txtid->buf_q)) { - bf = list_first_entry(&txtid->buf_q, struct ath_buf, list); - if (!bf_isretried(bf)) { - /* - * NB: it's based on the assumption that - * software retried frame will always stay - * at the head of software queue. - */ - break; - } - list_move_tail(&bf->list, &bf_head); - ath_tx_update_baw(sc, txtid, bf->bf_seqno); - ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); - } - spin_unlock_bh(&txq->axq_lock); - if (txtid->baw_head != txtid->baw_tail) { + /* + * If frames are still being transmitted for this TID, they will be + * cleaned up during tx completion. To prevent race conditions, this + * TID can only be reused after all in-progress subframes have been + * completed. + */ + if (txtid->baw_head != txtid->baw_tail) txtid->state |= AGGR_CLEANUP; - } else { + else txtid->state &= ~AGGR_ADDBA_COMPLETE; - ath_tx_flush_tid(sc, txtid); - } + spin_unlock_bh(&txq->axq_lock); + + ath_tx_flush_tid(sc, txtid); } void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) From 8ab2cd09fecc8819bbaee2d0fd8f3a092d866ce3 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:26 -0400 Subject: ath9k: fix power save race conditions From: Luis R. Rodriguez commit 8ab2cd09fecc8819bbaee2d0fd8f3a092d866ce3 upstream. ath9k has a race on putting the chip into network sleep and having registers read from hardware. The race occurs because although ath9k_ps_restore() locks its own callers it makes use of some variables which get altered in the driver at different code paths. The variables are the ps_enabled and ps_flags. This is easily reprodicible in large network environments when roaming with the wpa_supplicant simple bgscan. You'd get some 0xdeadbeef read out on certain registers such as: ath: timeout (100000 us) on reg 0x806c: 0xdeadbeef & 0x01f00000 != 0x00000000 ath: RX failed to go idle in 10 ms RXSM=0xdeadbeef ath: timeout (100000 us) on reg 0x7000: 0xdeadbeef & 0x00000003 != 0x00000000 ath: Chip reset failed The fix is to protect the ath9k_config(hw, IEEE80211_CONF_CHANGE_PS) calls with a spin_lock_irqsave() which will disable contendors for these variables from interrupt context, timers, re-entry from mac80211 on the same callback, and most importantly from ath9k_ps_restore() which is the only call which will put the device into network sleep. There are quite a few threads and bug reports on these a few of them are: https://bugs.launchpad.net/ubuntu/karmic/+source/linux/+bug/407040 http://code.google.com/p/chromium-os/issues/detail?id=5709 http://code.google.com/p/chromium-os/issues/detail?id=5943 Stable fixes apply to [2.6.32+] Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 5 ++++- drivers/net/wireless/ath/ath9k/recv.c | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1558,6 +1558,8 @@ static int ath9k_config(struct ieee80211 * IEEE80211_CONF_CHANGE_PS is only passed by mac80211 for STA mode. */ if (changed & IEEE80211_CONF_CHANGE_PS) { + unsigned long flags; + spin_lock_irqsave(&sc->sc_pm_lock, flags); if (conf->flags & IEEE80211_CONF_PS) { sc->ps_flags |= PS_ENABLED; /* @@ -1572,7 +1574,7 @@ static int ath9k_config(struct ieee80211 sc->ps_enabled = false; sc->ps_flags &= ~(PS_ENABLED | PS_NULLFUNC_COMPLETED); - ath9k_setpower(sc, ATH9K_PM_AWAKE); + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { ath9k_hw_setrxabort(sc->sc_ah, 0); @@ -1587,6 +1589,7 @@ static int ath9k_config(struct ieee80211 } } } + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) { --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1096,6 +1096,7 @@ int ath_rx_tasklet(struct ath_softc *sc, u8 rx_status_len = ah->caps.rx_status_len; u64 tsf = 0; u32 tsf_lower = 0; + unsigned long flags; if (edma) dma_type = DMA_BIDIRECTIONAL; @@ -1204,11 +1205,13 @@ int ath_rx_tasklet(struct ath_softc *sc, sc->rx.rxotherant = 0; } + spin_lock_irqsave(&sc->sc_pm_lock, flags); if (unlikely(ath9k_check_auto_sleep(sc) || (sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA)))) ath_rx_ps(sc, skb); + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath_rx_send_to_mac80211(hw, sc, skb, rxs); From 231c3a1f0630c07a584905507a1cb7b705a56ab7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 20 Sep 2010 19:35:28 +0200 Subject: ath9k: fix an aggregation start related race condition From: Felix Fietkau commit 231c3a1f0630c07a584905507a1cb7b705a56ab7 upstream. A new aggregation session start can be issued by mac80211, even when the cleanup of the previous session has not completed yet. Since the data structure for the session is not recreated, this could corrupt the block ack window and lock up the aggregation session. Fix this by delaying the new session until the old one has been cleaned up. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ath9k.h | 4 ++-- drivers/net/wireless/ath/ath9k/main.c | 5 +++-- drivers/net/wireless/ath/ath9k/xmit.c | 10 ++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -346,8 +346,8 @@ void ath_tx_tasklet(struct ath_softc *sc void ath_tx_edma_tasklet(struct ath_softc *sc); void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb); bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); -void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); void ath9k_enable_ps(struct ath_softc *sc); --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1973,8 +1973,9 @@ static int ath9k_ampdu_action(struct iee break; case IEEE80211_AMPDU_TX_START: ath9k_ps_wakeup(sc); - ath_tx_aggr_start(sc, sta, tid, ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + ret = ath_tx_aggr_start(sc, sta, tid, ssn); + if (!ret) + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); ath9k_ps_restore(sc); break; case IEEE80211_AMPDU_TX_STOP: --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -792,17 +792,23 @@ static void ath_tx_sched_aggr(struct ath status != ATH_AGGR_BAW_CLOSED); } -void ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, - u16 tid, u16 *ssn) +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); + + if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE)) + return -EAGAIN; + txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; *ssn = txtid->seq_start; + + return 0; } void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) From 3fac6dfdcd2b893c22b20a03dd1bf1af8b627c4b Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Thu, 16 Sep 2010 15:12:35 -0400 Subject: ath9k: fix regression which prevents chip sleep after CAB data From: Senthil Balasubramanian commit 3fac6dfdcd2b893c22b20a03dd1bf1af8b627c4b upstream. The patch: commit 293dc5dfdbcc16cde06e40a688394cc8ab083e48 Author: Gabor Juhos Date: Fri Jun 19 12:17:48 2009 +0200 ath9k: remove ath_rx_ps_back_to_sleep helper This helper only clears the SC_OP_WAIT_FOR_{BEACON,CAB} flags. Remove it and clear these flags directly in the approptiate places instead. Changes-licensed-under: ISC Signed-off-by: Gabor Juhos Signed-off-by: John W. Linville introduced a regression which forgot to lift the beacon flag after we received all broadcast and multicast data. This meant we never went to sleep consuming about ~650mW on idle. This pretty much broke power save completely. This patch has fixes for stable kernels [2.6.32+]. Cc: Paul Stewart Cc: Sameer Nanda Cc: Gabor Juhos Cc: Amod Bodas Signed-off-by: Senthil Balasubramanian Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -631,7 +631,7 @@ static void ath_rx_ps(struct ath_softc * * No more broadcast/multicast frames to be received at this * point. */ - sc->ps_flags &= ~PS_WAIT_FOR_CAB; + sc->ps_flags &= ~(PS_WAIT_FOR_CAB | PS_WAIT_FOR_BEACON); ath_print(common, ATH_DBG_PS, "All PS CAB frames received, back to sleep\n"); } else if ((sc->ps_flags & PS_WAIT_FOR_PSPOLL_DATA) && From 3ae74c33c4f799f6bf6d67240a94a0814a8f1944 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 14 Sep 2010 18:38:26 +0200 Subject: ath9k_hw: handle rx key miss From: Felix Fietkau commit 3ae74c33c4f799f6bf6d67240a94a0814a8f1944 upstream. If AR_KeyMiss is set in the rx descriptor and AR_RxFrameOK is unset, the hardware could not locate a valid key during a decryption attempt. In this case, the frame must not be reported as decrypted, otherwise mac80211 sees only random garbage. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 3 ++- drivers/net/wireless/ath/ath9k/mac.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -616,7 +616,8 @@ int ath9k_hw_process_rxdesc_edma(struct rxs->rs_status |= ATH9K_RXERR_DECRYPT; } else if (rxsp->status11 & AR_MichaelErr) { rxs->rs_status |= ATH9K_RXERR_MIC; - } + } else if (rxsp->status11 & AR_KeyMiss) + rxs->rs_status |= ATH9K_RXERR_DECRYPT; } return 0; --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -713,6 +713,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; + else if (ads.ds_rxstatus8 & AR_KeyMiss) + rs->rs_status |= ATH9K_RXERR_DECRYPT; } return 0; From 008443def34db1dcc8016763587a288254ea5735 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:36 -0400 Subject: ath9k: fix regression which disabled ps on ath9k From: Luis R. Rodriguez commit 008443def34db1dcc8016763587a288254ea5735 upstream. The patch titled "ath9k: Add new file init.c" shuffled some code around but in dong so for some reason also removed the revision check for disablign power save. Add this revision check again so we can get power save re-enabled again by default on cards newer than AR5416 and AR5418. $ git describe --contains 556242049cc3992d0ee625e9f15c4b00ea4baac8 v2.6.34-rc1~233^2~49^2~343 This patch has fixes for stable kernels [2.6.34+]. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -660,7 +660,8 @@ void ath9k_set_hw_capab(struct ath_softc BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT); - hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + if (AR_SREV_5416(sc->sc_ah)) + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->queues = 4; hw->max_rates = 4; From 52b8ac92496e03d6b5619204d7f3bae6ce6eae45 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:27 -0400 Subject: ath9k: fix regression on beacon loss after bgscan From: Luis R. Rodriguez commit 52b8ac92496e03d6b5619204d7f3bae6ce6eae45 upstream. When we return to the home channel we were never reseting our beacon timers, this was casued by the fact that the scanning flag was still on even after we returned to our home channel. There are also other reasons why we would get a reset and if we are not off channel we always need to resynch our beacon timers, because a reset will clear them. This bug is a regression introduced on 2.6.36. The order of the changes are as follows: 5ee08656 - Sat Jul 31 - ath9k: prevent calibration during off-channel activity a0daa0e7 - Tue Jul 27 - Revert "mac80211: fix sw scan bracketing" 543708be - Fri Jun 18 - mac80211: fix sw scan bracketing mcgrof@tux ~/linux-2.6-allstable (git::master)$ git describe \ --contains 5ee0865615f65f84e6ee9174771a6716c29e08e1 v2.6.36-rc1~43^2~34^2~22 mcgrof@tux ~/linux-2.6-allstable (git::master)$ git describe \ --contains a0daa0e7592ada797d6835f11529097aabc27ad2 v2.6.36-rc1~571^2~64^2~13 mcgrof@tux ~/linux-2.6-allstable (git::master)$ git describe \ --contains 543708be320d7df692d24b349ca01a947b340764 v2.6.36-rc1~571^2~107^2~187 So 5ee08656 would have worked if a0daa0e7 was not committed but it was so this means 5ee08656 was broken since it assumed that when we were in the channel change routine the scan flag would be lifted. As it turns out the scan flag will be set when we are already on the home channel. For more details refer to: http://code.google.com/p/chromium-os/issues/detail?id=5715 These issues will need to be considered for our solution on reshifting the scan complete callback location on mac80211 on current development kernel work. This patch has stable fixes which apply down to [2.6.36+] Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -257,9 +257,11 @@ int ath_set_channel(struct ath_softc *sc if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) { ath_start_ani(common); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - ath_beacon_config(sc, NULL); } + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) + ath_beacon_config(sc, NULL); + ps_restore: ath9k_ps_restore(sc); return r; @@ -953,7 +955,7 @@ int ath_reset(struct ath_softc *sc, bool ath_update_txpow(sc); - if (sc->sc_flags & SC_OP_BEACONS) + if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) ath_beacon_config(sc, NULL); /* restart beacons */ ath9k_hw_set_interrupts(ah, ah->imask); From 56363ddeeed3afc5277ca227209773bc1042cc7b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 28 Aug 2010 18:21:21 +0200 Subject: ath9k: fix spurious MIC failure reports From: Felix Fietkau commit 56363ddeeed3afc5277ca227209773bc1042cc7b upstream. According to the hardware documentation, the MIC failure bit is only valid if the frame was decrypted using a valid TKIP key and is not a fragment. In some setups I've seen hardware-reported MIC failures on an AP that was configured for CCMP only, so it's clear that additional checks are necessary. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath.h | 1 + drivers/net/wireless/ath/ath9k/common.c | 11 +++++++++++ drivers/net/wireless/ath/ath9k/mac.c | 3 ++- drivers/net/wireless/ath/ath9k/recv.c | 19 +++++++++++-------- 4 files changed, 25 insertions(+), 9 deletions(-) --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -119,6 +119,7 @@ struct ath_common { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); + DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); u8 splitmic; struct ath_regulatory regulatory; --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -366,9 +366,13 @@ int ath9k_cmn_key_config(struct ath_comm set_bit(idx, common->keymap); if (key->alg == ALG_TKIP) { set_bit(idx + 64, common->keymap); + set_bit(idx, common->tkip_keymap); + set_bit(idx + 64, common->tkip_keymap); if (common->splitmic) { set_bit(idx + 32, common->keymap); set_bit(idx + 64 + 32, common->keymap); + set_bit(idx + 32, common->tkip_keymap); + set_bit(idx + 64 + 32, common->tkip_keymap); } } @@ -393,10 +397,17 @@ void ath9k_cmn_key_delete(struct ath_com return; clear_bit(key->hw_key_idx + 64, common->keymap); + + clear_bit(key->hw_key_idx, common->tkip_keymap); + clear_bit(key->hw_key_idx + 64, common->tkip_keymap); + if (common->splitmic) { ath9k_hw_keyreset(ah, key->hw_key_idx + 32); clear_bit(key->hw_key_idx + 32, common->keymap); clear_bit(key->hw_key_idx + 64 + 32, common->keymap); + + clear_bit(key->hw_key_idx + 32, common->tkip_keymap); + clear_bit(key->hw_key_idx + 64 + 32, common->tkip_keymap); } } EXPORT_SYMBOL(ath9k_cmn_key_delete); --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -711,7 +711,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a rs->rs_phyerr = phyerr; } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) rs->rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) + else if ((ads.ds_rxstatus8 & AR_MichaelErr) && + rs->rs_keyix != ATH9K_RXKEYIX_INVALID) rs->rs_status |= ATH9K_RXERR_MIC; else if (ads.ds_rxstatus8 & AR_KeyMiss) rs->rs_status |= ATH9K_RXERR_DECRYPT; --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -870,15 +870,18 @@ static bool ath9k_rx_accept(struct ath_c if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { *decrypt_error = true; } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) { - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - rx_stats->rs_status &= ~ATH9K_RXERR_MIC; - else + /* + * The MIC error bit is only valid if the frame + * is not a control frame or fragment, and it was + * decrypted using a valid TKIP key. + */ + if (!ieee80211_is_ctl(fc) && + !ieee80211_has_morefrags(fc) && + !(le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) && + test_bit(rx_stats->rs_keyix, common->tkip_keymap)) rxs->flag |= RX_FLAG_MMIC_ERROR; + else + rx_stats->rs_status &= ~ATH9K_RXERR_MIC; } /* * Reject error frames with the exception of From fac6b6a065da42f826088c58bddad82e1b1ccb40 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 23 Oct 2010 17:45:38 +0200 Subject: ath9k: resume aggregation immediately after a hardware reset From: Felix Fietkau commit fac6b6a065da42f826088c58bddad82e1b1ccb40 upstream. Since aggregation is usually triggered by tx completion, a hardware reset (because of beacon stuck, tx hang or baseband hang) can significantly delay the transmission of the next AMPDU (until the next tx completion event). Fix this by rescheduling aggregation after such a reset. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/beacon.c | 2 +- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -366,7 +366,7 @@ void ath_beacon_tasklet(unsigned long da ath_print(common, ATH_DBG_BEACON, "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; - ath_reset(sc, false); + ath_reset(sc, true); } return; --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -554,7 +554,7 @@ void ath_hw_check(struct work_struct *wo msleep(1); } - ath_reset(sc, false); + ath_reset(sc, true); out: ath9k_ps_restore(sc); @@ -572,7 +572,7 @@ void ath9k_tasklet(unsigned long data) ath9k_ps_wakeup(sc); if (status & ATH9K_INT_FATAL) { - ath_reset(sc, false); + ath_reset(sc, true); ath9k_ps_restore(sc); return; } --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2206,7 +2206,7 @@ static void ath_tx_complete_poll_work(st ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); ath9k_ps_wakeup(sc); - ath_reset(sc, false); + ath_reset(sc, true); ath9k_ps_restore(sc); } From 2d3fca180710c6832de22c44155ce6a3a4953c6b Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Tue, 19 Oct 2010 20:01:41 +0530 Subject: ath9k_hw: Fix divide by zero cases in paprd. From: Senthil Balasubramanian commit 2d3fca180710c6832de22c44155ce6a3a4953c6b upstream. We are not handling all divide by zero cases in paprd. Add additional checks for divide by zero cases in papard. This patch has fixes intended for kernel 2.6.36. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_paprd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -347,6 +347,10 @@ static bool create_pa_curve(u32 *data_L, (((Y[6] - Y[3]) * 1 << scale_factor) + (x_est[6] - x_est[3])) / (x_est[6] - x_est[3]); + /* prevent division by zero */ + if (G_fxp == 0) + return false; + Y_intercept = (G_fxp * (x_est[0] - x_est[3]) + (1 << scale_factor)) / (1 << scale_factor) + Y[3]; @@ -356,14 +360,12 @@ static bool create_pa_curve(u32 *data_L, for (i = 0; i <= 3; i++) { y_est[i] = i * 32; - - /* prevent division by zero */ - if (G_fxp == 0) - return false; - x_est[i] = ((y_est[i] * 1 << scale_factor) + G_fxp) / G_fxp; } + if (y_est[max_index] == 0) + return false; + x_est_fxp1_nonlin = x_est[max_index] - ((1 << scale_factor) * y_est[max_index] + G_fxp) / G_fxp; @@ -457,6 +459,8 @@ static bool create_pa_curve(u32 *data_L, Q_scale_B = find_proper_scale(find_expn(abs(scale_B)), 10); scale_B = scale_B / (1 << Q_scale_B); + if (scale_B == 0) + return false; Q_beta = find_proper_scale(find_expn(abs(beta_raw)), 10); Q_alpha = find_proper_scale(find_expn(abs(alpha_raw)), 10); beta_raw = beta_raw / (1 << Q_beta); From 0dfa6dbb7372e581d3beb38b11772152114796b8 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Mon, 18 Oct 2010 22:47:54 -0700 Subject: ath9k_hw: Fix TX carrier leakage for IEEE compliance on AR9003 2.2 From: Luis R. Rodriguez commit 0dfa6dbb7372e581d3beb38b11772152114796b8 upstream. This updates the initvals for the AR9003 2.2 chipsets. The initvals are the initial register values we use for our registers upon hardware reset. This synchs up the initvals to match what our latest recommendation from our systems engineering team. The description of changes in this update: Improves ability to support very strong Rx conditions. Enhances DFS support for AP-mode. Improves performance of Tx carrier leak calibration. Adds support for Japan channel 14 Tx filtering requirements. Improves Tx power accuracy. Impact: Update required to address degraded throughput at very short range. Update required for AP-mode DFS certification. Update required to comply to IEEE Tx carrier leak specification. May not meet expected +/- 2 dB Tx power accuracy without update. The most important fix here would be the TX carrier leakage required to comply with IEEE 802.11 specifications. The group of changes have been tested all together in one release. References: Osprey 2.2 header file ver #33 Checksums: $ ./initvals -f ar9003-2p2 0x000000004a488fc7 ar9300_2p2_radio_postamble 0x0000000046cb1300 ar9300Modes_lowest_ob_db_tx_gain_table_2p2 0x00000000e912711f ar9300Modes_fast_clock_2p2 0x0000000037ac0ee8 ar9300_2p2_radio_core 0x00000000047a7700 ar9300Common_rx_gain_table_merlin_2p2 0x0000000003f783bb ar9300_2p2_mac_postamble 0x00000000301fc841 ar9300_2p2_soc_postamble 0x000000005ec8075f ar9200_merlin_2p2_radio_core 0x0000000083372ffa ar9300_2p2_baseband_postamble 0x00000000c4f59974 ar9300_2p2_baseband_core 0x00000000e20d2e72 ar9300Modes_high_power_tx_gain_table_2p2 0x000000007fd55c70 ar9300Modes_high_ob_db_tx_gain_table_2p2 0x0000000029495000 ar9300Common_rx_gain_table_2p2 0x0000000042cb1300 ar9300Modes_low_ob_db_tx_gain_table_2p2 0x00000000c4739cd6 ar9300_2p2_mac_core 0x000000003521a300 ar9300Common_wo_xlna_rx_gain_table_2p2 0x00000000a15ccf1b ar9300_2p2_soc_preamble 0x0000000029734396 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2 0x000000002d834396 ar9300PciePhy_clkreq_enable_L1_2p2 0x0000000029834396 ar9300PciePhy_clkreq_disable_L1_2p2 $ ./initvals -f ar9003-2p2 | sha1sum 0ceddb5cf66737610fb51f04cf3e9ff71870c7b4 - Cc: Yixiang Li Cc: Don Breslin Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 191 +++++++++++++------ 1 file changed, 135 insertions(+), 56 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -34,6 +34,10 @@ static const u32 ar9300_2p2_radio_postam static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -99,6 +103,30 @@ static const u32 ar9300Modes_lowest_ob_d {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -118,7 +146,7 @@ static const u32 ar9300Modes_fast_clock_ {0x00008014, 0x044c044c, 0x08980898}, {0x0000801c, 0x148ec02b, 0x148ec057}, {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x03721821, 0x03721821}, + {0x00009e00, 0x0372131c, 0x0372131c}, {0x0000a230, 0x0000000b, 0x00000016}, {0x0000a254, 0x00000898, 0x00001130}, }; @@ -595,15 +623,16 @@ static const u32 ar9300_2p2_baseband_pos {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, @@ -624,16 +653,16 @@ static const u32 ar9300_2p2_baseband_pos {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, @@ -649,13 +678,13 @@ static const u32 ar9300_2p2_baseband_cor {0x00009814, 0x9280c00a}, {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, + {0x00009834, 0x6400a290}, {0x00009838, 0x0108ecff}, {0x0000983c, 0x14750600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, + {0x000098b0, 0x32840bbe}, {0x000098d0, 0x004b6a8e}, {0x000098d4, 0x00000820}, {0x000098dc, 0x00000000}, @@ -681,7 +710,6 @@ static const u32 ar9300_2p2_baseband_cor {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e3c, 0xcf946222}, {0x00009e40, 0x0d261820}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, @@ -694,7 +722,7 @@ static const u32 ar9300_2p2_baseband_cor {0x0000a220, 0x00000000}, {0x0000a224, 0x00000000}, {0x0000a228, 0x10002310}, - {0x0000a22c, 0x01036a1e}, + {0x0000a22c, 0x01036a27}, {0x0000a23c, 0x00000000}, {0x0000a244, 0x0c000000}, {0x0000a2a0, 0x00000001}, @@ -702,10 +730,6 @@ static const u32 ar9300_2p2_baseband_cor {0x0000a2c8, 0x00000000}, {0x0000a2cc, 0x18c43433}, {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, {0x0000a2ec, 0x00000000}, {0x0000a2f0, 0x00000000}, {0x0000a2f4, 0x00000000}, @@ -753,33 +777,17 @@ static const u32 ar9300_2p2_baseband_cor {0x0000a430, 0x1ce739ce}, {0x0000a434, 0x00000000}, {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, + {0x0000a43c, 0x00100000}, {0x0000a440, 0x00000000}, {0x0000a444, 0x00000000}, {0x0000a448, 0x06000080}, {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a458, 0x00000000}, - {0x0000a600, 0x00000000}, - {0x0000a604, 0x00000000}, - {0x0000a608, 0x00000000}, - {0x0000a60c, 0x00000000}, - {0x0000a610, 0x00000000}, - {0x0000a614, 0x00000000}, - {0x0000a618, 0x00000000}, - {0x0000a61c, 0x00000000}, - {0x0000a620, 0x00000000}, - {0x0000a624, 0x00000000}, - {0x0000a628, 0x00000000}, - {0x0000a62c, 0x00000000}, - {0x0000a630, 0x00000000}, - {0x0000a634, 0x00000000}, - {0x0000a638, 0x00000000}, - {0x0000a63c, 0x00000000}, {0x0000a640, 0x00000000}, {0x0000a644, 0x3fad9d74}, {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00000637}, + {0x0000a64c, 0x00003c37}, {0x0000a670, 0x03020100}, {0x0000a674, 0x09080504}, {0x0000a678, 0x0d0c0b0a}, @@ -802,10 +810,6 @@ static const u32 ar9300_2p2_baseband_cor {0x0000a8f4, 0x00000000}, {0x0000b2d0, 0x00000080}, {0x0000b2d4, 0x00000000}, - {0x0000b2dc, 0x00000000}, - {0x0000b2e0, 0x00000000}, - {0x0000b2e4, 0x00000000}, - {0x0000b2e8, 0x00000000}, {0x0000b2ec, 0x00000000}, {0x0000b2f0, 0x00000000}, {0x0000b2f4, 0x00000000}, @@ -820,10 +824,6 @@ static const u32 ar9300_2p2_baseband_cor {0x0000b8f4, 0x00000000}, {0x0000c2d0, 0x00000080}, {0x0000c2d4, 0x00000000}, - {0x0000c2dc, 0x00000000}, - {0x0000c2e0, 0x00000000}, - {0x0000c2e4, 0x00000000}, - {0x0000c2e8, 0x00000000}, {0x0000c2ec, 0x00000000}, {0x0000c2f0, 0x00000000}, {0x0000c2f4, 0x00000000}, @@ -835,6 +835,10 @@ static const u32 ar9300_2p2_baseband_cor static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -855,7 +859,7 @@ static const u32 ar9300Modes_high_power_ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, @@ -900,6 +904,30 @@ static const u32 ar9300Modes_high_power_ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, @@ -913,6 +941,10 @@ static const u32 ar9300Modes_high_power_ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -933,7 +965,7 @@ static const u32 ar9300Modes_high_ob_db_ {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, @@ -978,6 +1010,30 @@ static const u32 ar9300Modes_high_ob_db_ {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800}, + {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000}, + {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -1151,14 +1207,14 @@ static const u32 ar9300Common_rx_gain_ta {0x0000b074, 0x00000000}, {0x0000b078, 0x00000000}, {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, + {0x0000b080, 0x2a2d2f32}, + {0x0000b084, 0x21232328}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, {0x0000b0a0, 0x00000000}, {0x0000b0a4, 0x00000000}, {0x0000b0a8, 0x00000000}, @@ -1251,6 +1307,10 @@ static const u32 ar9300Common_rx_gain_ta static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -1316,6 +1376,30 @@ static const u32 ar9300Modes_low_ob_db_t {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, @@ -1414,15 +1498,10 @@ static const u32 ar9300_2p2_mac_core[][2 {0x00008144, 0xffffffff}, {0x00008168, 0x00000000}, {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, {0x000081c0, 0x00000000}, {0x000081c4, 0x33332210}, {0x000081c8, 0x00000000}, {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, {0x000081ec, 0x00000000}, {0x000081f0, 0x00000000}, {0x000081f4, 0x00000000}, From d654567dec75782d6fd9add4b7b9c50e0926d369 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 27 Oct 2010 12:02:54 +0530 Subject: ath9k_htc: Set proper firmware offset for Netgear WNDA3200 From: Rajkumar Manoharan commit d654567dec75782d6fd9add4b7b9c50e0926d369 upstream. Netgear WNDA3200 device uses ar7010 firmware but it is failed to set correct firmware offset on firmware download which causes device initialization failure. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -799,10 +799,16 @@ static int ath9k_hif_usb_download_fw(str } kfree(buf); - if ((hif_dev->device_id == 0x7010) || (hif_dev->device_id == 0x7015)) + switch (hif_dev->device_id) { + case 0x7010: + case 0x7015: + case 0x9018: firm_offset = AR7010_FIRMWARE_TEXT; - else + break; + default: firm_offset = AR9271_FIRMWARE_TEXT; + break; + } /* * Issue FW download complete command to firmware. From 4fc4fbd1d9a05fa4f348b499aca3a6f8d3c9bbe6 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 28 Oct 2010 19:51:47 +0530 Subject: ath9k: Fix incorrect access of rate flags in RC From: Mohammed Shafi Shajakhan commit 4fc4fbd1d9a05fa4f348b499aca3a6f8d3c9bbe6 upstream. The index variable to access the rate flags should be obtained from the inner loop counter which corresponds to the rate table structure.This fixes the invalid rate selection i.e when the supported basic rate is invalid on a particular band and also the following warning message. Thanks to Raj for finding this out. Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_null+0x15/0x20 [] ath_get_rate+0x595/0x5b0 [ath9k] [] ? cpumask_next_and+0x36/0x50 [] rate_control_get_rate+0x86/0x160 [mac80211] [] invoke_tx_handlers+0x81c/0x12d0 [mac80211] [] ieee80211_tx+0x89/0x2b0 [mac80211] [] ? pskb_expand_head+0x1cc/0x1f0 [] ieee80211_xmit+0xb5/0x1c0 [mac80211] [] ieee80211_tx_skb+0x4f/0x60 [mac80211] [] ieee80211_send_nullfunc+0x46/0x60 [mac80211] [] ieee80211_offchannel_stop_station+0x107/0x150 [mac80211] [] ? pskb_expand_head+0x1cc/0x1f0 [] ieee80211_xmit+0xb5/0x1c0 [mac80211] [] ieee80211_tx_skb+0x4f/0x60 [mac80211] [] ieee80211_send_nullfunc+0x46/0x60 [mac80211] [] ieee80211_offchannel_stop_station+0x107/0x150 [mac80211] [] ieee80211_scan_work+0x146/0x600 [mac80211] [] ? schedule+0x2f5/0x8e0 [] ? ieee80211_scan_work+0x0/0x600 [mac80211] [] process_one_work+0x10f/0x380 [] worker_thread+0x162/0x340 [] ? worker_thread+0x0/0x340 Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -538,7 +538,7 @@ static u8 ath_rc_setvalid_rates(struct a for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; - u16 rate_flags = rate_table->info[i].rate_flags; + u16 rate_flags = rate_table->info[j].rate_flags; u8 rate = rateset->rs_rates[i]; u8 dot11rate = rate_table->info[j].dot11rate; From b79b33c4baf2532aac2c0924dce5a738099b888c Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Wed, 20 Oct 2010 16:07:05 -0700 Subject: ath9k: rename rxflushlock to pcu_lock From: Luis R. Rodriguez commit b79b33c4baf2532aac2c0924dce5a738099b888c upstream. The real way to lock RX is to contend on the PCU and reset, this will be fixed in the next patch but for now just do the renames so that the next patch which changes the locking order is crystal clear. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ath9k.h | 2 +- drivers/net/wireless/ath/ath9k/main.c | 4 ++-- drivers/net/wireless/ath/ath9k/recv.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -312,7 +312,7 @@ struct ath_rx { u8 rxotherant; u32 *rxlink; unsigned int rxfilter; - spinlock_t rxflushlock; + spinlock_t pcu_lock; spinlock_t rxbuflock; struct list_head rxbuf; struct ath_descdma rxdma; --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -587,7 +587,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.rxflushlock); + spin_lock_bh(&sc->rx.pcu_lock); /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && @@ -595,7 +595,7 @@ void ath9k_tasklet(unsigned long data) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); - spin_unlock_bh(&sc->rx.rxflushlock); + spin_unlock_bh(&sc->rx.pcu_lock); } if (status & ATH9K_INT_TX) { --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -310,7 +310,7 @@ int ath_rx_init(struct ath_softc *sc, in struct ath_buf *bf; int error = 0; - spin_lock_init(&sc->rx.rxflushlock); + spin_lock_init(&sc->rx.pcu_lock); sc->sc_flags &= ~SC_OP_RXFLUSH; spin_lock_init(&sc->rx.rxbuflock); @@ -522,13 +522,13 @@ bool ath_stoprecv(struct ath_softc *sc) void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxflushlock); + spin_lock_bh(&sc->rx.pcu_lock); sc->sc_flags |= SC_OP_RXFLUSH; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.rxflushlock); + spin_unlock_bh(&sc->rx.pcu_lock); } static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) From e609e2ea2cdb3448e7849703179cd792a28dcc55 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 27 Oct 2010 02:15:05 +0200 Subject: ath9k: fix tx aggregation flush on AR9003 From: Felix Fietkau commit e609e2ea2cdb3448e7849703179cd792a28dcc55 upstream. Completing aggregate frames can lead to new buffers being pushed into the tid queues due to software retransmission. When the tx queues are being drained, all pending aggregates must be completed before the tid queues get drained, otherwise buffers might be leaked. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/xmit.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1101,15 +1101,6 @@ void ath_draintxq(struct ath_softc *sc, txq->axq_tx_inprogress = false; spin_unlock_bh(&txq->axq_lock); - /* flush any pending frames if aggregation is enabled */ - if (sc->sc_flags & SC_OP_TXAGGR) { - if (!retry_tx) { - spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq); - spin_unlock_bh(&txq->axq_lock); - } - } - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { spin_lock_bh(&txq->axq_lock); while (!list_empty(&txq->txq_fifo_pending)) { @@ -1130,6 +1121,15 @@ void ath_draintxq(struct ath_softc *sc, } spin_unlock_bh(&txq->axq_lock); } + + /* flush any pending frames if aggregation is enabled */ + if (sc->sc_flags & SC_OP_TXAGGR) { + if (!retry_tx) { + spin_lock_bh(&txq->axq_lock); + ath_txq_drain_pending_buffers(sc, txq); + spin_unlock_bh(&txq->axq_lock); + } + } } void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) From 1e450285281bdf766272c181ecd43d4f2f0711ce Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Wed, 20 Oct 2010 16:07:03 -0700 Subject: ath9k: add locking for stopping RX From: Luis R. Rodriguez commit 1e450285281bdf766272c181ecd43d4f2f0711ce upstream. ath9k locks for starting RX but not for stopping RX. We could potentially run into a situation where tried to stop RX but immediately started RX. This allows for races on the the RX engine deciding what buffer we last left off on and could potentially cause ath9k to DMA into already free'd memory or in the worst case at a later time to already given memory to other drivers. Fix this by locking stopping RX. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -297,10 +297,8 @@ static void ath_edma_start_recv(struct a static void ath_edma_stop_recv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxbuflock); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); - spin_unlock_bh(&sc->rx.rxbuflock); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -508,6 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; bool stopped; + spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); @@ -516,6 +515,7 @@ bool ath_stoprecv(struct ath_softc *sc) ath_edma_stop_recv(sc); else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.rxbuflock); return stopped; } From 48a6a468198aadb54bc5d3fdd065364d43ff5197 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:28 -0400 Subject: ath9k: fix enabling ANI / tx monitor after bg scan From: Luis R. Rodriguez commit 48a6a468198aadb54bc5d3fdd065364d43ff5197 upstream. ath9k's entire logic with SC_OP_SCANNING is incorrect due to the way mac80211 currently implements the scan complete callback and we handle it in ath9k. This patch removes the flag completely in preference for the SC_OP_OFFCHANNEL which is really what we wanted. The scanning flag was used to ensure we reset ANI to the old values when we go back to the home channel, but if we are offchannel we use some defaults. The flag was also used to re-enable the TX monitor. Without this patch we simply never re-enabled ANI and the TX monitor after going offchannel. This means that after one background scan we are prone to noise issues and if we had a TX hang we would not recover. To get this to work properly we must enable ANI after we have configured the beacon timers, otherwise hardware acts really oddly. This patch has stable fixes which apply down to [2.6.36+], there *may* be a to fix this on older kernels but requires a bit of work since this patch relies on the new mac80211 flag IEEE80211_CONF_OFFCHANNEL which was introduced as of 2.6.36. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ath9k.h | 1 - drivers/net/wireless/ath/ath9k/main.c | 10 +++------- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 3 files changed, 5 insertions(+), 10 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -516,7 +516,6 @@ void ath_deinit_leds(struct ath_softc *s #define SC_OP_RXFLUSH BIT(7) #define SC_OP_LED_ASSOCIATED BIT(8) #define SC_OP_LED_ON BIT(9) -#define SC_OP_SCANNING BIT(10) #define SC_OP_TSF_RESET BIT(11) #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -254,14 +254,12 @@ int ath_set_channel(struct ath_softc *sc ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL | SC_OP_SCANNING))) { - ath_start_ani(common); + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { + ath_beacon_config(sc, NULL); ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + ath_start_ani(common); } - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_beacon_config(sc, NULL); - ps_restore: ath9k_ps_restore(sc); return r; @@ -2040,7 +2038,6 @@ static void ath9k_sw_scan_start(struct i aphy->state = ATH_WIPHY_SCAN; ath9k_wiphy_pause_all_forced(sc, aphy); - sc->sc_flags |= SC_OP_SCANNING; mutex_unlock(&sc->mutex); } @@ -2055,7 +2052,6 @@ static void ath9k_sw_scan_complete(struc mutex_lock(&sc->mutex); aphy->state = ATH_WIPHY_ACTIVE; - sc->sc_flags &= ~SC_OP_SCANNING; mutex_unlock(&sc->mutex); } --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -292,7 +292,7 @@ static void ath_edma_start_recv(struct a ath_opmode_init(sc); - ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_SCANNING)); + ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); } static void ath_edma_stop_recv(struct ath_softc *sc) @@ -496,7 +496,7 @@ int ath_startrecv(struct ath_softc *sc) start_recv: spin_unlock_bh(&sc->rx.rxbuflock); ath_opmode_init(sc); - ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_SCANNING)); + ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); return 0; } From 48a7c3df14d0cda850337a9b3f9e667a0b12a996 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 8 Nov 2010 20:40:53 +0530 Subject: ath9k_hw: Fix memory leak on ath9k_hw_rf_alloc_ext_banks failure From: Rajkumar Manoharan commit 48a7c3df14d0cda850337a9b3f9e667a0b12a996 upstream. The allocated externel radio banks have to be freed in case of ath9k_hw_rf_alloc_ext_banks failure. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -486,6 +486,7 @@ static int ath9k_hw_post_init(struct ath ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, "Failed allocating banks for " "external radio\n"); + ath9k_hw_rf_free_ext_banks(ah); return ecode; } From f119da3015712dc32bdf1c311652479e02dcb49a Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 4 Nov 2010 17:41:25 -0700 Subject: ath9k_hw: Fix AR9280 surprise removal during frequent idle on/off From: Vasanthakumar Thiagarajan commit f119da3015712dc32bdf1c311652479e02dcb49a upstream. Bit 22 of AR_WA should be set to fix the situation where chip reset is asynchronous to clock of analog shift registers, such that when reset is released, it could mess up the values of analog shift registers and cause some hw issue on AR9280. This bit is write only, but the driver does a read-modify-write on AR_WA without setting bit 22 in ar9002_hw_configpcipowersave() during radio disable. This causes surprise removal of hw. It can never recover from this state and the hw will become usable only after a power on/off cycle, and sometimes only during a cold reboot. This issue can be triggered by doing frequent roaming with the simple/test-roam script available from the wifi-test project [1] when roaming between APs quickly. When roaming there is a is a high possibility that the device being put into idle (radio disable) state by mac80211 during AUTH->ASSOC. A device hardware reset would fail and the kernel would output: [40251.363799] ath: AWAKE -> FULL-SLEEP [40251.363815] ieee80211 phy17: device no longer idle - working [40251.363817] ath: Marking phy17 as not-idle [40251.363819] ath: FULL-SLEEP -> AWAKE [40251.415978] pciehp 0000:00:1c.3:pcie04: Card not present on Slot(3) [40251.419896] ath: ah->misc_mode 0x4 [40251.428138] pciehp 0000:00:1c.3:pcie04: Card present on Slot(3) [40251.532247] ath: timeout (100000 us) on reg 0x9860: 0xffffffff & 0x00000001 != 0x00000000 [40251.532250] ath: Unable to reset channel (2462 MHz), reset status -5 [40251.532422] ath: Set channel: 5745 MHz [40251.540639] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.548826] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.557023] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.565211] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.573415] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.581603] ath: Failed to stop TX DMA in 100 msec after killing last frame [40251.581606] ath: Failed to stop TX DMA. Resetting hardware! [40251.592679] ath: DMA failed to stop in 10 ms AR_CR=0xffffffff AR_DIAG_SW=0xffffffff [40251.703330] ath: timeout (100000 us) on reg 0x7000: 0xffffffff & 0x00000003 != 0x00000000 [40251.703333] ath: RTC stuck in MAC reset [40251.703334] ath: Chip reset failed [40251.703335] ath: Unable to reset hardware; reset status -22 This is currently only reproducible with some HB92 (Half Mini-PCIE) cards but the fix applies to all AR9280 cards. This patch fixes this issue by setting bit 22 during radio disable. This patch has fixes for all kernels that has ath9k. [1] http://wireless.kernel.org/en/developers/Testing/wifi-test Cc: kyungwan.nam@atheros.com Cc: amod.bodas@atheros.com Cc: david.quan@atheros.com Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 3 +++ drivers/net/wireless/ath/ath9k/reg.h | 1 + 2 files changed, 4 insertions(+) --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -411,6 +411,9 @@ static void ar9002_hw_configpcipowersave val &= ~(AR_WA_BIT6 | AR_WA_BIT7); } + if (AR_SREV_9280(ah)) + val |= AR_WA_BIT22; + if (AR_SREV_9285E_20(ah)) val |= AR_WA_BIT23; --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -709,6 +709,7 @@ #define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */ #define AR_WA_ANALOG_SHIFT (1 << 20) #define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */ +#define AR_WA_BIT22 (1 << 22) #define AR9285_WA_DEFAULT 0x004a050b #define AR9280_WA_DEFAULT 0x0040073b #define AR_WA_DEFAULT 0x0000073f From 3bf30b56c4f0a1c4fae34050b7db4527c92891e8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 18 Nov 2010 12:19:52 +0530 Subject: ath9k_htc: Avoid setting QoS control for non-QoS frames From: Rajkumar Manoharan commit 3bf30b56c4f0a1c4fae34050b7db4527c92891e8 upstream. Setting tid information in the TX header is required only for QoS frames. Not handling this case causes severe data loss with some APs. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -121,7 +121,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_ tx_hdr.data_type = ATH9K_HTC_NORMAL; } - if (ieee80211_is_data(fc)) { + if (ieee80211_is_data_qos(fc)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } From 7583c550c3e635dcc61ab127c36ecefd59fb8dc8 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Wed, 20 Oct 2010 16:07:04 -0700 Subject: ath9k: add locking for starting the PCU on RX From: Luis R. Rodriguez commit 7583c550c3e635dcc61ab127c36ecefd59fb8dc8 upstream. There was some locking for starting some parts of RX but not for starting the PCU. Include this otherwise we can content against stopping the PCU. This can potentially lead to races against different buffers on the PCU which can lead to to the DMA RX engine writing to buffers which are already freed. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman index e581b1f..b3c9baf 100644 --- drivers/net/wireless/ath/ath9k/recv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -288,11 +288,11 @@ static void ath_edma_start_recv(struct a ath_rx_addbuffer_edma(sc, ATH9K_RX_QUEUE_LP, sc->rx.rx_edma[ATH9K_RX_QUEUE_LP].rx_fifo_hwsize); - spin_unlock_bh(&sc->rx.rxbuflock); - ath_opmode_init(sc); ath9k_hw_startpcureceive(sc->sc_ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + + spin_unlock_bh(&sc->rx.rxbuflock); } static void ath_edma_stop_recv(struct ath_softc *sc) @@ -494,10 +494,11 @@ int ath_startrecv(struct ath_softc *sc) ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->rx.rxbuflock); ath_opmode_init(sc); ath9k_hw_startpcureceive(ah, (sc->sc_flags & SC_OP_OFFCHANNEL)); + spin_unlock_bh(&sc->rx.rxbuflock); + return 0; } From b5261cf4f3860bd772346a3e692683b6144dd44c Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:26 +0530 Subject: ath9k_hw: Set proper eeprom offset for AR9287 HTC devices From: Rajkumar Manoharan commit b5261cf4f3860bd772346a3e692683b6144dd44c upstream. AR9287 based PCI & USB devices are differed in eeprom start offset. So set proper the offset for HTC devices to read nvram correctly. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/eeprom_9287.c | 2 +- drivers/net/wireless/ath/ath9k/reg.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -37,7 +37,7 @@ static bool ath9k_hw_ar9287_fill_eeprom( int addr, eep_start_loc; eep_data = (u16 *)eep; - if (ah->hw_version.devid == 0x7015) + if (AR9287_HTC_DEVID(ah)) eep_start_loc = AR9287_HTC_EEP_START_LOC; else eep_start_loc = AR9287_EEP_START_LOC; --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -903,6 +903,10 @@ ((_ah)->hw_version.devid == 0x7015) || \ ((_ah)->hw_version.devid == 0x9018)) +#define AR9287_HTC_DEVID(_ah) \ + (((_ah)->hw_version.devid == 0x7015) || \ + ((_ah)->hw_version.devid == 0x1200)) + #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 #define AR_RAD2133_SREV_MAJOR 0xd0 From 7cbf2611dac8d5f76fe64795a9426b8c97e6c3f8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:25 +0530 Subject: ath9k_htc: Add new devices into AR7010 From: Rajkumar Manoharan commit 7cbf2611dac8d5f76fe64795a9426b8c97e6c3f8 upstream. Treat new PIDs (0xA704, 0x1200) as AR7010 devices. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 4 ++++ drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 ++ drivers/net/wireless/ath/ath9k/reg.h | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -803,6 +803,8 @@ static int ath9k_hif_usb_download_fw(str case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: firm_offset = AR7010_FIRMWARE_TEXT; break; default: @@ -909,6 +911,8 @@ static int ath9k_hif_usb_probe(struct us case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202) hif_dev->fw_name = FIRMWARE_AR7010_1_1; else --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -247,6 +247,8 @@ static int ath9k_init_htc_services(struc case 0x7010: case 0x7015: case 0x9018: + case 0xA704: + case 0x1200: priv->htc->credits = 45; break; default: --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -901,7 +901,9 @@ #define AR_DEVID_7010(_ah) \ (((_ah)->hw_version.devid == 0x7010) || \ ((_ah)->hw_version.devid == 0x7015) || \ - ((_ah)->hw_version.devid == 0x9018)) + ((_ah)->hw_version.devid == 0x9018) || \ + ((_ah)->hw_version.devid == 0xA704) || \ + ((_ah)->hw_version.devid == 0x1200)) #define AR9287_HTC_DEVID(_ah) \ (((_ah)->hw_version.devid == 0x7015) || \ From ac618d70aeb681df7b77c1107fdf26f3249f855f Mon Sep 17 00:00:00 2001 From: Haitao Zhang Date: Sun, 7 Nov 2010 12:50:24 +0800 Subject: ath9k_htc: Add support for device ID 3346 From: Haitao Zhang commit ac618d70aeb681df7b77c1107fdf26f3249f855f upstream. This patch adds support for USB dongle with device ID 3346 from IMC Networks. Signed-off-by: Haitao Zhang Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 1 + 1 file changed, 1 insertion(+) --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -35,6 +35,7 @@ static struct usb_device_id ath9k_hif_us { USB_DEVICE(0x07D1, 0x3A10) }, /* Dlink Wireless 150 */ { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ { }, From 32b089558c54792028f14ae830ca7c0a8d9ac9a3 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Wed, 10 Nov 2010 17:51:24 +0530 Subject: ath9k_htc: Update usb device ID list From: Rajkumar Manoharan commit 32b089558c54792028f14ae830ca7c0a8d9ac9a3 upstream. Added new VID/PIDs into supported devices list Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 5 +++++ 1 file changed, 5 insertions(+) --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -36,8 +36,13 @@ static struct usb_device_id ath9k_hif_us { USB_DEVICE(0x13D3, 0x3327) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3328) }, /* Azurewave */ { USB_DEVICE(0x13D3, 0x3346) }, /* IMC Networks */ + { USB_DEVICE(0x13D3, 0x3348) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3349) }, /* Azurewave */ + { USB_DEVICE(0x13D3, 0x3350) }, /* Azurewave */ { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x083A, 0xA704) }, /* SMC Networks */ + { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ + { USB_DEVICE(0x1668, 0x1200) }, /* Verizon */ { }, }; From 5e848f789d60000d39d9a5f26ab02dbdd963f6cd Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Wed, 20 Oct 2010 16:07:06 -0700 Subject: ath9k: lock reset and PCU start/stopping From: Luis R. Rodriguez commit 5e848f789d60000d39d9a5f26ab02dbdd963f6cd upstream. Apart from locking the start and stop PCU we need to ensure we also content starting and stopping the PCU between hardware resets. This is part of a series that will help resolve the bug: https://bugzilla.kernel.org/show_bug.cgi?id=14624 For more details about this issue refer to: http://marc.info/?l=linux-wireless&m=128629803703756&w=2 Cc: Ben Greear Cc: Kyungwan Nam Signed-off-by: Luis R. Rodriguez Tested-by: Ben Greear Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 27 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath9k/recv.c | 2 -- 2 files changed, 27 insertions(+), 2 deletions(-) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -213,6 +213,9 @@ int ath_set_channel(struct ath_softc *sc */ ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); + + spin_lock_bh(&sc->rx.pcu_lock); + stopped = ath_stoprecv(sc); /* XXX: do not flush receive queue here. We don't want @@ -239,6 +242,7 @@ int ath_set_channel(struct ath_softc *sc "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); @@ -247,9 +251,12 @@ int ath_set_channel(struct ath_softc *sc ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto ps_restore; } + spin_unlock_bh(&sc->rx.pcu_lock); + ath_cache_conf_rate(sc, &hw->conf); ath_update_txpow(sc); ath9k_hw_set_interrupts(ah, ah->imask); @@ -840,6 +847,7 @@ void ath_radio_enable(struct ath_softc * if (!ah->curchan) 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) { @@ -854,8 +862,10 @@ void ath_radio_enable(struct ath_softc * if (ath_startrecv(sc) != 0) { ath_print(common, ATH_DBG_FATAL, "Unable to restart recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); return; } + spin_unlock_bh(&sc->rx.pcu_lock); if (sc->sc_flags & SC_OP_BEACONS) ath_beacon_config(sc, NULL); /* restart beacons */ @@ -894,6 +904,9 @@ void ath_radio_disable(struct ath_softc ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, false); /* clear pending tx frames */ + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); /* turn off frame recv */ ath_flushrecv(sc); /* flush recv queue */ @@ -911,6 +924,9 @@ void ath_radio_disable(struct ath_softc spin_unlock_bh(&sc->sc_resetlock); ath9k_hw_phy_disable(ah); + + spin_unlock_bh(&sc->rx.pcu_lock); + ath9k_hw_configpcipowersave(ah, 1, 1); ath9k_ps_restore(sc); ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); @@ -930,6 +946,9 @@ int ath_reset(struct ath_softc *sc, bool ath9k_hw_set_interrupts(ah, 0); ath_drain_all_txq(sc, retry_tx); + + spin_lock_bh(&sc->rx.pcu_lock); + ath_stoprecv(sc); ath_flushrecv(sc); @@ -944,6 +963,8 @@ int ath_reset(struct ath_softc *sc, bool ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); + spin_unlock_bh(&sc->rx.pcu_lock); + /* * We may be doing a reset in response to a request * that changes the channel so update any state that @@ -1108,6 +1129,7 @@ static int ath9k_start(struct ieee80211_ * 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_resetlock); r = ath9k_hw_reset(ah, init_channel, ah->caldata, false); if (r) { @@ -1116,6 +1138,7 @@ static int ath9k_start(struct ieee80211_ "(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); @@ -1137,8 +1160,10 @@ static int ath9k_start(struct ieee80211_ ath_print(common, ATH_DBG_FATAL, "Unable to start recv logic\n"); r = -EIO; + spin_unlock_bh(&sc->rx.pcu_lock); goto mutex_unlock; } + spin_unlock_bh(&sc->rx.pcu_lock); /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | @@ -1340,12 +1365,14 @@ static void ath9k_stop(struct ieee80211_ * before setting the invalid flag. */ ath9k_hw_set_interrupts(ah, 0); + spin_lock_bh(&sc->rx.pcu_lock); if (!(sc->sc_flags & SC_OP_INVALID)) { ath_drain_all_txq(sc, false); ath_stoprecv(sc); ath9k_hw_phy_disable(ah); } else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.pcu_lock); /* disable HAL and put h/w to sleep */ ath9k_hw_disable(ah); --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -523,13 +523,11 @@ bool ath_stoprecv(struct ath_softc *sc) void ath_flushrecv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.pcu_lock); sc->sc_flags |= SC_OP_RXFLUSH; if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, false); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->rx.pcu_lock); } static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) From 3207390a8b58bfc1335750f91cf6783c48ca19ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 6 Oct 2010 21:18:04 +0200 Subject: cfg80211: fix BSS double-unlinking From: Johannes Berg commit 3207390a8b58bfc1335750f91cf6783c48ca19ca upstream. When multiple interfaces are actively trying to associate with the same BSS, they may both find that the BSS isn't there and then try to unlink it. This can cause errors since the unlinking code can't currently deal with items that have already been unlinked. Normally this doesn't happen as most people don't try to use multiple station interfaces that associate at the same time too. Fix this by using the list entry as a flag to see if the item is still on a list. Reported-by: Ben Greear Tested-by: Hun-Kyi Wynn Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/scan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *w bss = container_of(pub, struct cfg80211_internal_bss, pub); spin_lock_bh(&dev->bss_lock); + if (!list_empty(&bss->list)) { + list_del_init(&bss->list); + dev->bss_generation++; + rb_erase(&bss->rbn, &dev->bss_tree); - list_del(&bss->list); - dev->bss_generation++; - rb_erase(&bss->rbn, &dev->bss_tree); - + kref_put(&bss->ref, bss_release); + } spin_unlock_bh(&dev->bss_lock); - - kref_put(&bss->ref, bss_release); } EXPORT_SYMBOL(cfg80211_unlink_bss); From 2234362c427e2ef667595b9b81c0125003ac5607 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 30 Sep 2010 22:17:43 +0200 Subject: cfg80211: fix locking From: Johannes Berg commit 2234362c427e2ef667595b9b81c0125003ac5607 upstream. Add missing unlocking of the wiphy in set_channel, and don't try to unlock a non-existing wiphy in set_cqm. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -761,11 +761,13 @@ static int nl80211_set_channel(struct sk result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); if (result) - goto unlock; + goto unlock_rtnl; result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); - unlock: + dev_put(netdev); + cfg80211_unlock_rdev(rdev); + unlock_rtnl: rtnl_unlock(); return result; @@ -4996,7 +4998,7 @@ static int nl80211_set_cqm_rssi(struct g err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); if (err) - goto unlock_rdev; + goto unlock_rtnl; wdev = dev->ieee80211_ptr; @@ -5013,9 +5015,10 @@ static int nl80211_set_cqm_rssi(struct g err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, threshold, hysteresis); -unlock_rdev: + unlock_rdev: cfg80211_unlock_rdev(rdev); dev_put(dev); + unlock_rtnl: rtnl_unlock(); return err; From a171fba491f54216e356efa46096171a7ed01d10 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Mon, 18 Oct 2010 17:44:51 -0700 Subject: cfg80211: fix regression on processing country IEs From: Luis R. Rodriguez commit a171fba491f54216e356efa46096171a7ed01d10 upstream. The patch 4f366c5: wireless: only use alpha2 regulatory information from country IE removed some complex intersection we were always doing between the AP's country IE info and what we got from CRDA. When CRDA sent us back a regulatory domain we would do some sanity checks on that regulatory domain response we just got. Part of these sanity checks included checking that we already had performed an intersection for the request of NL80211_REGDOM_SET_BY_COUNTRY_IE type. This mean that cfg80211 was only processing country IEs for cases where we already had an intersection, but since we removed enforcing this this is no longer required, we should just apply the country IE country hint with the data received from CRDA. This patch has fixes intended for kernels >= 2.6.36. Reported-by: Easwar Krishnan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1170,7 +1170,7 @@ static int ignore_request(struct wiphy * return 0; return -EALREADY; } - return REG_INTERSECT; + return 0; case NL80211_REGDOM_SET_BY_DRIVER: if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { if (regdom_changes(pending_request->alpha2)) From 15d46f38df87f89242e470f5797120fa384c1fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sun, 10 Oct 2010 22:14:25 +0200 Subject: mac80211: minstrel_ht A-MPDU fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= commit 15d46f38df87f89242e470f5797120fa384c1fc3 upstream. This patch fixes two problems with the minstrel_ht rate control algorithms handling of A-MPDU frames: 1. The ampdu_len field of the tx status is not always initialized for non-HT frames (and it would probably be unreasonable to require all drivers to do so). This could cause rate control statistics to be corrupted. We now trust the ampdu_len and ampdu_ack_len fields only when the frame is marked with the IEEE80211_TX_STAT_AMPDU flag. 2. Successful transmission attempts where only recognized when the A-MPDU subframe carrying the rate control status information was marked with the IEEE80211_TX_STAT_ACK flag. If this information happed to be carried on a frame that failed to be ACKed then the other subframes (which may have succeeded) where not correctly registered. We now update rate control statistics regardless of whether the subframe carrying the information was ACKed or not. Signed-off-by: Björn Smedman Acked-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rc80211_minstrel_ht.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -397,8 +397,9 @@ minstrel_ht_tx_status(void *priv, struct !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - if (!info->status.ampdu_len) { - info->status.ampdu_ack_len = 1; + if (!(info->flags & IEEE80211_TX_STAT_AMPDU)) { + info->status.ampdu_ack_len = + (info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); info->status.ampdu_len = 1; } @@ -426,7 +427,7 @@ minstrel_ht_tx_status(void *priv, struct group = minstrel_ht_get_group_idx(&ar[i]); rate = &mi->groups[group].rates[ar[i].idx % 8]; - if (last && (info->flags & IEEE80211_TX_STAT_ACK)) + if (last) rate->success += info->status.ampdu_ack_len; rate->attempts += ar[i].count * info->status.ampdu_len; From d12c74528e3065c90df70fbc06ec6ffd6e804738 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Fri, 8 Oct 2010 22:27:07 +0200 Subject: mac80211: fix possible null-pointer de-reference From: Christian Lamparter commit d12c74528e3065c90df70fbc06ec6ffd6e804738 upstream. This patch not only fixes a null-pointer de-reference that would be triggered by a PLINK_OPEN frame with mis- matching/incompatible mesh configuration, but also responds correctly to non-compatible PLINK_OPEN frames by generating a PLINK_CLOSE with the right reason code. The original bug was detected by smatch. ( http://repo.or.cz/w/smatch.git ) net/mac80211/mesh_plink.c +574 mesh_rx_plink_frame(168) error: we previously assumed 'sta' could be null. Reviewed-and-Tested-by: Steve deRosier Reviewed-and-Tested-by: Javier Cardona Acked-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mesh_plink.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -412,7 +412,7 @@ void mesh_rx_plink_frame(struct ieee8021 enum plink_event event; enum plink_frame_type ftype; size_t baselen; - bool deactivated; + bool deactivated, matches_local = true; u8 ie_len; u8 *baseaddr; __le16 plid, llid, reason; @@ -487,6 +487,7 @@ void mesh_rx_plink_frame(struct ieee8021 /* Now we will figure out the appropriate event... */ event = PLINK_UNDEFINED; if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) { + matches_local = false; switch (ftype) { case PLINK_OPEN: event = OPN_RJCT; @@ -498,7 +499,15 @@ void mesh_rx_plink_frame(struct ieee8021 /* avoid warning */ break; } - spin_lock_bh(&sta->lock); + } + + if (!sta && !matches_local) { + rcu_read_unlock(); + reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); + llid = 0; + mesh_plink_frame_tx(sdata, PLINK_CLOSE, mgmt->sa, llid, + plid, reason); + return; } else if (!sta) { /* ftype == PLINK_OPEN */ u32 rates; @@ -522,7 +531,7 @@ void mesh_rx_plink_frame(struct ieee8021 } event = OPN_ACPT; spin_lock_bh(&sta->lock); - } else { + } else if (matches_local) { spin_lock_bh(&sta->lock); switch (ftype) { case PLINK_OPEN: @@ -564,6 +573,8 @@ void mesh_rx_plink_frame(struct ieee8021 rcu_read_unlock(); return; } + } else { + spin_lock_bh(&sta->lock); } mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", From e7480bbb926c5816e4fbfca70748096bbe0e4978 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Fri, 1 Oct 2010 17:05:19 -0400 Subject: mac80211: fix channel assumption for association done work From: Luis R. Rodriguez commit e7480bbb926c5816e4fbfca70748096bbe0e4978 upstream. Be consistent and use the wk->chan instead of the local->hw.conf.channel for the association done work. This prevents any possible races against channel changes while we run this work. In the case that the race did happen we would be initializing the bit rates for the new AP under the assumption of a wrong channel and in the worst case, wrong band. This could lead to trying to assuming we could use CCK frames on 5 GHz, for example. This patch has a fix for kernels >= v2.6.34 Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1262,7 +1262,7 @@ static bool ieee80211_assoc_success(stru rates = 0; basic_rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sband = local->hw.wiphy->bands[wk->chan->band]; for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; @@ -1298,11 +1298,11 @@ static bool ieee80211_assoc_success(stru } } - sta->sta.supp_rates[local->hw.conf.channel->band] = rates; + sta->sta.supp_rates[wk->chan->band] = rates; sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + if (wk->chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; else From 8d4780eb1ece4e8109b4f6b2e5e61f7fc593c3f4 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Fri, 24 Sep 2010 21:59:57 -0400 Subject: mac80211: fix offchannel assumption upon association From: Luis R. Rodriguez commit 8d4780eb1ece4e8109b4f6b2e5e61f7fc593c3f4 upstream. Association is dealt with as an atomic offchannel operation, we do this because we don't know we are associated until we get the associatin response from the AP. When we do get the associatin response though we were never clearing the offchannel state. This has a few implications, we told drivers we were still offchannel, and the first configured TX power for the channel does not take into account any power constraints. For ath9k this meant ANI calibration would not start upon association, and we'd have to wait until the first bgscan to be triggered. There may be other issues this resolves but I'm too lazy to comb the code to check. Cc: Amod Bodas Cc: Vasanth Thiagarajan Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -108,7 +108,8 @@ int ieee80211_hw_config(struct ieee80211 chan = scan_chan; channel_type = NL80211_CHAN_NO_HT; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; - } else if (local->tmp_channel) { + } else if (local->tmp_channel && + local->oper_channel != local->tmp_channel) { chan = scan_chan = local->tmp_channel; channel_type = local->tmp_channel_type; local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; From 3ba06c6fbd651ed3377e584026d1c112b492cc8b Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 27 Aug 2010 22:21:13 +0300 Subject: mac80211: Fix signal strength average initialization for CQM events From: Jouni Malinen commit 3ba06c6fbd651ed3377e584026d1c112b492cc8b upstream. The ave_beacon_signal value uses 1/16 dB unit and as such, must be initialized with the signal level of the first Beacon frame multiplied by 16. This fixes an issue where the initial CQM events are reported incorrectly with a burst of events while the running average approaches the correct value after the incorrect initialization. This could cause user space -based roaming decision process to get quite confused at the moment when we would like to go through authentication and DHCP. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1540,7 +1540,7 @@ static void ieee80211_rx_mgmt_beacon(str ifmgd->last_beacon_signal = rx_status->signal; if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) { ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE; - ifmgd->ave_beacon_signal = rx_status->signal; + ifmgd->ave_beacon_signal = rx_status->signal * 16; ifmgd->last_cqm_event_signal = 0; } else { ifmgd->ave_beacon_signal = From 4730d5977f3e12b828d354f7752cffd94bdf39e5 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:31 -0400 Subject: mac80211: reset connection idle when going offchannel From: Luis R. Rodriguez commit 4730d5977f3e12b828d354f7752cffd94bdf39e5 upstream. When we go offchannel mac80211 currently leaves alive the connection idle monitor. This should be instead postponed until we come back to our home channel, otherwise by the time we get back to the home channel we could be triggering unecesary probe requests. For APs that do not respond to unicast probe requests (Nexus One is a simple example) this means we essentially get disconnected after the probes fails. This patch has stable fixes for kernels [2.6.35+] Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/offchannel.c | 5 +++++ 1 file changed, 5 insertions(+) --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -22,12 +22,15 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; local->offchannel_ps_enabled = false; /* FIXME: what to do when local->pspolling is true? */ del_timer_sync(&local->dynamic_ps_timer); + del_timer_sync(&ifmgd->conn_mon_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); if (local->hw.conf.flags & IEEE80211_CONF_PS) { @@ -85,6 +88,8 @@ static void ieee80211_offchannel_ps_disa mod_timer(&local->dynamic_ps_timer, jiffies + msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } + + ieee80211_sta_reset_conn_monitor(sdata); } void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) From be099e82e9cf6d5d65d044e9ef6fc8bee3c7a113 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:29 -0400 Subject: mac80211: add helper for reseting the connection monitor From: Luis R. Rodriguez commit be099e82e9cf6d5d65d044e9ef6fc8bee3c7a113 upstream. This will be used in another place later. The connection monitor was added as of 2.6.35 so these fixes will be applicable to >= 2.6.35. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1003,6 +1003,7 @@ void ieee80211_sta_restart(struct ieee80 void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); /* IBSS code */ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -118,6 +118,15 @@ static void mod_beacon_timer(struct ieee round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); } +void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) + return; + + mod_timer(&sdata->u.mgd.conn_mon_timer, + round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -1006,11 +1015,7 @@ void ieee80211_sta_rx_notify(struct ieee if (is_multicast_ether_addr(hdr->addr1)) return; - if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) - return; - - mod_timer(&sdata->u.mgd.conn_mon_timer, - round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); + ieee80211_sta_reset_conn_monitor(sdata); } static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) From d3a910a8e4e846b9a767d35483f4dc7c6de7af82 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:32 -0400 Subject: mac80211: make the beacon monitor available externally From: Luis R. Rodriguez commit d3a910a8e4e846b9a767d35483f4dc7c6de7af82 upstream. This will be used by other components next. The beacon monitor was added as of 2.6.34 so these fixes are applicable only to kernels >= 2.6.34. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1003,6 +1003,7 @@ void ieee80211_sta_restart(struct ieee80 void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata); void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata); /* IBSS code */ --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -109,7 +109,7 @@ static void run_again(struct ieee80211_i mod_timer(&ifmgd->timer, timeout); } -static void mod_beacon_timer(struct ieee80211_sub_if_data *sdata) +void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) { if (sdata->local->hw.flags & IEEE80211_HW_BEACON_FILTER) return; @@ -1367,7 +1367,7 @@ static bool ieee80211_assoc_success(stru * Also start the timer that will detect beacon loss. */ ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); - mod_beacon_timer(sdata); + ieee80211_sta_reset_beacon_monitor(sdata); return true; } @@ -1470,7 +1470,7 @@ static void ieee80211_rx_mgmt_probe_resp * we have or will be receiving any beacons or data, so let's * schedule the timers again, just in case. */ - mod_beacon_timer(sdata); + ieee80211_sta_reset_beacon_monitor(sdata); mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(jiffies + @@ -1593,7 +1593,7 @@ static void ieee80211_rx_mgmt_beacon(str * Push the beacon loss detection into the future since * we are processing a beacon from the AP just now. */ - mod_beacon_timer(sdata); + ieee80211_sta_reset_beacon_monitor(sdata); ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4); ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable, From f01a067d9e4598c71e3c9ee3a84859d2e8af4f8e Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:34 -0400 Subject: mac80211: send last 3/5 probe requests as unicast From: Luis R. Rodriguez commit f01a067d9e4598c71e3c9ee3a84859d2e8af4f8e upstream. Some buggy APs do not respond to unicast probe requests or send unicast probe requests very delayed so in the worst case we should try to send broadcast probe requests, otherwise we can get disconnected from these APs. Even if drivers do not have filters to disregard probe responses from foreign APs mac80211 will only process probe responses from our associated AP for re-arming connection monitoring. We need to do this since the beacon monitor does not push back the connection monitor by design so even if we are getting beacons from these type of APs our connection monitor currently relies heavily on the way the probe requests are received on the AP. An example of an AP affected by this is the Nexus One, but this has also been observed with random APs. We can probably optimize this later by using null funcs instead of probe requests. For more details refer to: http://code.google.com/p/chromium-os/issues/detail?id=5715 This patch has fixes for stable kernels [2.6.35+]. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1022,10 +1022,19 @@ static void ieee80211_mgd_probe_ap_send( { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; const u8 *ssid; + u8 *dst = ifmgd->associated->bssid; + u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); + + /* + * Try sending broadcast probe requests for the last three + * probe requests after the first ones failed since some + * buggy APs only support broadcast probe requests. + */ + if (ifmgd->probe_send_count >= unicast_limit) + dst = NULL; ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); - ieee80211_send_probe_req(sdata, ifmgd->associated->bssid, - ssid + 2, ssid[1], NULL, 0); + ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); ifmgd->probe_send_count++; ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; From 3bc3c0d748402e8c1f31b8569f5924d25d7b8e30 Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:33 -0400 Subject: mac80211: disable beacon monitor while going offchannel From: Luis R. Rodriguez commit 3bc3c0d748402e8c1f31b8569f5924d25d7b8e30 upstream. The beacon monitor should be disabled when going off channel to prevent spurious warnings and triggering connection deterioration work such as sending probe requests. Re-enable the beacon monitor once we come back to the home channel. This patch has fixes for stable kernels [2.6.34+]. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/offchannel.c | 2 ++ 1 file changed, 2 insertions(+) --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -29,6 +29,7 @@ static void ieee80211_offchannel_ps_enab /* FIXME: what to do when local->pspolling is true? */ del_timer_sync(&local->dynamic_ps_timer); + del_timer_sync(&ifmgd->bcn_mon_timer); del_timer_sync(&ifmgd->conn_mon_timer); cancel_work_sync(&local->dynamic_ps_enable_work); @@ -89,6 +90,7 @@ static void ieee80211_offchannel_ps_disa msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); } + ieee80211_sta_reset_beacon_monitor(sdata); ieee80211_sta_reset_conn_monitor(sdata); } From f5521b13880f4f4f612e1d20dd4f565122d16e04 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 14 Sep 2010 22:06:53 +0200 Subject: mac80211: use correct station flags lock From: Johannes Berg commit f5521b13880f4f4f612e1d20dd4f565122d16e04 upstream. This code is modifying the station flags, and as such should hold the flags lock so it can do so atomically vs. other flags modifications and readers. This issue was introduced when this code was added in eccb8e8f, as it used the wrong lock (thus not fixing the race that was previously documented in a comment.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -634,6 +634,7 @@ static void sta_apply_parameters(struct struct sta_info *sta, struct station_parameters *params) { + unsigned long flags; u32 rates; int i, j; struct ieee80211_supported_band *sband; @@ -642,7 +643,7 @@ static void sta_apply_parameters(struct sband = local->hw.wiphy->bands[local->oper_channel->band]; - spin_lock_bh(&sta->lock); + spin_lock_irqsave(&sta->flaglock, flags); mask = params->sta_flags_mask; set = params->sta_flags_set; @@ -669,7 +670,7 @@ static void sta_apply_parameters(struct if (set & BIT(NL80211_STA_FLAG_MFP)) sta->flags |= WLAN_STA_MFP; } - spin_unlock_bh(&sta->lock); + spin_unlock_irqrestore(&sta->flaglock, flags); /* * cfg80211 validates this (1-2007) and allows setting the AID From eb7d3066cf864342e8ae6a5c1126a1602c4d06c0 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 21 Sep 2010 21:36:18 +0200 Subject: mac80211: clear txflags for ps-filtered frames From: Christian Lamparter commit eb7d3066cf864342e8ae6a5c1126a1602c4d06c0 upstream. This patch fixes stale mac80211_tx_control_flags for filtered / retried frames. Because ieee80211_handle_filtered_frame feeds skbs back into the tx path, they have to be stripped of some tx flags so they won't confuse the stack, driver or device. Acked-by: Johannes Berg Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- include/net/mac80211.h | 16 ++++++++++++++++ net/mac80211/status.c | 1 + 2 files changed, 17 insertions(+) --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -315,6 +315,9 @@ struct ieee80211_bss_conf { * @IEEE80211_TX_CTL_LDPC: tells the driver to use LDPC for this frame * @IEEE80211_TX_CTL_STBC: Enables Space-Time Block Coding (STBC) for this * frame and selects the maximum number of streams that it can use. + * + * Note: If you have to add new flags to the enumeration, then don't + * forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary. */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), @@ -344,6 +347,19 @@ enum mac80211_tx_control_flags { #define IEEE80211_TX_CTL_STBC_SHIFT 23 +/* + * This definition is used as a mask to clear all temporary flags, which are + * set by the tx handlers for each transmission attempt by the mac80211 stack. + */ +#define IEEE80211_TX_TEMPORARY_FLAGS (IEEE80211_TX_CTL_NO_ACK | \ + IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT | \ + IEEE80211_TX_CTL_SEND_AFTER_DTIM | IEEE80211_TX_CTL_AMPDU | \ + IEEE80211_TX_STAT_TX_FILTERED | IEEE80211_TX_STAT_ACK | \ + IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_STAT_AMPDU_NO_BACK | \ + IEEE80211_TX_CTL_RATE_CTRL_PROBE | IEEE80211_TX_CTL_PSPOLL_RESPONSE | \ + IEEE80211_TX_CTL_MORE_FRAMES | IEEE80211_TX_CTL_LDPC | \ + IEEE80211_TX_CTL_STBC) + /** * enum mac80211_rate_control_flags - per-rate flags set by the * Rate Control algorithm. --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -58,6 +58,7 @@ static void ieee80211_handle_filtered_fr info->control.vif = &sta->sdata->vif; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | IEEE80211_TX_INTFL_RETRANSMISSION; + info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; sta->tx_filtered_count++; From 0c699c3a75d4e8d0d2c317f83048d8fd3ffe692a Mon Sep 17 00:00:00 2001 From: Luis R. Rodriguez Date: Thu, 16 Sep 2010 15:12:30 -0400 Subject: mac80211: reset probe send counter upon connection timer reset From: Luis R. Rodriguez commit 0c699c3a75d4e8d0d2c317f83048d8fd3ffe692a upstream. Upon beacon loss we send probe requests after 30 seconds of idle time and we wait for each probe response 1/2 second. We send a total of 3 probe requests before giving up on the AP. In the case that we reset the connection idle monitor we should reset the probe requests count to 0. Right now this won't help in any way but the next patch will. This patch has fixes for stable kernel [2.6.35+]. Cc: Paul Stewart Cc: Amod Bodas Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 4 ++++ 1 file changed, 4 insertions(+) --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -120,11 +120,15 @@ void ieee80211_sta_reset_beacon_monitor( void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) return; mod_timer(&sdata->u.mgd.conn_mon_timer, round_jiffies_up(jiffies + IEEE80211_CONNECTION_IDLE_TIME)); + + ifmgd->probe_send_count = 0; } static int ecw2cw(int ecw) From c8716d9dc13c7f6ee92f2bfc6cc3b723b417bff8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 23 Oct 2010 10:59:57 +0530 Subject: mac80211: Fix ibss station got expired immediately From: Rajkumar Manoharan commit c8716d9dc13c7f6ee92f2bfc6cc3b723b417bff8 upstream. Station addition in ieee80211_ibss_rx_queued_mgmt is not updating sta->last_rx which is causing station expiry in ieee80211_ibss_work path. So sta addition and deletion happens repeatedly. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 1 + 1 file changed, 1 insertion(+) --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -435,6 +435,7 @@ struct sta_info *ieee80211_ibss_add_sta( if (!sta) return NULL; + sta->last_rx = jiffies; set_sta_flags(sta, WLAN_STA_AUTHORIZED); /* make sure mandatory rates are always added */ From 5f4e6b2d3c74c1adda1cbfd9d9d30da22c7484fc Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 16 Oct 2010 18:49:15 +0200 Subject: mac80211: don't sanitize invalid rates From: Christian Lamparter commit 5f4e6b2d3c74c1adda1cbfd9d9d30da22c7484fc upstream. I found this bug while poking around with a pure-gn AP. Commit: cfg80211/mac80211: Use more generic bitrate mask for rate control Added some sanity checks to ensure that each tx rate index is included in the configured mask and it would change any rate indexes if it wasn't. But, the current implementation doesn't take into account that the invalid rate index "-1" has a special meaning (= no further attempts) and it should not be "changed". Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rate.c | 3 +++ 1 file changed, 3 insertions(+) --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -328,6 +328,9 @@ void rate_control_get_rate(struct ieee80 * if needed. */ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* Skip invalid rates */ + if (info->control.rates[i].idx < 0) + break; /* Rate masking supports only legacy rates for now */ if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) continue; From 44271488b91c9eecf249e075a1805dd887e222d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Oct 2010 21:40:33 +0200 Subject: mac80211: delete AddBA response timer From: Johannes Berg commit 44271488b91c9eecf249e075a1805dd887e222d2 upstream. We never delete the addBA response timer, which is typically fine, but if the station it belongs to is deleted very quickly after starting the BA session, before the peer had a chance to reply, the timer may fire after the station struct has been freed already. Therefore, we need to delete the timer in a suitable spot -- best when the session is being stopped (which will happen even then) in which case the delete will be a no-op most of the time. I've reproduced the scenario and tested the fix. This fixes the crash reported at http://mid.gmane.org/4CAB6F96.6090701@candelatech.com Reported-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/agg-tx.c | 2 ++ 1 file changed, 2 insertions(+) --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -177,6 +177,8 @@ int ___ieee80211_stop_tx_ba_session(stru del_timer_sync(&tid_tx->addba_resp_timer); + del_timer_sync(&tid_tx->addba_resp_timer); + /* * After this packets are no longer handed right through * to the driver but are put onto tid_tx->pending instead, From c8701a08d6a4efeae45d84d0aa87172f23b14e3c Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:40 +0000 Subject: isdn/gigaset: fix bas_gigaset AT read error handling From: Tilman Schmidt commit c8701a08d6a4efeae45d84d0aa87172f23b14e3c upstream. Rework the handling of USB errors in AT response reads to fix a possible infinite retry loop and a memory leak, and silence a few overly verbose kernel messages. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/bas-gigaset.c | 83 ++++++++++++++----------------------- 1 file changed, 33 insertions(+), 50 deletions(-) --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -438,23 +438,27 @@ static void cmd_in_timeout(unsigned long return; } - if (ucs->retry_cmd_in++ < BAS_RETRY) { - dev_notice(cs->dev, "control read: timeout, retry %d\n", - ucs->retry_cmd_in); - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ - return; - } else { + if (ucs->retry_cmd_in++ >= BAS_RETRY) { dev_err(cs->dev, "control read: timeout, giving up after %d tries\n", ucs->retry_cmd_in); + kfree(ucs->rcvbuf); + ucs->rcvbuf = NULL; + ucs->rcvbuf_size = 0; + error_reset(cs); + return; + } + + gig_dbg(DEBUG_USBREQ, "%s: timeout, retry %d", + __func__, ucs->retry_cmd_in); + rc = atread_submit(cs, BAS_TIMEOUT); + if (rc < 0) { + kfree(ucs->rcvbuf); + ucs->rcvbuf = NULL; + ucs->rcvbuf_size = 0; + if (rc != -ENODEV) + error_reset(cs); } - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - error_reset(cs); } /* read_ctrl_callback @@ -470,18 +474,11 @@ static void read_ctrl_callback(struct ur struct cardstate *cs = inbuf->cs; struct bas_cardstate *ucs = cs->hw.bas; int status = urb->status; - int have_data = 0; unsigned numbytes; int rc; update_basstate(ucs, 0, BS_ATRDPEND); wake_up(&ucs->waitqueue); - - if (!ucs->rcvbuf_size) { - dev_warn(cs->dev, "%s: no receive in progress\n", __func__); - return; - } - del_timer(&ucs->timer_cmd_in); switch (status) { @@ -495,19 +492,10 @@ static void read_ctrl_callback(struct ur numbytes = ucs->rcvbuf_size; } - /* copy received bytes to inbuf */ - have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes); - - if (unlikely(numbytes < ucs->rcvbuf_size)) { - /* incomplete - resubmit for remaining bytes */ - ucs->rcvbuf_size -= numbytes; - ucs->retry_cmd_in = 0; - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ - return; - error_reset(cs); + /* copy received bytes to inbuf, notify event layer */ + if (gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes)) { + gig_dbg(DEBUG_INTR, "%s-->BH", __func__); + gigaset_schedule_event(cs); } break; @@ -516,37 +504,32 @@ static void read_ctrl_callback(struct ur case -EINPROGRESS: /* pending */ case -ENODEV: /* device removed */ case -ESHUTDOWN: /* device shut down */ - /* no action necessary */ + /* no further action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", __func__, get_usb_statmsg(status)); break; - default: /* severe trouble */ - dev_warn(cs->dev, "control read: %s\n", - get_usb_statmsg(status)); + default: /* other errors: retry */ if (ucs->retry_cmd_in++ < BAS_RETRY) { - dev_notice(cs->dev, "control read: retry %d\n", - ucs->retry_cmd_in); + gig_dbg(DEBUG_USBREQ, "%s: %s, retry %d", __func__, + get_usb_statmsg(status), ucs->retry_cmd_in); rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0 || rc == -ENODEV) - /* resubmitted or disconnected */ - /* - bypass regular exit block */ + if (rc >= 0) + /* successfully resubmitted, skip freeing */ return; - } else { - dev_err(cs->dev, - "control read: giving up after %d tries\n", - ucs->retry_cmd_in); + if (rc == -ENODEV) + /* disconnect, no further action necessary */ + break; } + dev_err(cs->dev, "control read: %s, giving up after %d tries\n", + get_usb_statmsg(status), ucs->retry_cmd_in); error_reset(cs); } + /* read finished, free buffer */ kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; - if (have_data) { - gig_dbg(DEBUG_INTR, "%s-->BH", __func__); - gigaset_schedule_event(cs); - } } /* atread_submit From f3d531b99fb30945b4a64d6e2e86e1e62605aca5 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:51 +0000 Subject: isdn/gigaset: correct bas_gigaset rx buffer handling From: Tilman Schmidt commit f3d531b99fb30945b4a64d6e2e86e1e62605aca5 upstream. In transparent data reception, avoid a NULL pointer dereference in case an skbuff cannot be allocated, remove an inappropriate call to the HDLC flush routine, and correct the accounting of received bytes for continued buffers. Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/isocdata.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -842,13 +842,14 @@ static inline void trans_receive(unsigne if (unlikely(bcs->ignore)) { bcs->ignore--; - hdlc_flush(bcs); return; } skb = bcs->rx_skb; - if (skb == NULL) + if (skb == NULL) { skb = gigaset_new_rx_skb(bcs); - bcs->hw.bas->goodbytes += skb->len; + if (skb == NULL) + return; + } dobytes = bcs->rx_bufsize - skb->len; while (count > 0) { dst = skb_put(skb, count < dobytes ? count : dobytes); @@ -860,6 +861,7 @@ static inline void trans_receive(unsigne if (dobytes == 0) { dump_bytes(DEBUG_STREAM_DUMP, "rcv data", skb->data, skb->len); + bcs->hw.bas->goodbytes += skb->len; gigaset_skb_rcvd(bcs, skb); skb = gigaset_new_rx_skb(bcs); if (skb == NULL) From b33ffa5cbf52ee751bb8068218ebb3c742c5a515 Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Thu, 30 Sep 2010 13:34:30 +0000 Subject: isdn/gigaset: bas_gigaset locking fix From: Tilman Schmidt commit b33ffa5cbf52ee751bb8068218ebb3c742c5a515 upstream. Unlock cs->lock before calling error_hangup() which is marked "cs->lock must not be held". Signed-off-by: Tilman Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/gigaset/bas-gigaset.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -1581,13 +1581,13 @@ static int gigaset_init_bchannel(struct ret = starturbs(bcs); if (ret < 0) { + spin_unlock_irqrestore(&cs->lock, flags); dev_err(cs->dev, "could not start isochronous I/O for channel B%d: %s\n", bcs->channel + 1, ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); if (ret != -ENODEV) error_hangup(bcs); - spin_unlock_irqrestore(&cs->lock, flags); return ret; } @@ -1597,11 +1597,11 @@ static int gigaset_init_bchannel(struct dev_err(cs->dev, "could not open channel B%d\n", bcs->channel + 1); stopurbs(bcs->hw.bas); - if (ret != -ENODEV) - error_hangup(bcs); } spin_unlock_irqrestore(&cs->lock, flags); + if (ret < 0 && ret != -ENODEV) + error_hangup(bcs); return ret; } From 323584436db0cb05286425d4dfd9516fce88487f Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sun, 24 Oct 2010 18:16:57 +0200 Subject: i2c-pca-platform: Change device name of request_irq From: Nobuhiro Iwamatsu commit 323584436db0cb05286425d4dfd9516fce88487f upstream. i2c->adap.name shouldn't be used in request_irq. Instead the driver name "i2c-pca-platform" should be used. Signed-off-by: Nobuhiro Iwamatsu Acked-by: Wolfram Sang Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-pca-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -224,7 +224,7 @@ static int __devinit i2c_pca_pf_probe(st if (irq) { ret = request_irq(irq, i2c_pca_pf_handler, - IRQF_TRIGGER_FALLING, i2c->adap.name, i2c); + IRQF_TRIGGER_FALLING, pdev->name, i2c); if (ret) goto e_reqirq; } From 85c5702ac046b14713f776d59768252d8ed8018f Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Fri, 17 Sep 2010 01:16:25 +0000 Subject: viafb: fix i2c_transfer error handling From: Florian Tobias Schandinat commit 85c5702ac046b14713f776d59768252d8ed8018f upstream. i2c_transfer returns negative errno on error and number of messages processed on success. Just returning this value would give a poor interface as it is not obvious that you must compare with 2 after reading 1 or n bytes and with 1 after writing 1 byte to determine if it was successful. To avoid this error prone interface convert the error code of a successful read/write to zero and all other non-negative values to an negative error code. This fixes a regression introduced by via: Rationalize vt1636 detection which resulted in no longer detecting a VT1636 chip and therefore has broken the output in configurations which contain this chip. Signed-off-by: Florian Tobias Schandinat Acked-by: Jonathan Corbet Cc: Joseph Chan Signed-off-by: Greg Kroah-Hartman --- drivers/video/via/via_i2c.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) --- a/drivers/video/via/via_i2c.c +++ b/drivers/video/via/via_i2c.c @@ -114,6 +114,7 @@ static void via_i2c_setsda(void *data, i int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) { + int ret; u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -126,11 +127,18 @@ int viafb_i2c_readbyte(u8 adap, u8 slave mm1[0] = index; msgs[0].len = 1; msgs[1].len = 1; msgs[0].buf = mm1; msgs[1].buf = pdata; - return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + if (ret == 2) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) { + int ret; u8 msg[2] = { index, data }; struct i2c_msg msgs; @@ -140,11 +148,18 @@ int viafb_i2c_writebyte(u8 adap, u8 slav msgs.addr = slave_addr / 2; msgs.len = 2; msgs.buf = msg; - return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); + ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); + if (ret == 1) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) { + int ret; u8 mm1[] = {0x00}; struct i2c_msg msgs[2]; @@ -156,7 +171,13 @@ int viafb_i2c_readbytes(u8 adap, u8 slav mm1[0] = index; msgs[0].len = 1; msgs[1].len = buff_len; msgs[0].buf = mm1; msgs[1].buf = buff; - return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); + if (ret == 2) + ret = 0; + else if (ret >= 0) + ret = -EIO; + + return ret; } /* From a5193fe50e7f21c26d22c17c8196420fac1a3ca7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 17 Nov 2010 17:56:49 -0500 Subject: drm/radeon/kms: register an i2c adapter name for the dp aux bus From: Alex Deucher commit a5193fe50e7f21c26d22c17c8196420fac1a3ca7 upstream. This causes the connector to not be added since i2c init fails for the adapter. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=31688 Noticed by Ari Savolainen. Signed-off-by: Alex Deucher Cc: Ari Savolainen Cc: Jean Delvare Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_i2c.c | 1 + 1 file changed, 1 insertion(+) --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -946,6 +946,7 @@ struct radeon_i2c_chan *radeon_i2c_creat i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; i2c->dev = dev; + sprintf(i2c->adapter.name, "Radeon aux bus %s", name); i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.algo_data = &i2c->algo.dp; i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; From 0e7adbe263f89ea2ef15b5af5e80a812b2a85025 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 25 Oct 2010 10:37:11 +0200 Subject: ALSA: hda - Disable sticky PCM stream assignment for AD codecs From: Takashi Iwai commit 0e7adbe263f89ea2ef15b5af5e80a812b2a85025 upstream. The sticky PCM stream assignment introduced in 2.6.36 kernel seems causing problems on AD codecs. At some time later, the streaming no longer works by unknown reason. A simple workaround is to disable sticky-assignment for these codecs. Tested-by: Vasily Khoruzhick Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 3 +++ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/patch_analog.c | 7 +++++++ 3 files changed, 11 insertions(+) --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1281,6 +1281,9 @@ void __snd_hda_codec_cleanup_stream(stru if (!nid) return; + if (codec->no_sticky_stream) + do_now = 1; + snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); p = get_hda_cvt_setup(codec, nid); if (p) { --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -850,6 +850,7 @@ struct hda_codec { unsigned int pin_amp_workaround:1; /* pin out-amp takes index * (e.g. Conexant codecs) */ + unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */ unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ #ifdef CONFIG_SND_HDA_POWER_SAVE --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1276,6 +1276,7 @@ static int patch_ad1986a(struct hda_code spec->multiout.no_share_stream = 1; codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -1463,6 +1464,7 @@ static int patch_ad1983(struct hda_codec codec->patch_ops = ad198x_patch_ops; codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -1917,6 +1919,7 @@ static int patch_ad1981(struct hda_codec } codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -3235,6 +3238,7 @@ static int patch_ad1988(struct hda_codec spec->vmaster_nid = 0x04; codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -3449,6 +3453,7 @@ static int patch_ad1884(struct hda_codec codec->patch_ops = ad198x_patch_ops; codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -4422,6 +4427,7 @@ static int patch_ad1884a(struct hda_code } codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } @@ -4761,6 +4767,7 @@ static int patch_ad1882(struct hda_codec } codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; return 0; } From 62b7e5e09bcb854ff05e6ee1aa161f8283dc36ee Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Oct 2010 17:15:47 +0200 Subject: ALSA: hda - Add workarounds for CT-IBG controllers From: Takashi Iwai commit 62b7e5e09bcb854ff05e6ee1aa161f8283dc36ee upstream. Creative IBG controllers require the playback stream-tags to be started from 1, instead of capture+1. Otherwise the stream stalls. Reported-by: Wai Yew CHAY Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 5 ++++- sound/pci/hda/hda_intel.c | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1216,6 +1216,7 @@ void snd_hda_codec_setup_stream(struct h struct hda_codec *c; struct hda_cvt_setup *p; unsigned int oldval, newval; + int type; int i; if (!nid) @@ -1254,10 +1255,12 @@ void snd_hda_codec_setup_stream(struct h p->dirty = 0; /* make other inactive cvts with the same stream-tag dirty */ + type = get_wcaps_type(get_wcaps(codec, nid)); list_for_each_entry(c, &codec->bus->codec_list, list) { for (i = 0; i < c->cvt_setups.used; i++) { p = snd_array_elem(&c->cvt_setups, i); - if (!p->active && p->stream_tag == stream_tag) + if (!p->active && p->stream_tag == stream_tag && + get_wcaps_type(get_wcaps(codec, p->nid)) == type) p->dirty = 1; } } --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1647,7 +1647,7 @@ static int azx_pcm_prepare(struct snd_pc struct azx_dev *azx_dev = get_azx_dev(substream); struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bufsize, period_bytes, format_val; + unsigned int bufsize, period_bytes, format_val, stream_tag; int err; azx_stream_reset(chip, azx_dev); @@ -1689,7 +1689,12 @@ static int azx_pcm_prepare(struct snd_pc else azx_dev->fifo_size = 0; - return snd_hda_codec_prepare(apcm->codec, hinfo, azx_dev->stream_tag, + stream_tag = azx_dev->stream_tag; + /* CA-IBG chips need the playback stream starting from 1 */ + if (chip->driver_type == AZX_DRIVER_CTX && + stream_tag > chip->capture_streams) + stream_tag -= chip->capture_streams; + return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, azx_dev->format_val, substream); } From 24b55c69b66eb2a122842820ec14ab215fc8572f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Oct 2010 08:55:13 +0200 Subject: ALSA: hda - Fix wrong SPDIF NID assignment for CA0110 From: Takashi Iwai commit 24b55c69b66eb2a122842820ec14ab215fc8572f upstream. The dig_out_nid field must take a digital-converter widget, but the current ca0110 parser passed the pin wrongly instead. Reported-by: Wai Yew CHAY Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_ca0110.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -489,7 +489,7 @@ static void parse_digital(struct hda_cod if (cfg->dig_outs && snd_hda_get_connections(codec, cfg->dig_out_pins[0], &spec->dig_out, 1) == 1) - spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; + spec->multiout.dig_out_nid = spec->dig_out; } static int ca0110_parse_auto_config(struct hda_codec *codec) From 14d34f166c57e77e3d7f9bc8b43d349186d922c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Oct 2010 09:03:25 +0200 Subject: ALSA: hda - Add some workarounds for Creative IBG From: Takashi Iwai commit 14d34f166c57e77e3d7f9bc8b43d349186d922c1 upstream. Creative HD-audio controller chips require some workarounds: - Additional delay before RIRB response - Set the initial RIRB counter to 0xc0 The latter seems to be done in general in Windows driver, so we may use this value later for all types if it's confirmed to work better. Reported-by: Wai Yew CHAY Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -458,6 +458,7 @@ enum { AZX_DRIVER_ULI, AZX_DRIVER_NVIDIA, AZX_DRIVER_TERA, + AZX_DRIVER_CTX, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -473,6 +474,7 @@ static char *driver_short_names[] __devi [AZX_DRIVER_ULI] = "HDA ULI M5461", [AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_TERA] = "HDA Teradici", + [AZX_DRIVER_CTX] = "HDA Creative", [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; @@ -563,7 +565,10 @@ static void azx_init_cmd_io(struct azx * /* reset the rirb hw write pointer */ azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); /* set N=1, get RIRB response interrupt for new entry */ - azx_writew(chip, RINTCNT, 1); + if (chip->driver_type == AZX_DRIVER_CTX) + azx_writew(chip, RINTCNT, 0xc0); + else + azx_writew(chip, RINTCNT, 1); /* enable rirb dma and response irq */ azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); spin_unlock_irq(&chip->reg_lock); @@ -1136,8 +1141,11 @@ static irqreturn_t azx_interrupt(int irq /* clear rirb int */ status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) + if (status & RIRB_INT_RESPONSE) { + if (chip->driver_type == AZX_DRIVER_CTX) + udelay(80); azx_update_rirb(chip); + } azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); } @@ -2799,10 +2807,10 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_GENERIC }, + .driver_data = AZX_DRIVER_CTX }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ - { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX }, #endif /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), From 838c364ff05c143fd1810e8ad1469935d6c23a7a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 8 Oct 2010 10:48:50 +0200 Subject: ALSA: OSS mixer emulation - fix locking From: Jaroslav Kysela commit 838c364ff05c143fd1810e8ad1469935d6c23a7a upstream. Fix mutex release and cleanup some locking code. Signed-off-by: Jaroslav Kysela Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/mixer_oss.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -618,8 +618,10 @@ static void snd_mixer_oss_put_volume1_vo if (numid == ID_UNKNOWN) return; down_read(&card->controls_rwsem); - if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + up_read(&card->controls_rwsem); return; + } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) @@ -658,7 +660,7 @@ static void snd_mixer_oss_put_volume1_sw return; down_read(&card->controls_rwsem); if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { - up_read(&fmixer->card->controls_rwsem); + up_read(&card->controls_rwsem); return; } uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); @@ -797,7 +799,7 @@ static int snd_mixer_oss_get_recsrc2(str uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; - goto __unlock; + goto __free_only; } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -826,6 +828,7 @@ static int snd_mixer_oss_get_recsrc2(str err = 0; __unlock: up_read(&card->controls_rwsem); + __free_only: kfree(uctl); kfree(uinfo); return err; @@ -847,7 +850,7 @@ static int snd_mixer_oss_put_recsrc2(str uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; - goto __unlock; + goto __free_only; } down_read(&card->controls_rwsem); kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0); @@ -880,6 +883,7 @@ static int snd_mixer_oss_put_recsrc2(str err = 0; __unlock: up_read(&card->controls_rwsem); + __free_only: kfree(uctl); kfree(uinfo); return err; From flameeyes@gmail.com Mon Nov 22 16:18:17 2010 From: David Henningsson Date: Mon, 25 Oct 2010 23:52:04 +0200 Subject: ALSA: HDA: Enable internal mic on Dell E6410 and Dell E6510 To: stable@kernel.org Cc: Takashi Iwai , David Henningsson Message-ID: <1288043524-31436-2-git-send-email-flameeyes@gmail.com> From: David Henningsson [Not upstream as .37 fixes this differently in a much more complete way that is not able to be backported easily.] (Ported on top of 2.6.36) BugLink: http://launchpad.net/bugs/628961 BugLink: http://launchpad.net/bugs/605047 Signed-off-by: David Henningsson Signed-off-by: Diego Elio Pettenò Acked-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -93,6 +93,7 @@ enum { STAC_92HD83XXX_REF, STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, + STAC_DELL_E6410, STAC_92HD83XXX_HP, STAC_HP_DV7_4000, STAC_92HD83XXX_MODELS @@ -1633,6 +1634,13 @@ static unsigned int dell_s14_pin_configs 0x40f000f0, 0x40f000f0, }; +/* Deliberately turn off 0x0f (Dock Mic) to make it choose Int Mic instead */ +static unsigned int dell_e6410_pin_configs[10] = { + 0x04a11020, 0x0421101f, 0x400000f0, 0x90170110, + 0x23011050, 0x40f000f0, 0x400000f0, 0x90a60130, + 0x40f000f0, 0x40f000f0, +}; + static unsigned int hp_dv7_4000_pin_configs[10] = { 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, @@ -1643,6 +1651,7 @@ static unsigned int *stac92hd83xxx_brd_t [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, + [STAC_DELL_E6410] = dell_e6410_pin_configs, [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, }; @@ -1651,6 +1660,7 @@ static const char *stac92hd83xxx_models[ [STAC_92HD83XXX_REF] = "ref", [STAC_92HD83XXX_PWR_REF] = "mic-ref", [STAC_DELL_S14] = "dell-s14", + [STAC_DELL_E6410] = "dell-e6410", [STAC_92HD83XXX_HP] = "hp", [STAC_HP_DV7_4000] = "hp-dv7-4000", }; @@ -1663,6 +1673,10 @@ static struct snd_pci_quirk stac92hd83xx "DFI LanParty", STAC_92HD83XXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x040a, + "Dell E6410", STAC_DELL_E6410), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x040b, + "Dell E6510", STAC_DELL_E6410), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, "HP", STAC_92HD83XXX_HP), {} /* terminator */ From 1c2c25c78740b2796c7c06640784cb6732fa4907 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 17 Nov 2010 16:32:59 +0000 Subject: powerpc: Fix call to subpage_protection() From: Michael Neuling commit 1c2c25c78740b2796c7c06640784cb6732fa4907 upstream. In: powerpc/mm: Fix pgtable cache cleanup with CONFIG_PPC_SUBPAGE_PROT commit d28513bc7f675d28b479db666d572e078ecf182d Author: David Gibson subpage_protection() was changed to to take an mm rather a pgdir but it didn't change calling site in hashpage_preload(). The change wasn't noticed at compile time since hashpage_preload() used a void* as the parameter to subpage_protection(). This is obviously wrong and can trigger the following crash when CONFIG_SLAB, CONFIG_DEBUG_SLAB, CONFIG_PPC_64K_PAGES CONFIG_PPC_SUBPAGE_PROT are enabled. Freeing unused kernel memory: 704k freed Unable to handle kernel paging request for data at address 0x6b6b6b6b6b6c49b7 Faulting instruction address: 0xc0000000000410f4 cpu 0x2: Vector: 300 (Data Access) at [c00000004233f590] pc: c0000000000410f4: .hash_preload+0x258/0x338 lr: c000000000041054: .hash_preload+0x1b8/0x338 sp: c00000004233f810 msr: 8000000000009032 dar: 6b6b6b6b6b6c49b7 dsisr: 40000000 current = 0xc00000007e2c0070 paca = 0xc000000007fe0500 pid = 1, comm = init enter ? for help [c00000004233f810] c000000000041020 .hash_preload+0x184/0x338 (unreliable) [c00000004233f8f0] c00000000003ed98 .update_mmu_cache+0xb0/0xd0 [c00000004233f990] c000000000157754 .__do_fault+0x48c/0x5dc [c00000004233faa0] c000000000158fd0 .handle_mm_fault+0x508/0xa8c [c00000004233fb90] c0000000006acdd4 .do_page_fault+0x428/0x6ac [c00000004233fe30] c000000000005260 handle_page_fault+0x20/0x74 Reported-by: Jim Keniston Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Neuling cc: David Gibson Signed-off-by: Greg Kroah-Hartman diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 83f534d..5e95844 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -1123,7 +1123,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea, else #endif /* CONFIG_PPC_HAS_HASH_64K */ rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize, - subpage_protection(pgdir, ea)); + subpage_protection(mm, ea)); /* Dump some info in case of hash insertion failure, they should * never happen so it is really useful to know if/when they do From 118df3d17f11733b294ea2cd988d56ee376ef9fd Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 24 Oct 2010 17:17:31 -0400 Subject: SUNRPC: After calling xprt_release(), we must restart from call_reserve From: Trond Myklebust commit 118df3d17f11733b294ea2cd988d56ee376ef9fd upstream. Rob Leslie reports seeing the following Oops after his Kerberos session expired. BUG: unable to handle kernel NULL pointer dereference at 00000058 IP: [] rpcauth_refreshcred+0x11/0x12c [sunrpc] *pde = 00000000 Oops: 0000 [#1] last sysfs file: /sys/devices/platform/pc87360.26144/temp3_input Modules linked in: autofs4 authenc esp4 xfrm4_mode_transport ipt_LOG ipt_REJECT xt_limit xt_state ipt_REDIRECT xt_owner xt_HL xt_hl xt_tcpudp xt_mark cls_u32 cls_tcindex sch_sfq sch_htb sch_dsmark geodewdt deflate ctr twofish_generic twofish_i586 twofish_common camellia serpent blowfish cast5 cbc xcbc rmd160 sha512_generic sha1_generic hmac crypto_null af_key rpcsec_gss_krb5 nfsd exportfs nfs lockd fscache nfs_acl auth_rpcgss sunrpc ip_gre sit tunnel4 dummy ext3 jbd nf_nat_irc nf_conntrack_irc nf_nat_ftp nf_conntrack_ftp iptable_mangle iptable_nat nf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 iptable_filter ip_tables x_tables pc8736x_gpio nsc_gpio pc87360 hwmon_vid loop aes_i586 aes_generic sha256_generic dm_crypt cs5535_gpio serio_raw cs5535_mfgpt hifn_795x des_generic geode_rng rng_core led_class ext4 mbcache jbd2 crc16 dm_mirror dm_region_hash dm_log dm_snapshot dm_mod sd_mod crc_t10dif ide_pci_generic cs5536 amd74xx ide_core pata_cs5536 ata_generic libata usb_storage via_rhine mii scsi_mod btrfs zlib_deflate crc32c libcrc32c [last unloaded: scsi_wait_scan] Pid: 12875, comm: sudo Not tainted 2.6.36-net5501 #1 / EIP: 0060:[] EFLAGS: 00010292 CPU: 0 EIP is at rpcauth_refreshcred+0x11/0x12c [sunrpc] EAX: 00000000 EBX: defb13a0 ECX: 00000006 EDX: e18683b8 ESI: defb13a0 EDI: 00000000 EBP: 00000000 ESP: de571d58 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068 Process sudo (pid: 12875, ti=de570000 task=decd1430 task.ti=de570000) Stack: e186e008 00000000 defb13a0 0000000d deda6000 e1868f22 e196f12b defb13a0 <0> defb13d8 00000000 00000000 e186e0aa 00000000 defb13a0 de571dac 00000000 <0> e186956c de571e34 debea5c0 de571dc8 e186967a 00000000 debea5c0 de571e34 Call Trace: [] ? rpc_wake_up_next+0x114/0x11b [sunrpc] [] ? call_decode+0x24a/0x5af [sunrpc] [] ? nfs4_xdr_dec_access+0x0/0xa2 [nfs] [] ? __rpc_execute+0x62/0x17b [sunrpc] [] ? rpc_run_task+0x91/0x97 [sunrpc] [] ? rpc_call_sync+0x40/0x5b [sunrpc] [] ? nfs4_proc_access+0x10a/0x176 [nfs] [] ? nfs_do_access+0x2b1/0x2c0 [nfs] [] ? rpcauth_lookupcred+0x62/0x84 [sunrpc] [] ? nfs_permission+0xad/0x13b [nfs] [] ? exec_permission+0x15/0x4b [] ? link_path_walk+0x4f/0x456 [] ? path_walk+0x4c/0xa8 [] ? do_path_lookup+0x1f/0x68 [] ? user_path_at+0x37/0x5f [] ? handle_mm_fault+0x229/0x55b [] ? sys_faccessat+0x93/0x146 [] ? sys_access+0xf/0x13 [] ? syscall_call+0x7/0xb Code: 0f 94 c2 84 d2 74 09 8b 44 24 0c e8 6a e9 8b de 83 c4 14 89 d8 5b 5e 5f 5d c3 55 57 56 53 83 ec 1c fc 89 c6 8b 40 10 89 44 24 04 <8b> 58 58 85 db 0f 85 d4 00 00 00 0f b7 46 70 8b 56 20 89 c5 83 EIP: [] rpcauth_refreshcred+0x11/0x12c [sunrpc] SS:ESP 0068:de571d58 CR2: 0000000000000058 This appears to be caused by the function rpc_verify_header() first calling xprt_release(), then doing a call_refresh. If we release the transport slot, we should _always_ jump back to call_reserve before calling anything else. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/clnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1675,7 +1675,7 @@ rpc_verify_header(struct rpc_task *task) rpcauth_invalcred(task); /* Ensure we obtain a new XID! */ xprt_release(task); - task->tk_action = call_refresh; + task->tk_action = call_reserve; goto out_retry; case RPC_AUTH_BADCRED: case RPC_AUTH_BADVERF: From b843e4ec01991a386a9e0e9030703524446e03da Mon Sep 17 00:00:00 2001 From: Thomas Backlund Date: Thu, 21 Oct 2010 13:19:10 +0300 Subject: microblaze: Fix build with make 3.82 From: Thomas Backlund commit b843e4ec01991a386a9e0e9030703524446e03da upstream. When running make headers_install_all on x86_64 and make 3.82 I hit this: arch/microblaze/Makefile:80: *** mixed implicit and normal rules. Stop. make: *** [headers_install_all] Error 2 So split the rules to satisfy make 3.82. Signed-off-by: Thomas Backlund Signed-off-by: Michal Simek Signed-off-by: Greg Kroah-Hartman --- arch/microblaze/Makefile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) --- a/arch/microblaze/Makefile +++ b/arch/microblaze/Makefile @@ -72,12 +72,16 @@ export MMU DTB all: linux.bin -BOOT_TARGETS = linux.bin linux.bin.gz simpleImage.% +# With make 3.82 we cannot mix normal and wildcard targets +BOOT_TARGETS1 = linux.bin linux.bin.gz +BOOT_TARGETS2 = simpleImage.% archclean: $(Q)$(MAKE) $(clean)=$(boot) -$(BOOT_TARGETS): vmlinux +$(BOOT_TARGETS1): vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ +$(BOOT_TARGETS2): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ define archhelp From be8c648051048bc66fbca590d00f3e8543ec32af Mon Sep 17 00:00:00 2001 From: Arnaud Patard Date: Thu, 21 Oct 2010 03:59:57 -0700 Subject: phy/marvell: fix 88e1121 support From: Arnaud Patard commit be8c648051048bc66fbca590d00f3e8543ec32af upstream. Commit c477d0447db08068a497e7beb892b2b2a7bff64b added support for RGMII rx/tx delays except that it ends up clearing rx/tx delays bit for modes differents that RGMII*ID. Due to this, ethernet is not working anymore on my guruplug server +. This patch is fixing that. Signed-off-by: Arnaud Patard Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/marvell.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -196,20 +196,27 @@ static int m88e1121_config_aneg(struct p MII_88E1121_PHY_MSCR_PAGE); if (err < 0) return err; - mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & - MII_88E1121_PHY_MSCR_DELAY_MASK; - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) - mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | - MII_88E1121_PHY_MSCR_TX_DELAY); - else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; - else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { - err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); - if (err < 0) - return err; + mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) & + MII_88E1121_PHY_MSCR_DELAY_MASK; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY | + MII_88E1121_PHY_MSCR_TX_DELAY); + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + mscr |= MII_88E1121_PHY_MSCR_RX_DELAY; + else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + mscr |= MII_88E1121_PHY_MSCR_TX_DELAY; + + err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr); + if (err < 0) + return err; + } phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage); From 6eaa61496fb3b93cceface7a296415fc4c030bce Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 4 Oct 2010 17:59:08 -0400 Subject: NFSv4: Don't call nfs4_reclaim_complete() on receiving NFS4ERR_STALE_CLIENTID From: Trond Myklebust commit 6eaa61496fb3b93cceface7a296415fc4c030bce upstream. If the server sends us an NFS4ERR_STALE_CLIENTID while the state management thread is busy reclaiming state, we do want to treat all state that wasn't reclaimed before the STALE_CLIENTID as if a network partition occurred (see the edge conditions described in RFC3530 and RFC5661). What we do not want to do is to send an nfs4_reclaim_complete(), since we haven't yet even started reclaiming state after the server rebooted. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4state.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1138,16 +1138,14 @@ static void nfs4_reclaim_complete(struct (void)ops->reclaim_complete(clp); } -static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) +static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp) { struct nfs4_state_owner *sp; struct rb_node *pos; struct nfs4_state *state; if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) - return; - - nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); + return 0; for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); @@ -1161,6 +1159,14 @@ static void nfs4_state_end_reclaim_reboo } nfs_delegation_reap_unclaimed(clp); + return 1; +} + +static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) +{ + if (!nfs4_state_clear_reclaim_reboot(clp)) + return; + nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops); } static void nfs_delegation_clear_all(struct nfs_client *clp) @@ -1187,7 +1193,7 @@ static int nfs4_recovery_handle_error(st case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_LEASE_MOVED: set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); - nfs4_state_end_reclaim_reboot(clp); + nfs4_state_clear_reclaim_reboot(clp); nfs4_state_start_reclaim_reboot(clp); break; case -NFS4ERR_EXPIRED: From ae1007d37e00144b72906a4bdc47d517ae91bcc1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 4 Oct 2010 17:59:08 -0400 Subject: NFSv4: Don't call nfs4_state_mark_reclaim_reboot() from error handlers From: Trond Myklebust commit ae1007d37e00144b72906a4bdc47d517ae91bcc1 upstream. In the case of a server reboot, the state recovery thread starts by calling nfs4_state_end_reclaim_reboot() in order to avoid edge conditions when the server reboots while the client is in the middle of recovery. However, if the client has already marked the nfs4_state as requiring reboot recovery, then the above behaviour will cause the recovery thread to treat the open as if it was part of such an edge condition: the open will be recovered as if it was part of a lease expiration (and all the locks will be lost). Fix is to remove the call to nfs4_state_mark_reclaim_reboot from nfs4_async_handle_error(), and nfs4_handle_exception(). Instead we leave it to the recovery thread to do this for us. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 6 ------ 1 file changed, 6 deletions(-) --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -255,9 +255,6 @@ static int nfs4_handle_exception(const s nfs4_state_mark_reclaim_nograce(clp, state); goto do_state_recovery; case -NFS4ERR_STALE_STATEID: - if (state == NULL) - break; - nfs4_state_mark_reclaim_reboot(clp, state); case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_EXPIRED: goto do_state_recovery; @@ -3490,9 +3487,6 @@ nfs4_async_handle_error(struct rpc_task nfs4_state_mark_reclaim_nograce(clp, state); goto do_state_recovery; case -NFS4ERR_STALE_STATEID: - if (state == NULL) - break; - nfs4_state_mark_reclaim_reboot(clp, state); case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_EXPIRED: goto do_state_recovery; From b0ed9dbc24f1fd912b2dd08b995153cafc1d5b1c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 4 Oct 2010 17:59:08 -0400 Subject: NFSv4: Fix open recovery From: Trond Myklebust commit b0ed9dbc24f1fd912b2dd08b995153cafc1d5b1c upstream. NFSv4 open recovery is currently broken: since we do not clear the state->flags states before attempting recovery, we end up with the 'can_open_cached()' function triggering. This again leads to no OPEN call being put on the wire. Reported-by: Sachin Prabhu Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 3 +++ 1 file changed, 3 insertions(+) --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1117,6 +1117,7 @@ static int nfs4_open_recover(struct nfs4 clear_bit(NFS_DELEGATED_STATE, &state->flags); smp_rmb(); if (state->n_rdwr != 0) { + clear_bit(NFS_O_RDWR_STATE, &state->flags); ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); if (ret != 0) return ret; @@ -1124,6 +1125,7 @@ static int nfs4_open_recover(struct nfs4 return -ESTALE; } if (state->n_wronly != 0) { + clear_bit(NFS_O_WRONLY_STATE, &state->flags); ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); if (ret != 0) return ret; @@ -1131,6 +1133,7 @@ static int nfs4_open_recover(struct nfs4 return -ESTALE; } if (state->n_rdonly != 0) { + clear_bit(NFS_O_RDONLY_STATE, &state->flags); ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); if (ret != 0) return ret; From bc4866b6e0b44f8ea0df22a16e5927714beb4983 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 4 Oct 2010 17:59:08 -0400 Subject: NFS: Don't SIGBUS if nfs_vm_page_mkwrite races with a cache invalidation From: Trond Myklebust commit bc4866b6e0b44f8ea0df22a16e5927714beb4983 upstream. In the case where we lock the page, and then find out that the page has been thrown out of the page cache, we should just return VM_FAULT_NOPAGE. This is what block_page_mkwrite() does in these situations. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/file.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -551,7 +551,7 @@ static int nfs_vm_page_mkwrite(struct vm struct file *filp = vma->vm_file; struct dentry *dentry = filp->f_path.dentry; unsigned pagelen; - int ret = -EINVAL; + int ret = VM_FAULT_NOPAGE; struct address_space *mapping; dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld)\n", @@ -567,21 +567,20 @@ static int nfs_vm_page_mkwrite(struct vm if (mapping != dentry->d_inode->i_mapping) goto out_unlock; - ret = 0; pagelen = nfs_page_length(page); if (pagelen == 0) goto out_unlock; - ret = nfs_flush_incompatible(filp, page); - if (ret != 0) - goto out_unlock; + ret = VM_FAULT_LOCKED; + if (nfs_flush_incompatible(filp, page) == 0 && + nfs_updatepage(filp, page, 0, pagelen) == 0) + goto out; - ret = nfs_updatepage(filp, page, 0, pagelen); + ret = VM_FAULT_SIGBUS; out_unlock: - if (!ret) - return VM_FAULT_LOCKED; unlock_page(page); - return VM_FAULT_SIGBUS; +out: + return ret; } static const struct vm_operations_struct nfs_file_vm_ops = { From b7d8cce5b558e0c0aa6898c9865356481598b46d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 25 Oct 2010 19:44:00 -0400 Subject: drm/radeon/kms: MC vram map needs to be >= pci aperture size From: Alex Deucher commit b7d8cce5b558e0c0aa6898c9865356481598b46d upstream. The vram map in the radeon memory controller needs to be >= the pci aperture size. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=28402 The problematic cards in the above bug have 64 MB of vram, but the pci aperture is 128 MB and the MC vram map was only 64 MB. This can lead to hangs. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r100.c | 3 +++ 1 file changed, 3 insertions(+) --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2318,6 +2318,9 @@ void r100_vram_init_sizes(struct radeon_ /* Fix for RN50, M6, M7 with 8/16/32(??) MBs of VRAM - * Novell bug 204882 + along with lots of ubuntu ones */ + if (rdev->mc.aper_size > config_aper_size) + config_aper_size = rdev->mc.aper_size; + if (config_aper_size > rdev->mc.real_vram_size) rdev->mc.mc_vram_size = config_aper_size; else From 881fe6c1d06bf49f4ab7aef212cdaf66bd059614 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 18 Oct 2010 23:54:56 -0400 Subject: drm/radeon/kms: properly compute group_size on 6xx/7xx From: Alex Deucher commit 881fe6c1d06bf49f4ab7aef212cdaf66bd059614 upstream. Needed for tiled surfaces. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r600.c | 7 +++++-- drivers/gpu/drm/radeon/rv770.c | 9 +++++---- 2 files changed, 10 insertions(+), 6 deletions(-) --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -1608,8 +1608,11 @@ void r600_gpu_init(struct radeon_device rdev->config.r600.tiling_npipes = rdev->config.r600.max_tile_pipes; rdev->config.r600.tiling_nbanks = 4 << ((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); tiling_config |= BANK_TILING((ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); - tiling_config |= GROUP_SIZE(0); - rdev->config.r600.tiling_group_size = 256; + tiling_config |= GROUP_SIZE((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); + if ((ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) + rdev->config.r600.tiling_group_size = 512; + else + rdev->config.r600.tiling_group_size = 256; tmp = (ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT; if (tmp > 3) { tiling_config |= ROW_TILING(3); --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -643,10 +643,11 @@ static void rv770_gpu_init(struct radeon else gb_tiling_config |= BANK_TILING((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT); rdev->config.rv770.tiling_nbanks = 4 << ((gb_tiling_config >> 4) & 0x3); - - gb_tiling_config |= GROUP_SIZE(0); - rdev->config.rv770.tiling_group_size = 256; - + gb_tiling_config |= GROUP_SIZE((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT); + if ((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) + rdev->config.rv770.tiling_group_size = 512; + else + rdev->config.rv770.tiling_group_size = 256; if (((mc_arb_ramcfg & NOOFROWS_MASK) >> NOOFROWS_SHIFT) > 3) { gb_tiling_config |= ROW_TILING(3); gb_tiling_config |= SAMPLE_SPLIT(3); From 2d7b8366ae4a9ec2183c30e432a4a9a495c82bcd Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 8 Oct 2010 10:21:06 +0100 Subject: drm/i915: Update hotplug interrupts register definitions for Sandybridge From: Yuanhan Liu commit 2d7b8366ae4a9ec2183c30e432a4a9a495c82bcd upstream. On Sandybridge, the bit definition for hotplug on SDE has changed, so update the code to new definition. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30378 Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 21 ++++++++++++++++----- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ 2 files changed, 20 insertions(+), 5 deletions(-) --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -310,6 +310,7 @@ irqreturn_t ironlake_irq_handler(struct drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; int ret = IRQ_NONE; u32 de_iir, gt_iir, de_ier, pch_iir; + u32 hotplug_mask; struct drm_i915_master_private *master_priv; struct intel_ring_buffer *render_ring = &dev_priv->render_ring; @@ -325,6 +326,11 @@ irqreturn_t ironlake_irq_handler(struct if (de_iir == 0 && gt_iir == 0 && pch_iir == 0) goto done; + if (HAS_PCH_CPT(dev)) + hotplug_mask = SDE_HOTPLUG_MASK_CPT; + else + hotplug_mask = SDE_HOTPLUG_MASK; + ret = IRQ_HANDLED; if (dev->primary->master) { @@ -366,10 +372,8 @@ irqreturn_t ironlake_irq_handler(struct drm_handle_vblank(dev, 1); /* check event from PCH */ - if ((de_iir & DE_PCH_EVENT) && - (pch_iir & SDE_HOTPLUG_MASK)) { + if ((de_iir & DE_PCH_EVENT) && (pch_iir & hotplug_mask)) queue_work(dev_priv->wq, &dev_priv->hotplug_work); - } if (de_iir & DE_PCU_EVENT) { I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS)); @@ -1424,8 +1428,7 @@ static int ironlake_irq_postinstall(stru u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT; - u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | - SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; + u32 hotplug_mask; dev_priv->irq_mask_reg = ~display_mask; dev_priv->de_irq_enable_reg = display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK; @@ -1450,6 +1453,14 @@ static int ironlake_irq_postinstall(stru I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg); (void) I915_READ(GTIER); + if (HAS_PCH_CPT(dev)) { + hotplug_mask = SDE_CRT_HOTPLUG_CPT | SDE_PORTB_HOTPLUG_CPT | + SDE_PORTC_HOTPLUG_CPT | SDE_PORTD_HOTPLUG_CPT ; + } else { + hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG | + SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG; + } + dev_priv->pch_irq_mask_reg = ~hotplug_mask; dev_priv->pch_irq_enable_reg = hotplug_mask; --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2551,6 +2551,10 @@ #define SDE_PORTD_HOTPLUG_CPT (1 << 23) #define SDE_PORTC_HOTPLUG_CPT (1 << 22) #define SDE_PORTB_HOTPLUG_CPT (1 << 21) +#define SDE_HOTPLUG_MASK_CPT (SDE_CRT_HOTPLUG_CPT | \ + SDE_PORTD_HOTPLUG_CPT | \ + SDE_PORTC_HOTPLUG_CPT | \ + SDE_PORTB_HOTPLUG_CPT) #define SDEISR 0xc4000 #define SDEIMR 0xc4004 From 2126d0a4a205e2d6b763434f892524cd60f74228 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 6 Oct 2010 00:13:04 -0400 Subject: drm/radeon/kms: make sure blit addr masks are 64 bit From: Alex Deucher commit 2126d0a4a205e2d6b763434f892524cd60f74228 upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r600_blit_kms.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -650,8 +650,8 @@ void r600_kms_blit_copy(struct radeon_de int src_x = src_gpu_addr & 255; int dst_x = dst_gpu_addr & 255; int h = 1; - src_gpu_addr = src_gpu_addr & ~255; - dst_gpu_addr = dst_gpu_addr & ~255; + src_gpu_addr = src_gpu_addr & ~255ULL; + dst_gpu_addr = dst_gpu_addr & ~255ULL; if (!src_x && !dst_x) { h = (cur_size / max_bytes); @@ -744,8 +744,8 @@ void r600_kms_blit_copy(struct radeon_de int src_x = (src_gpu_addr & 255); int dst_x = (dst_gpu_addr & 255); int h = 1; - src_gpu_addr = src_gpu_addr & ~255; - dst_gpu_addr = dst_gpu_addr & ~255; + src_gpu_addr = src_gpu_addr & ~255ULL; + dst_gpu_addr = dst_gpu_addr & ~255ULL; if (!src_x && !dst_x) { h = (cur_size / max_bytes); From 43b93fbffc2c080dba2e84df6fce8d7e6c0a2581 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 27 Oct 2010 01:02:35 -0400 Subject: drm/radeon/kms: fix handling of tex lookup disable in cs checker on r2xx From: Alex Deucher commit 43b93fbffc2c080dba2e84df6fce8d7e6c0a2581 upstream. There are cases when multiple texture units have to be enabled, but not actually used to sample. This patch checks to see if the lookup_disable bit is set and if so, skips the texture check. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=25544 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r100.c | 3 +++ drivers/gpu/drm/radeon/r100_track.h | 1 + drivers/gpu/drm/radeon/r200.c | 2 ++ drivers/gpu/drm/radeon/radeon_reg.h | 1 + 4 files changed, 7 insertions(+) --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3228,6 +3228,8 @@ static int r100_cs_track_texture_check(s for (u = 0; u < track->num_texture; u++) { if (!track->textures[u].enabled) continue; + if (track->textures[u].lookup_disable) + continue; robj = track->textures[u].robj; if (robj == NULL) { DRM_ERROR("No texture bound to unit %u\n", u); @@ -3462,6 +3464,7 @@ void r100_cs_track_clear(struct radeon_d track->textures[i].robj = NULL; /* CS IB emission code makes sure texture unit are disabled */ track->textures[i].enabled = false; + track->textures[i].lookup_disable = false; track->textures[i].roundup_w = true; track->textures[i].roundup_h = true; if (track->separate_cube) --- a/drivers/gpu/drm/radeon/r100_track.h +++ b/drivers/gpu/drm/radeon/r100_track.h @@ -46,6 +46,7 @@ struct r100_cs_track_texture { unsigned height_11; bool use_pitch; bool enabled; + bool lookup_disable; bool roundup_w; bool roundup_h; unsigned compress_format; --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -447,6 +447,8 @@ int r200_packet0_check(struct radeon_cs_ track->textures[i].width = 1 << ((idx_value >> RADEON_TXFORMAT_WIDTH_SHIFT) & RADEON_TXFORMAT_WIDTH_MASK); track->textures[i].height = 1 << ((idx_value >> RADEON_TXFORMAT_HEIGHT_SHIFT) & RADEON_TXFORMAT_HEIGHT_MASK); } + if (idx_value & R200_TXFORMAT_LOOKUP_DISABLE) + track->textures[i].lookup_disable = true; switch ((idx_value & RADEON_TXFORMAT_FORMAT_MASK)) { case R200_TXFORMAT_I8: case R200_TXFORMAT_RGB332: --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -2836,6 +2836,7 @@ # define R200_TXFORMAT_ST_ROUTE_STQ5 (5 << 24) # define R200_TXFORMAT_ST_ROUTE_MASK (7 << 24) # define R200_TXFORMAT_ST_ROUTE_SHIFT 24 +# define R200_TXFORMAT_LOOKUP_DISABLE (1 << 27) # define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28) # define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) # define R200_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) From 1510a97182b4ddb5fe3c4e8d05240f7cd6fd13e7 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 8 Oct 2010 10:18:01 +0100 Subject: drm/i915/crt: Make sure the hotplug interrupt is enabled From: Yuanhan Liu commit 1510a97182b4ddb5fe3c4e8d05240f7cd6fd13e7 upstream. After disabling the hotplug interrupts for VGA detection on Ironlake, be sure to re-enable them again afterwards. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=30378 Signed-off-by: Yuanhan Liu Signed-off-by: Chris Wilson Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_crt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -191,7 +191,8 @@ static bool intel_ironlake_crt_detect_ho DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { - I915_WRITE(PCH_ADPA, temp); + /* Make sure hotplug is enabled */ + I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE); (void)I915_READ(PCH_ADPA); } From c2873e9633fe908dccd36dbb1d370e9c59a1ca62 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 7 Oct 2010 09:20:12 +0100 Subject: drm/i915: Free hardware status page on unload when physically mapped From: Keith Packard commit c2873e9633fe908dccd36dbb1d370e9c59a1ca62 upstream. A physically mapped hardware status page is allocated at driver load time but was never freed. Call the existing code to free this page at driver unload time on hardware which uses this kind. Signed-off-by: Keith Packard [ickle: call before tearing down registers on KMS-only path, as pointed out by Dave Airlie] Signed-off-by: Chris Wilson Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ 1 file changed, 3 insertions(+) --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2306,6 +2306,9 @@ int i915_driver_unload(struct drm_device i915_gem_lastclose(dev); intel_cleanup_overlay(dev); + + if (!I915_NEED_GFX_HWS(dev)) + i915_free_hws(dev); } intel_teardown_mchbar(dev); From 382b09362711d7d03272230a33767015a277926e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 7 Oct 2010 16:01:25 -0700 Subject: drm/i915: diasable clock gating for the panel power sequencer From: Jesse Barnes commit 382b09362711d7d03272230a33767015a277926e upstream. Needed on Ibex Peak and Cougar Point or the panel won't always come on. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 7 +++++++ 2 files changed, 10 insertions(+) --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2726,6 +2726,9 @@ #define FDI_RXB_CHICKEN 0xc2010 #define FDI_RX_PHASE_SYNC_POINTER_ENABLE (1) +#define SOUTH_DSPCLK_GATE_D 0xc2020 +#define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) + /* CPU: FDI_TX */ #define FDI_TXA_CTL 0x60100 #define FDI_TXB_CTL 0x61100 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5674,6 +5674,13 @@ void intel_init_clock_gating(struct drm_ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + + /* * According to the spec the following bits should be set in * order to enable memory self-refresh * The bit 22/21 of 0x42004 From 0ddc1289f3ffd779779ddd3922f26ae7d0a21604 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 12 Aug 2010 09:35:00 +0100 Subject: drm/i915/overlay: Ensure that the reg_bo is in the GTT prior to writing. From: Chris Wilson commit 0ddc1289f3ffd779779ddd3922f26ae7d0a21604 upstream. Just makes sure that writes are not being aliased by the CPU cache and do make it out to main memory. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=24977 Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_overlay.c | 8 ++++++++ 1 file changed, 8 insertions(+) --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -1367,6 +1367,12 @@ void intel_setup_overlay(struct drm_devi goto out_free_bo; } overlay->flip_addr = overlay->reg_bo->gtt_offset; + + ret = i915_gem_object_set_to_gtt_domain(reg_bo, true); + if (ret) { + DRM_ERROR("failed to move overlay register bo into the GTT\n"); + goto out_unpin_bo; + } } else { ret = i915_gem_attach_phys_object(dev, reg_bo, I915_GEM_PHYS_OVERLAY_REGS, @@ -1399,6 +1405,8 @@ void intel_setup_overlay(struct drm_devi DRM_INFO("initialized overlay support\n"); return; +out_unpin_bo: + i915_gem_object_unpin(reg_bo); out_free_bo: drm_gem_object_unreference(reg_bo); out_free: From 62391f97babb7fe0c769830b6f0e0bd184bd0704 Mon Sep 17 00:00:00 2001 From: Ken Kawasaki Date: Fri, 29 Oct 2010 12:17:51 +0000 Subject: pcnet_cs: add new_id From: Ken Kawasaki commit 62391f97babb7fe0c769830b6f0e0bd184bd0704 upstream. pcnet_cs: add new_id: "corega Ether CF-TD" 10Base-T PCMCIA card. Signed-off-by: Ken Kawasaki Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/pcmcia/pcnet_cs.c | 1 + 1 file changed, 1 insertion(+) --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1622,6 +1622,7 @@ static struct pcmcia_device_id pcnet_ids PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9), PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722), PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2), + PCMCIA_DEVICE_PROD_ID12("corega", "Ether CF-TD", 0x0a21501a, 0x6589340a), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-TD", 0x5261440f, 0xc49bd73d), PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d), From d8b5fc01683c66060edc202d6bb5635365822181 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 7 Oct 2010 14:08:52 +0100 Subject: SH: Add missing consts to sys_execve() declaration From: David Howells commit d8b5fc01683c66060edc202d6bb5635365822181 upstream. Add missing consts to the sys_execve() declaration which result in the following error: arch/sh/kernel/process_32.c:303: error: conflicting types for 'sys_execve' /warthog/nfs/linux-2.6-fscache/arch/sh/include/asm/syscalls_32.h:24: error: previous declaration of 'sys_execve' was here Signed-off-by: David Howells Cc: Nobuhiro Iwamatsu Signed-off-by: Greg Kroah-Hartman --- arch/sh/include/asm/syscalls_32.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) --- a/arch/sh/include/asm/syscalls_32.h +++ b/arch/sh/include/asm/syscalls_32.h @@ -19,9 +19,10 @@ asmlinkage int sys_clone(unsigned long c asmlinkage int sys_vfork(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs __regs); -asmlinkage int sys_execve(const char __user *ufilename, char __user * __user *uargv, - char __user * __user *uenvp, unsigned long r7, - struct pt_regs __regs); +asmlinkage int sys_execve(const char __user *ufilename, + const char __user *const __user *uargv, + const char __user *const __user *uenvp, + unsigned long r7, struct pt_regs __regs); asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5, unsigned long r6, unsigned long r7, struct pt_regs __regs);