From b3b46d76d0fcbb1f737107cec1a1ee87bc5e5fd3 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 11 Aug 2011 12:06:28 -0400 Subject: APEI: Fix WHEA _OSC call Bit 0 of the support parameter to the OSC call should be set in order to indicate that the OS supports the WHEA mechanism. Stuart Hayes tracked an APEI issue on some Dell platforms down to this. Reported-by: Stuart Hayes Signed-off-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/apei/apei-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 8041248fce9..61540360d5c 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -618,7 +618,7 @@ int apei_osc_setup(void) }; capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; - capbuf[OSC_SUPPORT_TYPE] = 0; + capbuf[OSC_SUPPORT_TYPE] = 1; capbuf[OSC_CONTROL_TYPE] = 0; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)) -- cgit v1.2.3-70-g09d2 From 03ba176a29dae5b4849f45c0b5c89b9d78baa2c6 Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Wed, 10 Aug 2011 10:46:22 +0800 Subject: ACPI APEI: Add Kconfig option IRQ_WORK for GHES IRQ_WORK is used by GHES, but it is selected by PERF_EVENT. For now PERF_EVENT is selected by x86 by default, but in concept, IRQ_WORK should be selected by GHES, not by others. Signed-off-by: Chen Gong Signed-off-by: Len Brown --- drivers/acpi/apei/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index c34aa51af4e..e3f47872ec2 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -13,6 +13,7 @@ config ACPI_APEI_GHES bool "APEI Generic Hardware Error Source" depends on ACPI_APEI && X86 select ACPI_HED + select IRQ_WORK select LLIST select GENERIC_ALLOCATOR help -- cgit v1.2.3-70-g09d2 From 6f5986bce558e64fe867bff600a2127a3cb0c006 Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Mon, 15 Aug 2011 12:51:31 +0800 Subject: xen-blkback: Don't disconnect backend until state switched to XenbusStateClosed. When do block-attach/block-detach test with below steps, umount hangs in the guest. Furthermore shutdown ends up being stuck when umounting file-systems. 1. start guest. 2. attach new block device by xm block-attach in Dom0. 3. mount new disk in guest. 4. execute xm block-detach to detach the block device in dom0 until timeout 5. Any request to the disk will hung. Root cause: This issue is caused when setting backend device's state to 'XenbusStateClosing', which sends to the frontend the XenbusStateClosing notification. When frontend receives the notification it tries to release the disk in blkfront_closing(), but at that moment the disk is still in use by guest, so frontend refuses to close. Specifically it sets the disk state to XenbusStateClosing and sends the notification to backend - when backend receives the event, it disconnects the vbd from real device, and sets the vbd device state to XenbusStateClosing. The backend disconnects the real device/file, and any IO requests to the disk in guest will end up in ether, leaving disk DEAD and set to XenbusStateClosing. When the guest wants to disconnect the disk, umount will hang on blkif_release()->xlvbd_release_gendisk() as it is unable to send any IO to the disk, which prevents clean system shutdown. Solution: Don't disconnect backend until frontend state switched to XenbusStateClosed. Signed-off-by: Joe Jin Cc: Daniel Stodden Cc: Jens Axboe Cc: Annie Li Cc: Ian Campbell [v1: Modified description a bit] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/xenbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 6cc0db1bf52..7be3d0fe8ad 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -601,11 +601,11 @@ static void frontend_changed(struct xenbus_device *dev, break; case XenbusStateClosing: - xen_blkif_disconnect(be->blkif); xenbus_switch_state(dev, XenbusStateClosing); break; case XenbusStateClosed: + xen_blkif_disconnect(be->blkif); xenbus_switch_state(dev, XenbusStateClosed); if (xenbus_dev_is_online(dev)) break; -- cgit v1.2.3-70-g09d2 From 1bc05b0ae6448b20d46076899e0cc12ad999e50e Mon Sep 17 00:00:00 2001 From: Joe Jin Date: Mon, 15 Aug 2011 12:57:07 +0800 Subject: xen-blkback: fixed indentation and comments This patch fixes belows: 1. Fix code style issue. 2. Fix incorrect functions name in comments. Signed-off-by: Joe Jin Cc: Jens Axboe Cc: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/block/xen-blkback/common.h | 2 +- drivers/block/xen-blkback/xenbus.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 9e40b283a46..00c57c90e2d 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -46,7 +46,7 @@ #define DRV_PFX "xen-blkback:" #define DPRINTK(fmt, args...) \ - pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \ + pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \ __func__, __LINE__, ##args) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 7be3d0fe8ad..a96cb5f893a 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -590,7 +590,7 @@ static void frontend_changed(struct xenbus_device *dev, /* * Enforce precondition before potential leak point. - * blkif_disconnect() is idempotent. + * xen_blkif_disconnect() is idempotent. */ xen_blkif_disconnect(be->blkif); @@ -611,7 +611,7 @@ static void frontend_changed(struct xenbus_device *dev, break; /* fall through if not online */ case XenbusStateUnknown: - /* implies blkif_disconnect() via blkback_remove() */ + /* implies xen_blkif_disconnect() via xen_blkbk_remove() */ device_unregister(&dev->dev); break; -- cgit v1.2.3-70-g09d2 From 65299a3b788bd274bed92f9fa3232082c9f3ea70 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 23 Aug 2011 14:50:29 +0200 Subject: block: separate priority boosting from REQ_META Add a new REQ_PRIO to let requests preempt others in the cfq I/O schedule, and lave REQ_META purely for marking requests as metadata in blktrace. All existing callers of REQ_META except for XFS are updated to also set REQ_PRIO for now. Signed-off-by: Christoph Hellwig Reviewed-by: Namhyung Kim Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 20 ++++++++++---------- drivers/mmc/card/block.c | 3 +++ fs/ext3/inode.c | 4 ++-- fs/ext3/namei.c | 3 ++- fs/ext4/inode.c | 4 ++-- fs/ext4/namei.c | 3 ++- fs/gfs2/log.c | 4 ++-- fs/gfs2/meta_io.c | 6 +++--- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/quota.c | 2 +- include/linux/blk_types.h | 6 ++++-- 11 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index a33bd4377c6..16ace89613b 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -130,8 +130,8 @@ struct cfq_queue { unsigned long slice_end; long slice_resid; - /* pending metadata requests */ - int meta_pending; + /* pending priority requests */ + int prio_pending; /* number of requests that are on the dispatch list or inside driver */ int dispatched; @@ -684,8 +684,8 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2, if (rq_is_sync(rq1) != rq_is_sync(rq2)) return rq_is_sync(rq1) ? rq1 : rq2; - if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META) - return rq1->cmd_flags & REQ_META ? rq1 : rq2; + if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_PRIO) + return rq1->cmd_flags & REQ_PRIO ? rq1 : rq2; s1 = blk_rq_pos(rq1); s2 = blk_rq_pos(rq2); @@ -1612,9 +1612,9 @@ static void cfq_remove_request(struct request *rq) cfqq->cfqd->rq_queued--; cfq_blkiocg_update_io_remove_stats(&(RQ_CFQG(rq))->blkg, rq_data_dir(rq), rq_is_sync(rq)); - if (rq->cmd_flags & REQ_META) { - WARN_ON(!cfqq->meta_pending); - cfqq->meta_pending--; + if (rq->cmd_flags & REQ_PRIO) { + WARN_ON(!cfqq->prio_pending); + cfqq->prio_pending--; } } @@ -3372,7 +3372,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, * So both queues are sync. Let the new request get disk time if * it's a metadata request and the current queue is doing regular IO. */ - if ((rq->cmd_flags & REQ_META) && !cfqq->meta_pending) + if ((rq->cmd_flags & REQ_PRIO) && !cfqq->prio_pending) return true; /* @@ -3439,8 +3439,8 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_io_context *cic = RQ_CIC(rq); cfqd->rq_queued++; - if (rq->cmd_flags & REQ_META) - cfqq->meta_pending++; + if (rq->cmd_flags & REQ_PRIO) + cfqq->prio_pending++; cfq_update_io_thinktime(cfqd, cfqq, cic); cfq_update_io_seektime(cfqd, cfqq, rq); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1ff5486213f..4c1a648d00f 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -926,6 +926,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, /* * Reliable writes are used to implement Forced Unit Access and * REQ_META accesses, and are supported only on MMCs. + * + * XXX: this really needs a good explanation of why REQ_META + * is treated special. */ bool do_rel_wr = ((req->cmd_flags & REQ_FUA) || (req->cmd_flags & REQ_META)) && diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index bba7b96e0d9..12661e1deed 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1134,7 +1134,7 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode, return bh; if (buffer_uptodate(bh)) return bh; - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -2807,7 +2807,7 @@ make_io: trace_ext3_load_inode(inode); get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META, bh); + submit_bh(READ | REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ext3_error(inode->i_sb, "ext3_get_inode_loc", diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index c7d4032aa82..0629e09f651 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -922,7 +922,8 @@ restart: bh = ext3_getblk(NULL, dir, b++, 0, &err); bh_use[ra_max] = bh; if (bh) - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(READ | REQ_META | REQ_PRIO, + 1, &bh); } } if ((bh = bh_use[ra_ptr++]) == NULL) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1dfa18feeb3..c7cbb3d85d9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -650,7 +650,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, return bh; if (buffer_uptodate(bh)) return bh; - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -3301,7 +3301,7 @@ make_io: trace_ext4_load_inode(inode); get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META, bh); + submit_bh(READ | REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { EXT4_ERROR_INODE_BLOCK(inode, block, diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d36315ae629..1c924faeb6c 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -922,7 +922,8 @@ restart: bh = ext4_getblk(NULL, dir, b++, 0, &err); bh_use[ra_max] = bh; if (bh) - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(READ | REQ_META | REQ_PRIO, + 1, &bh); } } if ((bh = bh_use[ra_ptr++]) == NULL) diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 85c62923ee2..59864643436 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -624,9 +624,9 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) bh->b_end_io = end_buffer_write_sync; get_bh(bh); if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) - submit_bh(WRITE_SYNC | REQ_META, bh); + submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); else - submit_bh(WRITE_FLUSH_FUA | REQ_META, bh); + submit_bh(WRITE_FLUSH_FUA | REQ_META | REQ_PRIO, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 747238cd9f9..be29858900f 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -37,7 +37,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb { struct buffer_head *bh, *head; int nr_underway = 0; - int write_op = REQ_META | + int write_op = REQ_META | REQ_PRIO | (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); BUG_ON(!PageLocked(page)); @@ -225,7 +225,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, } bh->b_end_io = end_buffer_read_sync; get_bh(bh); - submit_bh(READ_SYNC | REQ_META, bh); + submit_bh(READ_SYNC | REQ_META | REQ_PRIO, bh); if (!(flags & DIO_WAIT)) return 0; @@ -435,7 +435,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) if (buffer_uptodate(first_bh)) goto out; if (!buffer_locked(first_bh)) - ll_rw_block(READ_SYNC | REQ_META, 1, &first_bh); + ll_rw_block(READ_SYNC | REQ_META | REQ_PRIO, 1, &first_bh); dblock++; extlen--; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 3bc073a4cf8..079587e5384 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -224,7 +224,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) bio->bi_end_io = end_bio_io_page; bio->bi_private = page; - submit_bio(READ_SYNC | REQ_META, bio); + submit_bio(READ_SYNC | REQ_META | REQ_PRIO, bio); wait_on_page_locked(page); bio_put(bio); if (!PageUptodate(page)) { diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 053434049db..0e8bb13381e 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -709,7 +709,7 @@ get_a_page: set_buffer_uptodate(bh); if (!buffer_uptodate(bh)) { - ll_rw_block(READ | REQ_META, 1, &bh); + ll_rw_block(READ | REQ_META | REQ_PRIO, 1, &bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) goto unlock_out; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 32f0076e844..71fc53bb8f1 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -124,6 +124,7 @@ enum rq_flag_bits { __REQ_SYNC, /* request is sync (sync write or read) */ __REQ_META, /* metadata io request */ + __REQ_PRIO, /* boost priority in cfq */ __REQ_DISCARD, /* request to discard sectors */ __REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */ @@ -161,14 +162,15 @@ enum rq_flag_bits { #define REQ_FAILFAST_DRIVER (1 << __REQ_FAILFAST_DRIVER) #define REQ_SYNC (1 << __REQ_SYNC) #define REQ_META (1 << __REQ_META) +#define REQ_PRIO (1 << __REQ_PRIO) #define REQ_DISCARD (1 << __REQ_DISCARD) #define REQ_NOIDLE (1 << __REQ_NOIDLE) #define REQ_FAILFAST_MASK \ (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) #define REQ_COMMON_MASK \ - (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_DISCARD | \ - REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE) + (REQ_WRITE | REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | \ + REQ_DISCARD | REQ_NOIDLE | REQ_FLUSH | REQ_FUA | REQ_SECURE) #define REQ_CLONE_MASK REQ_COMMON_MASK #define REQ_RAHEAD (1 << __REQ_RAHEAD) -- cgit v1.2.3-70-g09d2 From 1a878284473284f9577d44babf16d87152a05c33 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 29 Jul 2011 17:16:40 -0700 Subject: [SCSI] isci: fix sata response handling A bug (likely copy/paste) that has been carried from the original implementation. The unsolicited frame handling structure returns the d2h fis in the isci_request.stp.rsp buffer. Cc: Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/request.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index a46e07ac789..b4cf998385b 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -2399,22 +2399,19 @@ static void isci_task_save_for_upper_layer_completion( } } -static void isci_request_process_stp_response(struct sas_task *task, - void *response_buffer) +static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis) { - struct dev_to_host_fis *d2h_reg_fis = response_buffer; struct task_status_struct *ts = &task->task_status; struct ata_task_resp *resp = (void *)&ts->buf[0]; - resp->frame_len = le16_to_cpu(*(__le16 *)(response_buffer + 6)); - memcpy(&resp->ending_fis[0], response_buffer + 16, 24); + resp->frame_len = sizeof(*fis); + memcpy(resp->ending_fis, fis, sizeof(*fis)); ts->buf_valid_size = sizeof(*resp); - /** - * If the device fault bit is set in the status register, then + /* If the device fault bit is set in the status register, then * set the sense data and return. */ - if (d2h_reg_fis->status & ATA_DF) + if (fis->status & ATA_DF) ts->stat = SAS_PROTO_RESPONSE; else ts->stat = SAM_STAT_GOOD; @@ -2428,7 +2425,6 @@ static void isci_request_io_request_complete(struct isci_host *ihost, { struct sas_task *task = isci_request_access_task(request); struct ssp_response_iu *resp_iu; - void *resp_buf; unsigned long task_flags; struct isci_remote_device *idev = isci_lookup_device(task->dev); enum service_response response = SAS_TASK_UNDELIVERED; @@ -2565,9 +2561,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost, task); if (sas_protocol_ata(task->task_proto)) { - resp_buf = &request->stp.rsp; - isci_request_process_stp_response(task, - resp_buf); + isci_process_stp_response(task, &request->stp.rsp); } else if (SAS_PROTOCOL_SSP == task->task_proto) { /* crack the iu response buffer. */ -- cgit v1.2.3-70-g09d2 From ee33e2b771f9e9e4aaba2bb2ace7b727fe451a8b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 29 Jul 2011 17:16:45 -0700 Subject: [SCSI] isci: fix 32-bit operation when CONFIG_HIGHMEM64G=n The unsolicited frame control infrastructure requires a table of dma addresses for the hardware to lookup the frame buffer location by an index. The hardware expects the elements of this table to be 64-bit quantities, so we cannot reference these elements as dma_addr_t. All unsolicited frame protocols are affected, particularly SATA-PIO and SMP which prevented direct-attached SATA drives and expander-attached drives to not be discovered. Cc: Reported-by: Jacek Danecki Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/unsolicited_frame_control.c | 2 +- drivers/scsi/isci/unsolicited_frame_control.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/isci/unsolicited_frame_control.c b/drivers/scsi/isci/unsolicited_frame_control.c index e9e1e2abacb..16f88ab939c 100644 --- a/drivers/scsi/isci/unsolicited_frame_control.c +++ b/drivers/scsi/isci/unsolicited_frame_control.c @@ -72,7 +72,7 @@ int sci_unsolicited_frame_control_construct(struct isci_host *ihost) */ buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE; header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header); - size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(dma_addr_t); + size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]); /* * The Unsolicited Frame buffers are set at the start of the UF diff --git a/drivers/scsi/isci/unsolicited_frame_control.h b/drivers/scsi/isci/unsolicited_frame_control.h index 31cb9506f52..75d896686f5 100644 --- a/drivers/scsi/isci/unsolicited_frame_control.h +++ b/drivers/scsi/isci/unsolicited_frame_control.h @@ -214,7 +214,7 @@ struct sci_uf_address_table_array { * starting address of the UF address table. * 64-bit pointers are required by the hardware. */ - dma_addr_t *array; + u64 *array; /** * This field specifies the physical address location for the UF -- cgit v1.2.3-70-g09d2 From 985af6f70dbb8a33b3af8a7c7df508d924650e37 Mon Sep 17 00:00:00 2001 From: Marcin Tomczak Date: Fri, 29 Jul 2011 17:16:50 -0700 Subject: [SCSI] isci: change sas phy timeouts from 54us to 59us Need the following workaround in the driver for interoperability with the older Intel SSD drives and any other SATA drive that may exhibit the same behavior. This is a corner case where SCU speed is limited to either 3G or 1.5G and the drive has a period of DC idle when it switches speed during SATA speed negotiation. Workaround :change PHYTOV[31:24] from 0x36 to 0x3B. Signed-off-by: Marcin Tomczak Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/phy.c | 13 +++++++++++++ drivers/scsi/isci/registers.h | 12 ++++++++++++ 2 files changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 79313a7a235..430fc8ff014 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -104,6 +104,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, u32 parity_count = 0; u32 llctl, link_rate; u32 clksm_value = 0; + u32 sp_timeouts = 0; iphy->link_layer_registers = reg; @@ -211,6 +212,18 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy, llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); writel(llctl, &iphy->link_layer_registers->link_layer_control); + sp_timeouts = readl(&iphy->link_layer_registers->sas_phy_timeouts); + + /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ + sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); + + /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can + * lock with 3Gb drive when SCU max rate is set to 1.5Gb. + */ + sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); + + writel(sp_timeouts, &iphy->link_layer_registers->sas_phy_timeouts); + if (is_a2(ihost->pdev)) { /* Program the max ARB time for the PHY to 700us so we inter-operate with * the PMC expander which shuts down PHYs if the expander PHY generates too diff --git a/drivers/scsi/isci/registers.h b/drivers/scsi/isci/registers.h index 9b266c7428e..00afc738bbe 100644 --- a/drivers/scsi/isci/registers.h +++ b/drivers/scsi/isci/registers.h @@ -1299,6 +1299,18 @@ struct scu_transport_layer_registers { #define SCU_AFE_XCVRCR_OFFSET 0x00DC #define SCU_AFE_LUTCR_OFFSET 0x00E0 +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL) +#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL) + +#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \ + SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value) + #define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0) #define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003) #define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0) -- cgit v1.2.3-70-g09d2 From 3a7bda830fad427768ed71c0ebf3448849c006b5 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 29 Jul 2011 17:17:00 -0700 Subject: [SCSI] isci: Adding documentation to API change and fixup sysfs registration Adding API update for adding isci_id entry scsi_host sysfs entry. Also fixing up the sysfs registration to the scsi_host template Signed-off-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- Documentation/ABI/testing/sysfs-class-scsi_host | 13 +++++++++ drivers/scsi/isci/init.c | 36 ++++++++++++------------- 2 files changed, 31 insertions(+), 18 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-scsi_host (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-scsi_host b/Documentation/ABI/testing/sysfs-class-scsi_host new file mode 100644 index 00000000000..29a4f892e43 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-scsi_host @@ -0,0 +1,13 @@ +What: /sys/class/scsi_host/hostX/isci_id +Date: June 2011 +Contact: Dave Jiang +Description: + This file contains the enumerated host ID for the Intel + SCU controller. The Intel(R) C600 Series Chipset SATA/SAS + Storage Control Unit embeds up to two 4-port controllers in + a single PCI device. The controllers are enumerated in order + which usually means the lowest number scsi_host corresponds + with the first controller, but this association is not + guaranteed. The 'isci_id' attribute unambiguously identifies + the controller index: '0' for the first controller, + '1' for the second. diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 61e0d09e2b5..e78320bbec4 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "isci.h" #include "task.h" #include "probe_roms.h" @@ -113,6 +114,22 @@ unsigned char max_concurr_spinup = 1; module_param(max_concurr_spinup, byte, 0); MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); +static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev); + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); + struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha); + + return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id); +} + +static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL); + +struct device_attribute *isci_host_attrs[] = { + &dev_attr_isci_id, + NULL +}; + static struct scsi_host_template isci_sht = { .module = THIS_MODULE, @@ -138,6 +155,7 @@ static struct scsi_host_template isci_sht = { .slave_alloc = sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, + .shost_attrs = isci_host_attrs, }; static struct sas_domain_function_template isci_transport_ops = { @@ -232,17 +250,6 @@ static int isci_register_sas_ha(struct isci_host *isci_host) return 0; } -static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha); - - return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id); -} - -static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL); - static void isci_unregister(struct isci_host *isci_host) { struct Scsi_Host *shost; @@ -251,7 +258,6 @@ static void isci_unregister(struct isci_host *isci_host) return; shost = isci_host->shost; - device_remove_file(&shost->shost_dev, &dev_attr_isci_id); sas_unregister_ha(&isci_host->sas_ha); @@ -415,14 +421,8 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) if (err) goto err_shost_remove; - err = device_create_file(&shost->shost_dev, &dev_attr_isci_id); - if (err) - goto err_unregister_ha; - return isci_host; - err_unregister_ha: - sas_unregister_ha(&(isci_host->sas_ha)); err_shost_remove: scsi_remove_host(shost); err_shost: -- cgit v1.2.3-70-g09d2 From 39ea2c5b5ffaa344467da53e885cfa4ac0105050 Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Fri, 29 Jul 2011 17:17:05 -0700 Subject: [SCSI] isci: Leave requests alone if already terminating. Instead of immediately completing any request that has a second termination call made on it, wait for the TC done/abort HW event. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/request.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index b4cf998385b..b5d3a8c4d32 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -732,12 +732,20 @@ sci_io_request_terminate(struct isci_request *ireq) sci_change_state(&ireq->sm, SCI_REQ_ABORTING); return SCI_SUCCESS; case SCI_REQ_TASK_WAIT_TC_RESP: + /* The task frame was already confirmed to have been + * sent by the SCU HW. Since the state machine is + * now only waiting for the task response itself, + * abort the request and complete it immediately + * and don't wait for the task response. + */ sci_change_state(&ireq->sm, SCI_REQ_ABORTING); sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); return SCI_SUCCESS; case SCI_REQ_ABORTING: - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; + /* If a request has a termination requested twice, return + * a failure indication, since HW confirmation of the first + * abort is still outstanding. + */ case SCI_REQ_COMPLETED: default: dev_warn(&ireq->owning_controller->pdev->dev, -- cgit v1.2.3-70-g09d2 From 9b4be528999483d70a1ffc0accd102e477d5a503 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 29 Jul 2011 17:17:10 -0700 Subject: [SCSI] isci: dynamic interrupt coalescing Hardware allows both an outstanding number commands and a timeout value (whichever occurs first) as a gate to the next interrupt generation. This scheme at completion time looks at the remaining number of outstanding tasks and sets the timeout to maximize small transaction operation. If transactions are large (take more than a few 10s of microseconds to complete) then performance is not interrupt processing bound, so the small timeouts this scheme generates are overridden by the time it takes for a completion to arrive. Tested-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 10 +++++++++- drivers/scsi/isci/host.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 26072f1e985..2328f98c7f1 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -1091,6 +1091,7 @@ static void isci_host_completion_routine(unsigned long data) struct isci_request *request; struct isci_request *next_request; struct sas_task *task; + u16 active; INIT_LIST_HEAD(&completed_request_list); INIT_LIST_HEAD(&errored_request_list); @@ -1181,6 +1182,13 @@ static void isci_host_completion_routine(unsigned long data) } } + /* the coalesence timeout doubles at each encoding step, so + * update it based on the ilog2 value of the outstanding requests + */ + active = isci_tci_active(ihost); + writel(SMU_ICC_GEN_VAL(NUMBER, active) | + SMU_ICC_GEN_VAL(TIMER, ISCI_COALESCE_BASE + ilog2(active)), + &ihost->smu_registers->interrupt_coalesce_control); } /** @@ -1471,7 +1479,7 @@ static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm) struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); /* set the default interrupt coalescence number and timeout value. */ - sci_controller_set_interrupt_coalescence(ihost, 0x10, 250); + sci_controller_set_interrupt_coalescence(ihost, 0, 0); } static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm) diff --git a/drivers/scsi/isci/host.h b/drivers/scsi/isci/host.h index 062101a39f7..9f33831a2f0 100644 --- a/drivers/scsi/isci/host.h +++ b/drivers/scsi/isci/host.h @@ -369,6 +369,9 @@ static inline struct isci_host *dev_to_ihost(struct domain_device *dev) #define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1)) #define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1)) +/* interrupt coalescing baseline: 9 == 3 to 5us interrupt delay per command */ +#define ISCI_COALESCE_BASE 9 + /* expander attached sata devices require 3 rnc slots */ static inline int sci_remote_device_node_count(struct isci_remote_device *idev) { -- cgit v1.2.3-70-g09d2 From 77cd72a53f6426f81b7f56a862402849ee903bda Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 29 Jul 2011 17:17:16 -0700 Subject: [SCSI] isci: fix event-get pointer increment Hardware only increments the put pointer on event types >= 4. Do not increment the get pointer for event type 3. Reported-by: Kapil Karkra Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/host.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index 2328f98c7f1..6981b773a88 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c @@ -531,6 +531,9 @@ static void sci_controller_process_completions(struct isci_host *ihost) break; case SCU_COMPLETION_TYPE_EVENT: + sci_controller_event_completion(ihost, ent); + break; + case SCU_COMPLETION_TYPE_NOTIFY: { event_cycle ^= ((event_get+1) & SCU_MAX_EVENTS) << (SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT - SCU_MAX_EVENTS_SHIFT); -- cgit v1.2.3-70-g09d2 From 98e2a5a3a125608505783bdb95744997f76b3c30 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 29 Jul 2011 17:17:21 -0700 Subject: [SCSI] isci: add version number Signed-off-by: Dan Williams Signed-off-by: James Bottomley --- drivers/scsi/isci/init.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index e78320bbec4..29aa34efb0f 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -64,6 +64,14 @@ #include "task.h" #include "probe_roms.h" +#define MAJ 1 +#define MIN 0 +#define BUILD 0 +#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ + __stringify(BUILD) + +MODULE_VERSION(DRV_VERSION); + static struct scsi_transport_template *isci_transport_template; static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { @@ -540,7 +548,8 @@ static __init int isci_init(void) { int err; - pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME); + pr_info("%s: Intel(R) C600 SAS Controller Driver - version %s\n", + DRV_NAME, DRV_VERSION); isci_transport_template = sas_domain_attach_transport(&isci_transport_ops); if (!isci_transport_template) -- cgit v1.2.3-70-g09d2 From 0b0e1d6cbcc8627970e0399df8f06edd690ec7d9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 9 Aug 2011 08:17:30 -0500 Subject: [SCSI] hpsa: fix problem that OBDR devices are not detected The test to detect OBDR ("One Button Disaster Recovery") cd-rom devices was comparing against uninitialized data. Fixed by moving the test for the device to where the inquiry data is collected, and uninitialized variable altogether as it wasn't really being used. Signed-off-by: Stephen M. Cameron Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ec61bdb833a..1f32f0610bc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1548,10 +1548,17 @@ static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device, } static int hpsa_update_device_info(struct ctlr_info *h, - unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device) + unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, + unsigned char *is_OBDR_device) { -#define OBDR_TAPE_INQ_SIZE 49 + +#define OBDR_SIG_OFFSET 43 +#define OBDR_TAPE_SIG "$DR-10" +#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1) +#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN) + unsigned char *inq_buff; + unsigned char *obdr_sig; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (!inq_buff) @@ -1583,6 +1590,16 @@ static int hpsa_update_device_info(struct ctlr_info *h, else this_device->raid_level = RAID_UNKNOWN; + if (is_OBDR_device) { + /* See if this is a One-Button-Disaster-Recovery device + * by looking for "$DR-10" at offset 43 in inquiry data. + */ + obdr_sig = &inq_buff[OBDR_SIG_OFFSET]; + *is_OBDR_device = (this_device->devtype == TYPE_ROM && + strncmp(obdr_sig, OBDR_TAPE_SIG, + OBDR_SIG_LEN) == 0); + } + kfree(inq_buff); return 0; @@ -1716,7 +1733,7 @@ static int add_msa2xxx_enclosure_device(struct ctlr_info *h, return 0; } - if (hpsa_update_device_info(h, scsi3addr, this_device)) + if (hpsa_update_device_info(h, scsi3addr, this_device, NULL)) return 0; (*nmsa2xxx_enclosures)++; hpsa_set_bus_target_lun(this_device, bus, target, 0); @@ -1808,7 +1825,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) */ struct ReportLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; - unsigned char *inq_buff = NULL; u32 nphysicals = 0; u32 nlogicals = 0; u32 ndev_allocated = 0; @@ -1824,11 +1840,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) GFP_KERNEL); physdev_list = kzalloc(reportlunsize, GFP_KERNEL); logdev_list = kzalloc(reportlunsize, GFP_KERNEL); - inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); - if (!currentsd || !physdev_list || !logdev_list || - !inq_buff || !tmpdevice) { + if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } @@ -1863,7 +1877,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) /* adjust our table of devices */ nmsa2xxx_enclosures = 0; for (i = 0; i < nphysicals + nlogicals + 1; i++) { - u8 *lunaddrbytes; + u8 *lunaddrbytes, is_OBDR = 0; /* Figure out where the LUN ID info is coming from */ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, @@ -1874,7 +1888,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) continue; /* Get device type, vendor, model, device id */ - if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice)) + if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, + &is_OBDR)) continue; /* skip it if we can't talk to it. */ figure_bus_target_lun(h, lunaddrbytes, &bus, &target, &lun, tmpdevice); @@ -1898,7 +1913,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) hpsa_set_bus_target_lun(this_device, bus, target, lun); switch (this_device->devtype) { - case TYPE_ROM: { + case TYPE_ROM: /* We don't *really* support actual CD-ROM devices, * just "One Button Disaster Recovery" tape drive * which temporarily pretends to be a CD-ROM drive. @@ -1906,15 +1921,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) * device by checking for "$DR-10" in bytes 43-48 of * the inquiry data. */ - char obdr_sig[7]; -#define OBDR_TAPE_SIG "$DR-10" - strncpy(obdr_sig, &inq_buff[43], 6); - obdr_sig[6] = '\0'; - if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0) - /* Not OBDR device, ignore it. */ - break; - } - ncurrent++; + if (is_OBDR) + ncurrent++; break; case TYPE_DISK: if (i < nphysicals) @@ -1947,7 +1955,6 @@ out: for (i = 0; i < ndev_allocated; i++) kfree(currentsd[i]); kfree(currentsd); - kfree(inq_buff); kfree(physdev_list); kfree(logdev_list); } -- cgit v1.2.3-70-g09d2 From 01350d05539d1c95ef3568d062d864ab76ae7670 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Tue, 9 Aug 2011 08:18:01 -0500 Subject: [SCSI] hpsa: fix physical device lun and target numbering problem If a physical device exposed to the OS by hpsa is replaced (e.g. one hot plug tape drive is replaced by another, or a tape drive is placed into "OBDR" mode in which it acts like a CD-ROM device) and a rescan is initiated, the replaced device will be added to the SCSI midlayer with target and lun numbers set to -1. After that, a panic is likely to ensue. When a physical device is replaced, the lun and target number should be preserved. Signed-off-by: Stephen M. Cameron Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1f32f0610bc..b200b736b00 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -676,6 +676,16 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA); removed[*nremoved] = h->dev[entry]; (*nremoved)++; + + /* + * New physical devices won't have target/lun assigned yet + * so we need to preserve the values in the slot we are replacing. + */ + if (new_entry->target == -1) { + new_entry->target = h->dev[entry]->target; + new_entry->lun = h->dev[entry]->lun; + } + h->dev[entry] = new_entry; added[*nadded] = new_entry; (*nadded)++; -- cgit v1.2.3-70-g09d2 From cfb7d557242783bc3bfe77683ced20b4909258ec Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 26 Aug 2011 23:10:02 -0700 Subject: Input: wacom - remove pressure for touch devices Touch devices do not report valid pressure or capacitance. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_sys.c | 14 -------------- drivers/input/tablet/wacom_wac.c | 6 +++--- 2 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index d27c9d91630..958b4eb6369 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -229,13 +229,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi get_unaligned_le16(&report[i + 3]); i += 4; } - } else if (usage == WCM_DIGITIZER) { - /* max pressure isn't reported - features->pressure_max = (unsigned short) - (report[i+4] << 8 | report[i + 3]); - */ - features->pressure_max = 255; - i += 4; } break; @@ -291,13 +284,6 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi pen = 1; i++; break; - - case HID_USAGE_UNDEFINED: - if (usage == WCM_DESKTOP && finger) /* capacity */ - features->pressure_max = - get_unaligned_le16(&report[i + 3]); - i += 4; - break; } break; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c1c2f7b28d8..3eccf212d5b 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -818,7 +818,6 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) x <<= 5; y <<= 5; } - input_report_abs(input, ABS_MT_PRESSURE, p); input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); } @@ -1056,10 +1055,11 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, features->x_fuzz, 0); input_set_abs_params(input_dev, ABS_Y, 0, features->y_max, features->y_fuzz, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, - features->pressure_fuzz, 0); if (features->device_type == BTN_TOOL_PEN) { + input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, + features->pressure_fuzz, 0); + /* penabled devices have fixed resolution for each model */ input_abs_set_res(input_dev, ABS_X, features->x_resolution); input_abs_set_res(input_dev, ABS_Y, features->y_resolution); -- cgit v1.2.3-70-g09d2 From 1fab84aa635572fbd74df8fd4fd25ea0a24c76e5 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Fri, 26 Aug 2011 23:18:22 -0700 Subject: Input: wacom - advertise BTN_TOOL_PEN and BTN_STYLUS for PenPartner The Wacom PenPartner should advertise its stylus tip and button in addition to the eraser tool. These are both physically present on the hardware, and emitted from 'wacom_penpartner_irq'. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 3eccf212d5b..2d88316d0e5 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1191,13 +1191,13 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case PL: case PTU: case DTU: - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); __set_bit(BTN_STYLUS2, input_dev->keybit); /* fall through */ case PENPARTNER: + __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); + __set_bit(BTN_STYLUS, input_dev->keybit); break; case BAMBOO_PT: -- cgit v1.2.3-70-g09d2 From 7b727acc412c9320dc56a0fd7312febf8710ac0e Mon Sep 17 00:00:00 2001 From: axel lin Date: Thu, 25 Aug 2011 09:42:09 -0700 Subject: Input: cm109 - fix checking return value of usb_control_msg If successful, usb_control_msg returns the number of bytes transferred, otherwise a negative error number. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cm109.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index b09c7d12721..ab860511f01 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -475,7 +475,7 @@ static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on) le16_to_cpu(dev->ctl_req->wIndex), dev->ctl_data, USB_PKT_LEN, USB_CTRL_SET_TIMEOUT); - if (error && error != EINTR) + if (error < 0 && error != -EINTR) err("%s: usb_control_msg() failed %d", __func__, error); } -- cgit v1.2.3-70-g09d2 From 8c6756603976e9d21bba9913cd80c38ec529a1fb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 26 Aug 2011 23:37:33 -0700 Subject: Input: adp5588-keys - remove incorrect modalias For i2c drivers, we should use "i2c:" prefix for modalias. MODULE_DEVICE_TABLE will setup the modulalias for us, thus adding a MODULE_ALIAS is redundant (in addition to being incorrect). Signed-off-by: Axel Lin Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5588-keys.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 7b404e5443e..e34eeb8ae37 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -668,4 +668,3 @@ module_exit(adp5588_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("ADP5588/87 Keypad driver"); -MODULE_ALIAS("platform:adp5588-keys"); -- cgit v1.2.3-70-g09d2 From 8cb2049c744809193ed3707a37c09676a24599ee Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 16 Aug 2011 11:29:22 -0700 Subject: [SCSI] qla2xxx: T10 DIF - Handle uninitalized sectors. Driver needs to update protection bytes for uninitialized sectors as they are not DMA-d. Signed-off-by: Arun Easi Reviewed-by: Andrew Vasquez Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 5 +- drivers/scsi/qla2xxx/qla_fw.h | 5 + drivers/scsi/qla2xxx/qla_inline.h | 21 ++++ drivers/scsi/qla2xxx/qla_iocb.c | 233 +++++++++++++++++++++++++++++++++++--- drivers/scsi/qla2xxx/qla_isr.c | 90 ++++++++++++--- drivers/scsi/qla2xxx/qla_os.c | 19 +++- 6 files changed, 335 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7836eb01c7f..81006709980 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1788,11 +1788,14 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { + int prot = 0; vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_user, vha, 0x7082, "Registered for DIF/DIX type 1 and 3 protection.\n"); + if (ql2xenabledif == 1) + prot = SHOST_DIX_TYPE0_PROTECTION; scsi_host_set_prot(vha->host, - SHOST_DIF_TYPE1_PROTECTION + prot | SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 691783abfb6..aa69486dc06 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -537,6 +537,11 @@ struct sts_entry_24xx { /* * If DIF Error is set in comp_status, these additional fields are * defined: + * + * !!! NOTE: Firmware sends expected/actual DIF data in big endian + * format; but all of the "data" field gets swab32-d in the beginning + * of qla2x00_status_entry(). + * * &data[10] : uint8_t report_runt_bg[2]; - computed guard * &data[12] : uint8_t actual_dif[8]; - DIF Data received * &data[20] : uint8_t expected_dif[8]; - DIF Data computed diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index d2e904bc21c..c06e5f9b431 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -102,3 +102,24 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state) fcport->d_id.b.al_pa); } } + +static inline int +qla2x00_hba_err_chk_enabled(unsigned char op) +{ + switch (op) { + case SCSI_PROT_READ_STRIP: + case SCSI_PROT_WRITE_INSERT: + if (ql2xenablehba_err_chk >= 1) + return 1; + break; + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + if (ql2xenablehba_err_chk >= 2) + return 1; + break; + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + return 1; + } + return 0; +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 49d6906af88..09ad3ce6006 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -717,12 +717,17 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, unsigned char op = scsi_get_prot_op(cmd); switch (scsi_get_prot_type(cmd)) { - /* For TYPE 0 protection: no checking */ case SCSI_PROT_DIF_TYPE0: - pkt->ref_tag_mask[0] = 0x00; - pkt->ref_tag_mask[1] = 0x00; - pkt->ref_tag_mask[2] = 0x00; - pkt->ref_tag_mask[3] = 0x00; + /* + * No check for ql2xenablehba_err_chk, as it would be an + * I/O error if hba tag generation is not done. + */ + pkt->ref_tag = cpu_to_le32((uint32_t) + (0xffffffff & scsi_get_lba(cmd))); + pkt->ref_tag_mask[0] = 0xff; + pkt->ref_tag_mask[1] = 0xff; + pkt->ref_tag_mask[2] = 0xff; + pkt->ref_tag_mask[3] = 0xff; break; /* @@ -730,7 +735,7 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, * match LBA in CDB + N */ case SCSI_PROT_DIF_TYPE2: - if (!ql2xenablehba_err_chk) + if (!qla2x00_hba_err_chk_enabled(op)) break; if (scsi_prot_sg_count(cmd)) { @@ -763,7 +768,7 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, * 16 bit app tag. */ case SCSI_PROT_DIF_TYPE1: - if (!ql2xenablehba_err_chk) + if (!qla2x00_hba_err_chk_enabled(op)) break; if (protcnt && (op == SCSI_PROT_WRITE_STRIP || @@ -798,7 +803,161 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, scsi_get_prot_type(cmd), cmd); } +struct qla2_sgx { + dma_addr_t dma_addr; /* OUT */ + uint32_t dma_len; /* OUT */ + + uint32_t tot_bytes; /* IN */ + struct scatterlist *cur_sg; /* IN */ + + /* for book keeping, bzero on initial invocation */ + uint32_t bytes_consumed; + uint32_t num_bytes; + uint32_t tot_partial; + + /* for debugging */ + uint32_t num_sg; + srb_t *sp; +}; + +static int +qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, + uint32_t *partial) +{ + struct scatterlist *sg; + uint32_t cumulative_partial, sg_len; + dma_addr_t sg_dma_addr; + + if (sgx->num_bytes == sgx->tot_bytes) + return 0; + + sg = sgx->cur_sg; + cumulative_partial = sgx->tot_partial; + + sg_dma_addr = sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed; + + if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) { + sgx->dma_len = (blk_sz - cumulative_partial); + sgx->tot_partial = 0; + sgx->num_bytes += blk_sz; + *partial = 0; + } else { + sgx->dma_len = sg_len - sgx->bytes_consumed; + sgx->tot_partial += sgx->dma_len; + *partial = 1; + } + + sgx->bytes_consumed += sgx->dma_len; + + if (sg_len == sgx->bytes_consumed) { + sg = sg_next(sg); + sgx->num_sg++; + sgx->cur_sg = sg; + sgx->bytes_consumed = 0; + } + + return 1; +} +static int +qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, + uint32_t *dsd, uint16_t tot_dsds) +{ + void *next_dsd; + uint8_t avail_dsds = 0; + uint32_t dsd_list_len; + struct dsd_dma *dsd_ptr; + struct scatterlist *sg_prot; + uint32_t *cur_dsd = dsd; + uint16_t used_dsds = tot_dsds; + + uint32_t prot_int; + uint32_t partial; + struct qla2_sgx sgx; + dma_addr_t sle_dma; + uint32_t sle_dma_len, tot_prot_dma_len = 0; + struct scsi_cmnd *cmd = sp->cmd; + + prot_int = cmd->device->sector_size; + + memset(&sgx, 0, sizeof(struct qla2_sgx)); + sgx.tot_bytes = scsi_bufflen(sp->cmd); + sgx.cur_sg = scsi_sglist(sp->cmd); + sgx.sp = sp; + + sg_prot = scsi_prot_sglist(sp->cmd); + + while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) { + + sle_dma = sgx.dma_addr; + sle_dma_len = sgx.dma_len; +alloc_and_fill: + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); + if (!dsd_ptr) + return 1; + + /* allocate new list */ + dsd_ptr->dsd_addr = next_dsd = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + + if (!next_dsd) { + /* + * Need to cleanup only this dsd_ptr, rest + * will be done by sp_free_dma() + */ + kfree(dsd_ptr); + return 1; + } + + list_add_tail(&dsd_ptr->list, + &((struct crc_context *)sp->ctx)->dsd_list); + + sp->flags |= SRB_CRC_CTX_DSD_VALID; + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = (uint32_t *)next_dsd; + } + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sle_dma_len); + avail_dsds--; + + if (partial == 0) { + /* Got a full protection interval */ + sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len; + sle_dma_len = 8; + + tot_prot_dma_len += sle_dma_len; + if (tot_prot_dma_len == sg_dma_len(sg_prot)) { + tot_prot_dma_len = 0; + sg_prot = sg_next(sg_prot); + } + + partial = 1; /* So as to not re-enter this block */ + goto alloc_and_fill; + } + } + /* Null termination */ + *cur_dsd++ = 0; + *cur_dsd++ = 0; + *cur_dsd++ = 0; + return 0; +} static int qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, uint16_t tot_dsds) @@ -981,7 +1140,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *cur_seg; int sgc; - uint32_t total_bytes; + uint32_t total_bytes = 0; uint32_t data_bytes; uint32_t dif_bytes; uint8_t bundling = 1; @@ -1023,8 +1182,10 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, __constant_cpu_to_le16(CF_READ_DATA); } - tot_prot_dsds = scsi_prot_sg_count(cmd); - if (!tot_prot_dsds) + if ((scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_INSERT) || + (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_STRIP) || + (scsi_get_prot_op(sp->cmd) == SCSI_PROT_READ_STRIP) || + (scsi_get_prot_op(sp->cmd) == SCSI_PROT_WRITE_INSERT)) bundling = 0; /* Allocate CRC context from global pool */ @@ -1107,15 +1268,28 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ /* Compute dif len and adjust data len to incude protection */ - total_bytes = data_bytes; dif_bytes = 0; blk_size = cmd->device->sector_size; - if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { - dif_bytes = (data_bytes / blk_size) * 8; - total_bytes += dif_bytes; + dif_bytes = (data_bytes / blk_size) * 8; + + switch (scsi_get_prot_op(sp->cmd)) { + case SCSI_PROT_READ_INSERT: + case SCSI_PROT_WRITE_STRIP: + total_bytes = data_bytes; + data_bytes += dif_bytes; + break; + + case SCSI_PROT_READ_STRIP: + case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_READ_PASS: + case SCSI_PROT_WRITE_PASS: + total_bytes = data_bytes + dif_bytes; + break; + default: + BUG(); } - if (!ql2xenablehba_err_chk) + if (!qla2x00_hba_err_chk_enabled(scsi_get_prot_op(cmd))) fw_prot_opts |= 0x10; /* Disable Guard tag checking */ if (!bundling) { @@ -1151,7 +1325,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, cmd_pkt->control_flags |= __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); - if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, + + if (!bundling && tot_prot_dsds) { + if (qla24xx_walk_and_build_sglist_no_difb(ha, sp, + cur_dsd, tot_dsds)) + goto crc_queuing_error; + } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, (tot_dsds - tot_prot_dsds))) goto crc_queuing_error; @@ -1414,6 +1593,22 @@ qla24xx_dif_start_scsi(srb_t *sp) goto queuing_error; else sp->flags |= SRB_DMA_VALID; + + if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || + (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { + struct qla2_sgx sgx; + uint32_t partial; + + memset(&sgx, 0, sizeof(struct qla2_sgx)); + sgx.tot_bytes = scsi_bufflen(cmd); + sgx.cur_sg = scsi_sglist(cmd); + sgx.sp = sp; + + nseg = 0; + while (qla24xx_get_one_block_sg( + cmd->device->sector_size, &sgx, &partial)) + nseg++; + } } else nseg = 0; @@ -1428,6 +1623,11 @@ qla24xx_dif_start_scsi(srb_t *sp) goto queuing_error; else sp->flags |= SRB_CRC_PROT_DMA_VALID; + + if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || + (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { + nseg = scsi_bufflen(cmd) / cmd->device->sector_size; + } } else { nseg = 0; } @@ -1454,6 +1654,7 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Build header part of command packet (excluding the OPCODE). */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; + sp->handle = handle; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b16b7725dee..53339f10a59 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1435,25 +1435,27 @@ struct scsi_dif_tuple { * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST * to indicate to the kernel that the HBA detected error. */ -static inline void +static inline int qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) { struct scsi_qla_host *vha = sp->fcport->vha; struct scsi_cmnd *cmd = sp->cmd; - struct scsi_dif_tuple *ep = - (struct scsi_dif_tuple *)&sts24->data[20]; - struct scsi_dif_tuple *ap = - (struct scsi_dif_tuple *)&sts24->data[12]; + uint8_t *ap = &sts24->data[12]; + uint8_t *ep = &sts24->data[20]; uint32_t e_ref_tag, a_ref_tag; uint16_t e_app_tag, a_app_tag; uint16_t e_guard, a_guard; - e_ref_tag = be32_to_cpu(ep->ref_tag); - a_ref_tag = be32_to_cpu(ap->ref_tag); - e_app_tag = be16_to_cpu(ep->app_tag); - a_app_tag = be16_to_cpu(ap->app_tag); - e_guard = be16_to_cpu(ep->guard); - a_guard = be16_to_cpu(ap->guard); + /* + * swab32 of the "data" field in the beginning of qla2x00_status_entry() + * would make guard field appear at offset 2 + */ + a_guard = le16_to_cpu(*(uint16_t *)(ap + 2)); + a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0)); + a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4)); + e_guard = le16_to_cpu(*(uint16_t *)(ep + 2)); + e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0)); + e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4)); ql_dbg(ql_dbg_io, vha, 0x3023, "iocb(s) %p Returned STATUS.\n", sts24); @@ -1465,6 +1467,63 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, a_app_tag, e_app_tag, a_guard, e_guard); + /* + * Ignore sector if: + * For type 3: ref & app tag is all 'f's + * For type 0,1,2: app tag is all 'f's + */ + if ((a_app_tag == 0xffff) && + ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) || + (a_ref_tag == 0xffffffff))) { + uint32_t blocks_done, resid; + sector_t lba_s = scsi_get_lba(cmd); + + /* 2TB boundary case covered automatically with this */ + blocks_done = e_ref_tag - (uint32_t)lba_s + 1; + + resid = scsi_bufflen(cmd) - (blocks_done * + cmd->device->sector_size); + + scsi_set_resid(cmd, resid); + cmd->result = DID_OK << 16; + + /* Update protection tag */ + if (scsi_prot_sg_count(cmd)) { + uint32_t i, j = 0, k = 0, num_ent; + struct scatterlist *sg; + struct sd_dif_tuple *spt; + + /* Patch the corresponding protection tags */ + scsi_for_each_prot_sg(cmd, sg, + scsi_prot_sg_count(cmd), i) { + num_ent = sg_dma_len(sg) / 8; + if (k + num_ent < blocks_done) { + k += num_ent; + continue; + } + j = blocks_done - k - 1; + k = blocks_done; + break; + } + + if (k != blocks_done) { + qla_printk(KERN_WARNING, sp->fcport->vha->hw, + "unexpected tag values tag:lba=%x:%lx)\n", + e_ref_tag, lba_s); + return 1; + } + + spt = page_address(sg_page(sg)) + sg->offset; + spt += j; + + spt->app_tag = 0xffff; + if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3) + spt->ref_tag = 0xffffffff; + } + + return 0; + } + /* check guard */ if (e_guard != a_guard) { scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, @@ -1472,7 +1531,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) set_driver_byte(cmd, DRIVER_SENSE); set_host_byte(cmd, DID_ABORT); cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return; + return 1; } /* check appl tag */ @@ -1482,7 +1541,7 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) set_driver_byte(cmd, DRIVER_SENSE); set_host_byte(cmd, DID_ABORT); cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return; + return 1; } /* check ref tag */ @@ -1492,8 +1551,9 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) set_driver_byte(cmd, DRIVER_SENSE); set_host_byte(cmd, DID_ABORT); cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return; + return 1; } + return 1; } /** @@ -1767,7 +1827,7 @@ check_scsi_status: break; case CS_DIF_ERROR: - qla2x00_handle_dif_error(sp, sts24); + logit = qla2x00_handle_dif_error(sp, sts24); break; default: cp->result = DID_ERROR << 16; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index e02df276804..d65a3005b43 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -106,17 +106,21 @@ MODULE_PARM_DESC(ql2xmaxqdepth, "Maximum queue depth to report for target devices."); /* Do not change the value of this after module load */ -int ql2xenabledif = 1; +int ql2xenabledif = 0; module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xenabledif, " Enable T10-CRC-DIF " - " Default is 0 - No DIF Support. 1 - Enable it"); + " Default is 0 - No DIF Support. 1 - Enable it" + ", 2 - Enable DIF for all types, except Type 0."); -int ql2xenablehba_err_chk; +int ql2xenablehba_err_chk = 2; module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xenablehba_err_chk, - " Enable T10-CRC-DIF Error isolation by HBA" - " Default is 0 - Error isolation disabled, 1 - Enable it"); + " Enable T10-CRC-DIF Error isolation by HBA:\n" + " Default is 1.\n" + " 0 -- Error isolation disabled\n" + " 1 -- Error isolation enabled only for DIX Type 0\n" + " 2 -- Error isolation enabled for all Types\n"); int ql2xiidmaenable=1; module_param(ql2xiidmaenable, int, S_IRUGO); @@ -2380,11 +2384,14 @@ skip_dpc: if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { + int prot = 0; base_vha->flags.difdix_supported = 1; ql_dbg(ql_dbg_init, base_vha, 0x00f1, "Registering for DIF/DIX type 1 and 3 protection.\n"); + if (ql2xenabledif == 1) + prot = SHOST_DIX_TYPE0_PROTECTION; scsi_host_set_prot(host, - SHOST_DIF_TYPE1_PROTECTION + prot | SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION -- cgit v1.2.3-70-g09d2 From e02587d777bfb398f70709fd3a92fa0154959003 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 16 Aug 2011 11:29:23 -0700 Subject: [SCSI] qla2xxx: T10 DIF - Fix incorrect error reporting. This fix: - Disables app tag peeking; correct tag check will be added when the SCSI API is available. - Always derive ref_tag from scsi_get_lba() - Removes incorrect swap of FCP_LUN in FCP_CMND - Moves app-tag error check before ref-tag check. The reason being, currently there is no interface in SCSI to retrieve the app-tag for protection I/Os, so driver puts zero for app-tag in the firmware interface, but requests not to validate it, but when a ref-tag error is detected by firmware, it would put expected/actual tags for all the protection tags (guard/app/ref). As driver checks for app tag error first, a ref-tag error is incorrectly flagged as app-tag error. - Convert HBA specific checks to capability based. Signed-off-by: Arun Easi Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_dbg.c | 36 ++++++++++++------------- drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_inline.h | 12 +++++++-- drivers/scsi/qla2xxx/qla_iocb.c | 55 +++++++++++++++------------------------ drivers/scsi/qla2xxx/qla_isr.c | 13 ++++----- drivers/scsi/qla2xxx/qla_mid.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 4 +-- 8 files changed, 62 insertions(+), 64 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 81006709980..a31e05f3bfd 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1786,7 +1786,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); } - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { int prot = 0; vha->flags.difdix_supported = 1; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 2155071f310..d79cd8a5f83 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -8,24 +8,24 @@ /* * Table for showing the current message id in use for particular level * Change this table for addition of log/debug messages. - * ----------------------------------------------------- - * | Level | Last Value Used | - * ----------------------------------------------------- - * | Module Init and Probe | 0x0116 | - * | Mailbox commands | 0x111e | - * | Device Discovery | 0x2083 | - * | Queue Command and IO tracing | 0x302e | - * | DPC Thread | 0x401c | - * | Async Events | 0x5059 | - * | Timer Routines | 0x600d | - * | User Space Interactions | 0x709c | - * | Task Management | 0x8043 | - * | AER/EEH | 0x900f | - * | Virtual Port | 0xa007 | - * | ISP82XX Specific | 0xb027 | - * | MultiQ | 0xc00b | - * | Misc | 0xd00b | - * ----------------------------------------------------- + * ---------------------------------------------------------------------- + * | Level | Last Value Used | Holes | + * ---------------------------------------------------------------------- + * | Module Init and Probe | 0x0116 | | + * | Mailbox commands | 0x1126 | | + * | Device Discovery | 0x2083 | | + * | Queue Command and IO tracing | 0x302e | 0x3008 | + * | DPC Thread | 0x401c | | + * | Async Events | 0x5059 | | + * | Timer Routines | 0x600d | | + * | User Space Interactions | 0x709d | | + * | Task Management | 0x8041 | | + * | AER/EEH | 0x900f | | + * | Virtual Port | 0xa007 | | + * | ISP82XX Specific | 0xb04f | | + * | MultiQ | 0xc00b | | + * | Misc | 0xd00b | | + * ---------------------------------------------------------------------- */ #include "qla_def.h" diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cc5a79259d3..a03eaf40f37 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2529,6 +2529,7 @@ struct qla_hw_data { #define DT_ISP8021 BIT_14 #define DT_ISP_LAST (DT_ISP8021 << 1) +#define DT_T10_PI BIT_25 #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 #define DT_ZIO_SUPPORTED BIT_28 @@ -2572,6 +2573,7 @@ struct qla_hw_data { #define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha)) #define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) +#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) #define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED) diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index c06e5f9b431..9902834e0b7 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -104,9 +104,17 @@ qla2x00_set_fcport_state(fc_port_t *fcport, int state) } static inline int -qla2x00_hba_err_chk_enabled(unsigned char op) +qla2x00_hba_err_chk_enabled(srb_t *sp) { - switch (op) { + /* + * Uncomment when corresponding SCSI changes are done. + * + if (!sp->cmd->prot_chk) + return 0; + * + */ + + switch (scsi_get_prot_op(sp->cmd)) { case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: if (ql2xenablehba_err_chk >= 1) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 09ad3ce6006..dbec89622a0 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -709,12 +709,11 @@ struct fw_dif_context { * */ static inline void -qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, +qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, unsigned int protcnt) { - struct sd_dif_tuple *spt; + struct scsi_cmnd *cmd = sp->cmd; scsi_qla_host_t *vha = shost_priv(cmd->device->host); - unsigned char op = scsi_get_prot_op(cmd); switch (scsi_get_prot_type(cmd)) { case SCSI_PROT_DIF_TYPE0: @@ -724,6 +723,10 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, */ pkt->ref_tag = cpu_to_le32((uint32_t) (0xffffffff & scsi_get_lba(cmd))); + + if (!qla2x00_hba_err_chk_enabled(sp)) + break; + pkt->ref_tag_mask[0] = 0xff; pkt->ref_tag_mask[1] = 0xff; pkt->ref_tag_mask[2] = 0xff; @@ -735,20 +738,16 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, * match LBA in CDB + N */ case SCSI_PROT_DIF_TYPE2: - if (!qla2x00_hba_err_chk_enabled(op)) - break; - - if (scsi_prot_sg_count(cmd)) { - spt = page_address(sg_page(scsi_prot_sglist(cmd))) + - scsi_prot_sglist(cmd)[0].offset; - pkt->app_tag = swab32(spt->app_tag); - pkt->app_tag_mask[0] = 0xff; - pkt->app_tag_mask[1] = 0xff; - } + pkt->app_tag = __constant_cpu_to_le16(0); + pkt->app_tag_mask[0] = 0x0; + pkt->app_tag_mask[1] = 0x0; pkt->ref_tag = cpu_to_le32((uint32_t) (0xffffffff & scsi_get_lba(cmd))); + if (!qla2x00_hba_err_chk_enabled(sp)) + break; + /* enable ALL bytes of the ref tag */ pkt->ref_tag_mask[0] = 0xff; pkt->ref_tag_mask[1] = 0xff; @@ -768,26 +767,15 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, * 16 bit app tag. */ case SCSI_PROT_DIF_TYPE1: - if (!qla2x00_hba_err_chk_enabled(op)) + pkt->ref_tag = cpu_to_le32((uint32_t) + (0xffffffff & scsi_get_lba(cmd))); + pkt->app_tag = __constant_cpu_to_le16(0); + pkt->app_tag_mask[0] = 0x0; + pkt->app_tag_mask[1] = 0x0; + + if (!qla2x00_hba_err_chk_enabled(sp)) break; - if (protcnt && (op == SCSI_PROT_WRITE_STRIP || - op == SCSI_PROT_WRITE_PASS)) { - spt = page_address(sg_page(scsi_prot_sglist(cmd))) + - scsi_prot_sglist(cmd)[0].offset; - ql_dbg(ql_dbg_io, vha, 0x3008, - "LBA from user %p, lba = 0x%x for cmd=%p.\n", - spt, (int)spt->ref_tag, cmd); - pkt->ref_tag = swab32(spt->ref_tag); - pkt->app_tag_mask[0] = 0x0; - pkt->app_tag_mask[1] = 0x0; - } else { - pkt->ref_tag = cpu_to_le32((uint32_t) - (0xffffffff & scsi_get_lba(cmd))); - pkt->app_tag = __constant_cpu_to_le16(0); - pkt->app_tag_mask[0] = 0x0; - pkt->app_tag_mask[1] = 0x0; - } /* enable ALL bytes of the ref tag */ pkt->ref_tag_mask[0] = 0xff; pkt->ref_tag_mask[1] = 0xff; @@ -1208,7 +1196,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); - qla24xx_set_t10dif_tags(cmd, (struct fw_dif_context *) + qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *) &crc_ctx_pkt->ref_tag, tot_prot_dsds); cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); @@ -1237,7 +1225,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, fcp_cmnd->additional_cdb_len |= 2; int_to_scsilun(sp->cmd->device->lun, &fcp_cmnd->lun); - host_to_fcp_swap((uint8_t *)&fcp_cmnd->lun, sizeof(fcp_cmnd->lun)); memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( @@ -1289,7 +1276,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, BUG(); } - if (!qla2x00_hba_err_chk_enabled(scsi_get_prot_op(cmd))) + if (!qla2x00_hba_err_chk_enabled(sp)) fw_prot_opts |= 0x10; /* Disable Guard tag checking */ if (!bundling) { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 53339f10a59..ec53e87781a 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1534,25 +1534,26 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) return 1; } - /* check appl tag */ - if (e_app_tag != a_app_tag) { + /* check ref tag */ + if (e_ref_tag != a_ref_tag) { scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x2); + 0x10, 0x3); set_driver_byte(cmd, DRIVER_SENSE); set_host_byte(cmd, DID_ABORT); cmd->result |= SAM_STAT_CHECK_CONDITION << 1; return 1; } - /* check ref tag */ - if (e_ref_tag != a_ref_tag) { + /* check appl tag */ + if (e_app_tag != a_app_tag) { scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x3); + 0x10, 0x2); set_driver_byte(cmd, DRIVER_SENSE); set_host_byte(cmd, DID_ABORT); cmd->result |= SAM_STAT_CHECK_CONDITION << 1; return 1; } + return 1; } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index c706ed37000..f488cc69fc7 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -472,7 +472,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) host->can_queue = base_vha->req->length + 128; host->this_id = 255; host->cmd_per_lun = 3; - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) host->max_cmd_len = 32; else host->max_cmd_len = MAX_CMDSZ; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d65a3005b43..f57c292845a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2255,7 +2255,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->this_id = 255; host->cmd_per_lun = 3; host->unique_id = host->host_no; - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) host->max_cmd_len = 32; else host->max_cmd_len = MAX_CMDSZ; @@ -2382,7 +2382,7 @@ skip_dpc: "Detected hba at address=%p.\n", ha); - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { int prot = 0; base_vha->flags.difdix_supported = 1; -- cgit v1.2.3-70-g09d2 From 42cd4f5dc2a3de31bfd24642ab4e8b21834a6b78 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 16 Aug 2011 11:29:24 -0700 Subject: [SCSI] qla2xxx: Fix qla24xx revision check while enabling interrupts. Since we enable interrupts before initializing the firmware, use the chip revision from PCI config space directly to perform the chip revision check. Also remove the unnecessary firmware attributes test. Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ec53e87781a..477767fcfd1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2529,11 +2529,10 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) goto skip_msi; } - if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX || - !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) { + if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) { ql_log(ql_log_warn, vha, 0x0035, "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n", - ha->pdev->revision, ha->fw_attributes); + ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX); goto skip_msix; } -- cgit v1.2.3-70-g09d2 From 7594206493880007fd68a18d6e9f380a1afe20d4 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 16 Aug 2011 11:29:25 -0700 Subject: [SCSI] qla2xxx: Acquire hardware lock while manipulating dsd list. The dsd list shouldn't be manipulated without taking the per host hardware lock to prevent multiple callers from trampling upon one another. Signed-off-by: Saurav Kashyap Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f57c292845a..2caab83c4c9 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -913,7 +913,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) "Abort command mbx success.\n"); wait = 1; } + + spin_lock_irqsave(&ha->hardware_lock, flags); qla2x00_sp_compl(ha, sp); + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for the command to be returned. */ if (wait) { -- cgit v1.2.3-70-g09d2 From bc91ade9b7bc274d625c9b24c04d365a2daf481e Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 16 Aug 2011 11:29:26 -0700 Subject: [SCSI] qla2xxx: Double check for command completion if abort mailbox command fails. Close a small window where we could falsely fail an abort request if the mailbox command fails but the command was returned during interrupt context. Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 2caab83c4c9..4cace3f20c0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -918,6 +918,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) qla2x00_sp_compl(ha, sp); spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Did the command return during mailbox execution? */ + if (ret == FAILED && !CMD_SP(cmd)) + ret = SUCCESS; + /* Wait for the command to be returned. */ if (wait) { if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { -- cgit v1.2.3-70-g09d2 From 3553d343e7acc418988cb8f22cd5b4976e7b484a Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 16 Aug 2011 11:29:27 -0700 Subject: [SCSI] qla2xxx: Save and restore irq in the response queue interrupt handler. Signed-off-by: Saurav Kashyap Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 5cbf33a50b1..02704fe8afa 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2208,6 +2208,7 @@ qla82xx_msix_rsp_q(int irq, void *dev_id) struct qla_hw_data *ha; struct rsp_que *rsp; struct device_reg_82xx __iomem *reg; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -2218,11 +2219,11 @@ qla82xx_msix_rsp_q(int irq, void *dev_id) ha = rsp->hw; reg = &ha->iobase->isp82; - spin_lock_irq(&ha->hardware_lock); + spin_lock_irqsave(&ha->hardware_lock, flags); vha = pci_get_drvdata(ha->pdev); qla24xx_process_response_queue(vha, rsp); WRT_REG_DWORD(®->host_int, 0); - spin_unlock_irq(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return IRQ_HANDLED; } -- cgit v1.2.3-70-g09d2 From 58b48576966ed0afd3f63ef17480ec12748a7119 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Tue, 16 Aug 2011 11:29:28 -0700 Subject: [SCSI] qla2xxx: Correct inadvertent loop state transitions during port-update handling. Transitioning to a LOOP_UPDATE loop-state could cause the driver to miss normal link/target processing. LOOP_UPDATE is a crufty artifact leftover from at time the driver performed it's own internal command-queuing. Safely remove this state. Signed-off-by: Andrew Vasquez Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 3 --- drivers/scsi/qla2xxx/qla_isr.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index def694271bf..37da04d3db2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3838,15 +3838,12 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) req = vha->req; rsp = req->rsp; - atomic_set(&vha->loop_state, LOOP_UPDATE); clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); if (vha->flags.online) { if (!(rval = qla2x00_fw_ready(vha))) { /* Wait at most MAX_TARGET RSCNs for a stable link. */ wait_time = 256; do { - atomic_set(&vha->loop_state, LOOP_UPDATE); - /* Issue a marker after FW becomes ready. */ qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 477767fcfd1..646fc5263d5 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -719,7 +719,6 @@ skip_rio: vha->flags.rscn_queue_overflow = 1; } - atomic_set(&vha->loop_state, LOOP_UPDATE); atomic_set(&vha->loop_down_timer, 0); vha->flags.management_server_logged_in = 0; -- cgit v1.2.3-70-g09d2 From 51cc9a8e5f610a0d0881b45410c37890e02a2f76 Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 16 Aug 2011 11:29:29 -0700 Subject: [SCSI] qla2xxx: Set the task attributes after memsetting fcp cmnd. The memset of the fcp_cmnd struct needs to be moved so that it will not zero-out valid data. Signed-off-by: Saurav Kashyap Signed-off-by: Chad Dupuis Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 02704fe8afa..049807cda41 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2839,6 +2839,16 @@ sufficient_dsds: int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun); host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + /* build FCP_CMND IU */ + memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); + int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); + ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 1; + else if (cmd->sc_data_direction == DMA_FROM_DEVICE) + ctx->fcp_cmnd->additional_cdb_len |= 2; + /* * Update tagged queuing modifier -- default is TSK_SIMPLE (0). */ @@ -2855,16 +2865,6 @@ sufficient_dsds: } } - /* build FCP_CMND IU */ - memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(sp->cmd->device->lun, &ctx->fcp_cmnd->lun); - ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 1; - else if (cmd->sc_data_direction == DMA_FROM_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 2; - memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 + -- cgit v1.2.3-70-g09d2 From 7ca3c803e85080afdff4097e60fefec865027809 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 16 Aug 2011 11:29:30 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.03.07.07-k. Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 062c97bf62f..13b6357c1fa 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.03-k" +#define QLA2XXX_VERSION "8.03.07.07-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -- cgit v1.2.3-70-g09d2 From 848e7d5b46b9b0ee613a106bc460acf6a09a8546 Mon Sep 17 00:00:00 2001 From: Robert Love Date: Thu, 25 Aug 2011 12:40:47 -0700 Subject: [SCSI] fcoe: Fix deadlock between fip's recv_work and rtnl The rtnl cannot be held durrng the fcoe_interface_put. If it is the last reference on the fcoe_interface the fcoe_ctlr_destroy will be called as a part of the cleanup, ultimately calling cancel_work_sync(&fip->recv_work); If we are processing a flogi response we will be in the recv_work context and we will lock the rtnl to add a new unicast MAC address. This is how the deadlock can occur. The fix is simply to move the rtnl_lock/unlock into fcoe_interface_cleanup so that it can be unlocked before fcoe_interface_put is called. Here is the lockdep report: Jul 21 11:26:35 bubba [ 223.870702] ul 21 11:26:35 bubba [ 223.870704] ======================================================= Jul 21 11:26:35 bubba [ 223.871255] [ INFO: possible circular locking dependency detected ] Jul 21 11:26:35 bubba [ 223.871530] 3.0.0-rc7+ #1 Jul 21 11:26:35 bubba [ 223.871797] ------------------------------------------------------- Jul 21 11:26:35 bubba [ 223.872072] lockdeptest.sh/3464 is trying to acquire lock: Jul 21 11:26:35 bubba [ 223.872345] ((&fip->recv_work) Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] wait_on_work+0x0/0xbd Jul 21 11:26:35 bubba [ 223.873022] Jul 21 11:26:35 bubba [ 223.873023] but task is already holding lock: Jul 21 11:26:35 bubba [ 223.873555] (rtnl_mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] rtnl_lock+0x12/0x14 Jul 21 11:26:35 bubba [ 223.874229] Jul 21 11:26:35 bubba [ 223.874230] which lock already depends on the new lock. Jul 21 11:26:35 bubba [ 223.874231] Jul 21 11:26:35 bubba [ 223.875032] Jul 21 11:26:35 bubba [ 223.875033] the existing dependency chain (in reverse order) is: Jul 21 11:26:35 bubba [ 223.875573] Jul 21 11:26:35 bubba [ 223.875573] -> #1 Jul 21 11:26:35 bubba (rtnl_mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba : Jul 21 11:26:35 bubba [ 223.876301] Jul 21 11:26:35 bubba [] lock_acquire+0xd2/0xf7 Jul 21 11:26:35 bubba [ 223.876645] Jul 21 11:26:35 bubba [] __mutex_lock_common+0x47/0x30d Jul 21 11:26:35 bubba [ 223.876991] Jul 21 11:26:35 bubba [] mutex_lock_nested+0x3b/0x40 Jul 21 11:26:35 bubba [ 223.877334] Jul 21 11:26:35 bubba [] rtnl_lock+0x12/0x14 Jul 21 11:26:35 bubba [ 223.877675] Jul 21 11:26:35 bubba [] fcoe_update_src_mac+0x2b/0x80 [fcoe] Jul 21 11:26:35 bubba [ 223.878022] Jul 21 11:26:35 bubba [] fcoe_flogi_resp+0x5e/0x79 [fcoe] Jul 21 11:26:35 bubba [ 223.878366] Jul 21 11:26:35 bubba [] fc_exch_recv+0x7f5/0x9da [libfc] Jul 21 11:26:35 bubba [ 223.878713] Jul 21 11:26:35 bubba [] fcoe_ctlr_recv_work+0x71f/0x10dc [libfcoe] Jul 21 11:26:35 bubba [ 223.879258] Jul 21 11:26:35 bubba [] process_one_work+0x1d7/0x347 Jul 21 11:26:35 bubba [ 223.879601] Jul 21 11:26:35 bubba [] worker_thread+0xf8/0x17c Jul 21 11:26:35 bubba [ 223.879944] Jul 21 11:26:35 bubba [] kthread+0x7d/0x85 Jul 21 11:26:35 bubba [ 223.880287] Jul 21 11:26:35 bubba [] kernel_thread_helper+0x4/0x10 Jul 21 11:26:35 bubba [ 223.880634] Jul 21 11:26:35 bubba [ 223.880635] -> #0 Jul 21 11:26:35 bubba ((&fip->recv_work) Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba : Jul 21 11:26:35 bubba [ 223.881357] Jul 21 11:26:35 bubba [] __lock_acquire+0xb1d/0xe2c Jul 21 11:26:35 bubba [ 223.881695] Jul 21 11:26:35 bubba [] lock_acquire+0xd2/0xf7 Jul 21 11:26:35 bubba [ 223.882033] Jul 21 11:26:35 bubba [] wait_on_work+0x50/0xbd Jul 21 11:26:35 bubba [ 223.882378] Jul 21 11:26:35 bubba [] __cancel_work_timer+0xb6/0xf4 Jul 21 11:26:35 bubba [ 223.882718] Jul 21 11:26:35 bubba [] cancel_work_sync+0xb/0xd Jul 21 11:26:35 bubba [ 223.883057] Jul 21 11:26:35 bubba [] fcoe_ctlr_destroy+0x1d/0x67 [libfcoe] Jul 21 11:26:35 bubba [ 223.883399] Jul 21 11:26:35 bubba [] fcoe_interface_release+0x21/0x45 [fcoe] Jul 21 11:26:35 bubba [ 223.883940] Jul 21 11:26:35 bubba [] kref_put+0x43/0x4d Jul 21 11:26:35 bubba [ 223.884280] Jul 21 11:26:35 bubba [] fcoe_interface_put+0x17/0x19 [fcoe] Jul 21 11:26:35 bubba [ 223.884624] Jul 21 11:26:35 bubba [] fcoe_interface_cleanup+0x188/0x193 [fcoe] Jul 21 11:26:35 bubba [ 223.885163] Jul 21 11:26:35 bubba [] fcoe_destroy+0x52/0x72 [fcoe] Jul 21 11:26:35 bubba [ 223.885502] Jul 21 11:26:35 bubba [] fcoe_transport_destroy+0xab/0x110 [libfcoe] Jul 21 11:26:35 bubba [ 223.886045] Jul 21 11:26:35 bubba [] param_attr_store+0x43/0x62 Jul 21 11:26:35 bubba [ 223.886385] Jul 21 11:26:35 bubba [] module_attr_store+0x21/0x25 Jul 21 11:26:35 bubba [ 223.886728] Jul 21 11:26:35 bubba [] sysfs_write_file+0x103/0x13f Jul 21 11:26:35 bubba [ 223.887068] Jul 21 11:26:35 bubba [] vfs_write+0xa7/0xfa Jul 21 11:26:35 bubba [ 223.887406] Jul 21 11:26:35 bubba [] sys_write+0x45/0x69 Jul 21 11:26:35 bubba [ 223.887742] Jul 21 11:26:35 bubba [] system_call_fastpath+0x16/0x1b Jul 21 11:26:35 bubba [ 223.888083] Jul 21 11:26:35 bubba [ 223.888084] other info that might help us debug this: Jul 21 11:26:35 bubba [ 223.888085] Jul 21 11:26:35 bubba [ 223.888879] Possible unsafe locking scenario: Jul 21 11:26:35 bubba [ 223.888881] Jul 21 11:26:35 bubba [ 223.889411] CPU0 CPU1 Jul 21 11:26:35 bubba [ 223.889683] ---- ---- Jul 21 11:26:35 bubba [ 223.889955] lock( Jul 21 11:26:35 bubba rtnl_mutex Jul 21 11:26:35 bubba ); Jul 21 11:26:35 bubba [ 223.890349] lock( Jul 21 11:26:35 bubba (&fip->recv_work) Jul 21 11:26:35 bubba ); Jul 21 11:26:35 bubba [ 223.890751] lock( Jul 21 11:26:35 bubba rtnl_mutex Jul 21 11:26:35 bubba ); Jul 21 11:26:35 bubba [ 223.891154] lock( Jul 21 11:26:35 bubba (&fip->recv_work) Jul 21 11:26:35 bubba ); Jul 21 11:26:35 bubba [ 223.891549] Jul 21 11:26:35 bubba [ 223.891550] *** DEADLOCK *** Jul 21 11:26:35 bubba [ 223.891551] Jul 21 11:26:35 bubba [ 223.892347] 6 locks held by lockdeptest.sh/3464: Jul 21 11:26:35 bubba [ 223.892621] #0: Jul 21 11:26:35 bubba (&buffer->mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] sysfs_write_file+0x37/0x13f Jul 21 11:26:35 bubba [ 223.893359] #1: Jul 21 11:26:35 bubba (s_active Jul 21 11:26:35 bubba ){++++.+} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] sysfs_write_file+0xe2/0x13f Jul 21 11:26:35 bubba [ 223.894094] #2: Jul 21 11:26:35 bubba (param_lock Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] param_attr_store+0x36/0x62 Jul 21 11:26:35 bubba [ 223.894835] #3: Jul 21 11:26:35 bubba (ft_mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] fcoe_transport_destroy+0x1e/0x110 [libfcoe] Jul 21 11:26:35 bubba [ 223.895574] #4: Jul 21 11:26:35 bubba (fcoe_config_mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] fcoe_destroy+0x18/0x72 [fcoe] Jul 21 11:26:35 bubba [ 223.896314] #5: Jul 21 11:26:35 bubba (rtnl_mutex Jul 21 11:26:35 bubba ){+.+.+.} Jul 21 11:26:35 bubba , at: Jul 21 11:26:35 bubba [] rtnl_lock+0x12/0x14 Jul 21 11:26:35 bubba [ 223.897047] Jul 21 11:26:35 bubba [ 223.897048] stack backtrace: Jul 21 11:26:35 bubba [ 223.897578] Pid: 3464, comm: lockdeptest.sh Not tainted 3.0.0-rc7+ #1 Jul 21 11:26:35 bubba [ 223.897853] Call Trace: Jul 21 11:26:35 bubba [ 223.898128] [] print_circular_bug+0x1f8/0x209 Jul 21 11:26:35 bubba [ 223.898416] [] __lock_acquire+0xb1d/0xe2c Jul 21 11:26:35 bubba [ 223.898699] [] ? wait_on_cpu_work+0xe6/0xe6 Jul 21 11:26:35 bubba [ 223.898982] [] lock_acquire+0xd2/0xf7 Jul 21 11:26:35 bubba [ 223.899263] [] ? wait_on_cpu_work+0xe6/0xe6 Jul 21 11:26:35 bubba [ 223.899547] [] ? mod_timer+0x8f/0x98 Jul 21 11:26:35 bubba [ 223.899827] [] wait_on_work+0x50/0xbd Jul 21 11:26:35 bubba [ 223.900108] [] ? wait_on_cpu_work+0xe6/0xe6 Jul 21 11:26:35 bubba [ 223.900390] [] __cancel_work_timer+0xb6/0xf4 Jul 21 11:26:35 bubba [ 223.900671] [] cancel_work_sync+0xb/0xd Jul 21 11:26:35 bubba [ 223.900953] [] fcoe_ctlr_destroy+0x1d/0x67 [libfcoe] Jul 21 11:26:35 bubba [ 223.901237] [] fcoe_interface_release+0x21/0x45 [fcoe] Jul 21 11:26:35 bubba [ 223.901522] [] ? fcoe_enable+0x6b/0x6b [fcoe] Jul 21 11:26:35 bubba [ 223.901803] [] kref_put+0x43/0x4d Jul 21 11:26:35 bubba [ 223.902083] [] fcoe_interface_put+0x17/0x19 [fcoe] Jul 21 11:26:35 bubba [ 223.902367] [] fcoe_interface_cleanup+0x188/0x193 [fcoe] Jul 21 11:26:35 bubba [ 223.902653] [] ? mutex_lock_nested+0x3b/0x40 Jul 21 11:26:35 bubba [ 223.902939] [] fcoe_destroy+0x52/0x72 [fcoe] Jul 21 11:26:35 bubba [ 223.903223] [] fcoe_transport_destroy+0xab/0x110 [libfcoe] Jul 21 11:26:35 bubba [ 223.903508] [] param_attr_store+0x43/0x62 Jul 21 11:26:35 bubba [ 223.903792] [] module_attr_store+0x21/0x25 Jul 21 11:26:35 bubba [ 223.904075] [] sysfs_write_file+0x103/0x13f Jul 21 11:26:35 bubba [ 223.904357] [] vfs_write+0xa7/0xfa Jul 21 11:26:35 bubba [ 223.904642] [] ? fget_light+0x35/0x96 Jul 21 11:26:35 bubba [ 223.904923] [] sys_write+0x45/0x69 Jul 21 11:26:35 bubba [ 223.905204] [] system_call_fastpath+0x16/0x1b Jul 21 11:26:36 bubba [ 223.964438] ixgbe 0000:05:00.0: eth3: detected SFP+: 5 Jul 21 11:26:37 bubba [ 225.196702] ixgbe 0000:05:00.0: eth3: NIC Link is Up 10 Gbps, Flow Control: None Signed-off-by: Robert Love Tested-by: Ross Brattain Reviewed-by: Yi Zou Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ba710e350ac..5d0e9a24ae9 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -432,6 +432,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; + rtnl_lock(); + /* * Don't listen for Ethernet packets anymore. * synchronize_net() ensures that the packet handlers are not running @@ -461,6 +463,8 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) " specific feature for LLD.\n"); } + rtnl_unlock(); + /* Release the self-reference taken during fcoe_interface_create() */ fcoe_interface_put(fcoe); } @@ -1951,11 +1955,8 @@ static void fcoe_destroy_work(struct work_struct *work) fcoe_if_destroy(port->lport); /* Do not tear down the fcoe interface for NPIV port */ - if (!npiv) { - rtnl_lock(); + if (!npiv) fcoe_interface_cleanup(fcoe); - rtnl_unlock(); - } mutex_unlock(&fcoe_config_mutex); } @@ -2009,8 +2010,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", netdev->name); rc = -EIO; + rtnl_unlock(); fcoe_interface_cleanup(fcoe); - goto out_nodev; + goto out_nortnl; } /* Make this the "master" N_Port */ @@ -2027,6 +2029,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) out_nodev: rtnl_unlock(); +out_nortnl: mutex_unlock(&fcoe_config_mutex); return rc; } -- cgit v1.2.3-70-g09d2 From 77a2b73a7805a3c6a473b6741aa514ef40295d26 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Thu, 25 Aug 2011 12:40:52 -0700 Subject: [SCSI] libfc: fix fc_eh_host_reset Current fc_eh_host_reset leaves lport offline permanently due to FLOGI response getting handled by LOGO response from last reset as both had same exchange id. So fix this by having end to end exches clean-up using exchange abort along exches reset done from fc_eh_host_reset. This would avoid exchanges collision between the sessions across the reset. In this case implicit login should have done that but no aborting support for FIP frames, so just wait till lport->r_a_tov before restarting next flogi to ensure all exchanges are good to use again for next session. Below is the trace of LOGO from older session coming ahead of FLOGI response with same exche id 0x203:- 617 86.435165 4e.00.0b -> ff.ff.fc FC ELS LOGO 0x203 618 86.435195 4e.00.0b -> b6.02.00 FC ELS LOGO 0x213 619 86.435220 4e.00.0b -> 18.03.00 FC ELS LOGO 0x223 620 86.435244 4e.00.0b -> 18.02.00 FC ELS LOGO 0x233 621 86.435267 4e.00.0b -> 18.01.00 FC ELS LOGO 0x243 622 86.435349 00.00.00 -> ff.ff.fe FC ELS FLOGI 0x203 623 86.435549 ff.ff.fc -> 4e.00.0b FC ELS ACC (LOGO) 0x203 624 86.438721 ff.ff.fe -> 4e.00.0b FC ELS ACC (FLOGI) 0x203 625 86.442059 18.03.00 -> 4e.00.0b FC ELS ACC (LOGO) 0x223 626 86.443683 b6.02.00 -> 4e.00.0b FC ELS ACC (LOGO) 0x213 627 86.447693 18.01.00 -> 4e.00.0b FC ELS ACC (LOGO) 0x243 628 86.453499 18.02.00 -> 4e.00.0b FC ELS ACC (LOGO) 0x233 Signed-off-by: Vasu Dev Tested-by: Ross Brattain Reviewed-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 51 +++++++++++++++++++++++++++++-------------- drivers/scsi/libfc/fc_lport.c | 11 +++++++++- 2 files changed, 45 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 01ff082dc34..744fefe8134 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -494,6 +494,9 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, */ error = lport->tt.frame_send(lport, fp); + if (fh->fh_type == FC_TYPE_BLS) + return error; + /* * Update the exchange and sequence flags, * assuming all frames for the sequence have been sent. @@ -575,42 +578,35 @@ static void fc_seq_set_resp(struct fc_seq *sp, } /** - * fc_seq_exch_abort() - Abort an exchange and sequence - * @req_sp: The sequence to be aborted + * fc_exch_abort_locked() - Abort an exchange + * @ep: The exchange to be aborted * @timer_msec: The period of time to wait before aborting * - * Generally called because of a timeout or an abort from the upper layer. + * Locking notes: Called with exch lock held + * + * Return value: 0 on success else error code */ -static int fc_seq_exch_abort(const struct fc_seq *req_sp, - unsigned int timer_msec) +static int fc_exch_abort_locked(struct fc_exch *ep, + unsigned int timer_msec) { struct fc_seq *sp; - struct fc_exch *ep; struct fc_frame *fp; int error; - ep = fc_seq_exch(req_sp); - - spin_lock_bh(&ep->ex_lock); if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL) || - ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) { - spin_unlock_bh(&ep->ex_lock); + ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) return -ENXIO; - } /* * Send the abort on a new sequence if possible. */ sp = fc_seq_start_next_locked(&ep->seq); - if (!sp) { - spin_unlock_bh(&ep->ex_lock); + if (!sp) return -ENOMEM; - } ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL; if (timer_msec) fc_exch_timer_set_locked(ep, timer_msec); - spin_unlock_bh(&ep->ex_lock); /* * If not logged into the fabric, don't send ABTS but leave @@ -632,6 +628,28 @@ static int fc_seq_exch_abort(const struct fc_seq *req_sp, return error; } +/** + * fc_seq_exch_abort() - Abort an exchange and sequence + * @req_sp: The sequence to be aborted + * @timer_msec: The period of time to wait before aborting + * + * Generally called because of a timeout or an abort from the upper layer. + * + * Return value: 0 on success else error code + */ +static int fc_seq_exch_abort(const struct fc_seq *req_sp, + unsigned int timer_msec) +{ + struct fc_exch *ep; + int error; + + ep = fc_seq_exch(req_sp); + spin_lock_bh(&ep->ex_lock); + error = fc_exch_abort_locked(ep, timer_msec); + spin_unlock_bh(&ep->ex_lock); + return error; +} + /** * fc_exch_timeout() - Handle exchange timer expiration * @work: The work_struct identifying the exchange that timed out @@ -1715,6 +1733,7 @@ static void fc_exch_reset(struct fc_exch *ep) int rc = 1; spin_lock_bh(&ep->ex_lock); + fc_exch_abort_locked(ep, 0); ep->state |= FC_EX_RST_CLEANUP; if (cancel_delayed_work(&ep->timeout_work)) atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e55ed9cf23f..628f347404f 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -88,6 +88,7 @@ */ #include +#include #include #include @@ -1029,8 +1030,16 @@ static void fc_lport_enter_reset(struct fc_lport *lport) FCH_EVT_LIPRESET, 0); fc_vports_linkchange(lport); fc_lport_reset_locked(lport); - if (lport->link_up) + if (lport->link_up) { + /* + * Wait upto resource allocation time out before + * doing re-login since incomplete FIP exchanged + * from last session may collide with exchanges + * in new session. + */ + msleep(lport->r_a_tov); fc_lport_enter_flogi(lport); + } } /** -- cgit v1.2.3-70-g09d2 From 21cc0bd3a9e524b44a4f0ff05ac612aa0ff1a26e Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Thu, 25 Aug 2011 12:40:57 -0700 Subject: [SCSI] libfc: block SCSI eh thread for blocked rports Call fc_block_scsi_eh() in all fcoe eh to blocks the scsi_eh thread for blocked rports. Signed-off-by: Vasu Dev Tested-by: Ross Brattain Reviewed-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index afb63c84314..4c41ee816f0 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -2019,6 +2019,11 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd) struct fc_fcp_internal *si; int rc = FAILED; unsigned long flags; + int rval; + + rval = fc_block_scsi_eh(sc_cmd); + if (rval) + return rval; lport = shost_priv(sc_cmd->device->host); if (lport->state != LPORT_ST_READY) @@ -2068,9 +2073,9 @@ int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) int rc = FAILED; int rval; - rval = fc_remote_port_chkready(rport); + rval = fc_block_scsi_eh(sc_cmd); if (rval) - goto out; + return rval; lport = shost_priv(sc_cmd->device->host); @@ -2116,6 +2121,8 @@ int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) FC_SCSI_DBG(lport, "Resetting host\n"); + fc_block_scsi_eh(sc_cmd); + lport->tt.lport_reset(lport); wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT; while (!fc_fcp_lport_queue_ready(lport) && time_before(jiffies, -- cgit v1.2.3-70-g09d2 From 3ee17f59c5378af8d245f82498e3919b7de2ab40 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Thu, 25 Aug 2011 12:41:03 -0700 Subject: [SCSI] libfc: fix referencing to fc_fcp_pkt from the frame pointer via fr_fsp() In commit 6a716a8, while releasing the DDP context in case frame_send() failed, the frame may already be freed, so we should store the pointer to fc_fcp_pkt and release the DDP context using the locally stored fsp instead of getting fsp from the fr_fsp(fp) on a frame. Signed-off-by: Yi Zou Reported-by: Bhanu Prakash Gollapudi Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 744fefe8134..d261e982a2f 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1981,6 +1981,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport, struct fc_exch *ep; struct fc_seq *sp = NULL; struct fc_frame_header *fh; + struct fc_fcp_pkt *fsp = NULL; int rc = 1; ep = fc_exch_alloc(lport, fp); @@ -2003,8 +2004,10 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport, fc_exch_setup_hdr(ep, fp, ep->f_ctl); sp->cnt++; - if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) + if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) { + fsp = fr_fsp(fp); fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); + } if (unlikely(lport->tt.frame_send(lport, fp))) goto err; @@ -2018,7 +2021,8 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport, spin_unlock_bh(&ep->ex_lock); return sp; err: - fc_fcp_ddp_done(fr_fsp(fp)); + if (fsp) + fc_fcp_ddp_done(fsp); rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); if (!rc) -- cgit v1.2.3-70-g09d2 From 610602f369b4c810c9df05e431abd38f38cb8e0d Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Fri, 26 Aug 2011 11:16:47 -0700 Subject: [SCSI] bnx2i: Fixed the endian on TTT for NOP out transmission The iscsi_nopout task's TTT is defined as __be32 while the DMA memory to the chip is CPU specific. This creates a problem for unsolicited NOP-In responses where the TTT is not the RESERVED tag of 0xFFs. This patch adds a call to be32_to_cpu for the TTT specified. Signed-off-by: Eddie Wai Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_hwi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 9ae80cd5953..dba72a4e6a1 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -563,7 +563,7 @@ int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, nopout_wqe->itt = ((u16)task->itt | (ISCSI_TASK_TYPE_MPATH << ISCSI_TMF_REQUEST_TYPE_SHIFT)); - nopout_wqe->ttt = nopout_hdr->ttt; + nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt); nopout_wqe->flags = 0; if (!unsol) nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; -- cgit v1.2.3-70-g09d2 From 1c1bdd324cd50ac55f7ebf95ef249d946c6e4361 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Fri, 26 Aug 2011 12:42:11 +0530 Subject: ath9k_hw: Fix init mode register regression The commit 172805ad46b78717a738ca5c7908c68f0326d3a9 overwirtes additional clock settings of AR9330 to all AR9300 chips. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1baca8e4715..fcafec0605f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -671,7 +671,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); - if (AR_SREV_9300(ah)) + if (AR_SREV_9330(ah)) REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) -- cgit v1.2.3-70-g09d2 From 7c2510120e9b43b0caf32c3786a6ab831f7d9e87 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 26 Aug 2011 17:24:59 +0200 Subject: iwlegacy: fix BUG_ON(info->control.rates[0].idx < 0) When trying to connect to 5GHz we can provide negative index to mac80211 what trigger BUG_ON. Reason of iwl-3945-rs malfunction on 5GHz is unknown and needs further investigation. For now, to do not trigger a bug, correct value and just print WARNING. Address bug: https://bugzilla.redhat.com/show_bug.cgi?id=730653 Reported-and-tested-by: Jan Teichmann Cc: stable@kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-3945-rs.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c index 977bd2477c6..164bcae821f 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c @@ -822,12 +822,15 @@ static void iwl3945_rs_get_rate(void *priv_r, struct ieee80211_sta *sta, out: - rs_sta->last_txrate_idx = index; - if (sband->band == IEEE80211_BAND_5GHZ) - info->control.rates[0].idx = rs_sta->last_txrate_idx - - IWL_FIRST_OFDM_RATE; - else + if (sband->band == IEEE80211_BAND_5GHZ) { + if (WARN_ON_ONCE(index < IWL_FIRST_OFDM_RATE)) + index = IWL_FIRST_OFDM_RATE; + rs_sta->last_txrate_idx = index; + info->control.rates[0].idx = index - IWL_FIRST_OFDM_RATE; + } else { + rs_sta->last_txrate_idx = index; info->control.rates[0].idx = rs_sta->last_txrate_idx; + } IWL_DEBUG_RATE(priv, "leave: %d\n", index); } -- cgit v1.2.3-70-g09d2 From b33c25d6a62ac253caabda2b5f43258abff451c0 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Mon, 29 Aug 2011 23:01:58 -0400 Subject: acpica: ACPI_MAX_SLEEP should be 2 sec, not 20 This limit is a workaround for AML that sleeps too long, but the workaround didn't work b/c of a typo. https://bugzilla.kernel.org/show_bug.cgi?id=13195 Signed-off-by: Len Brown cc: stable@kernel.org # 2.6.35..3.0 --- drivers/acpi/acpica/acconfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index bc533dde16c..f895a244ca7 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -121,7 +121,7 @@ /* Maximum sleep allowed via Sleep() operator */ -#define ACPI_MAX_SLEEP 20000 /* Two seconds */ +#define ACPI_MAX_SLEEP 2000 /* Two seconds */ /****************************************************************************** * -- cgit v1.2.3-70-g09d2 From 0e4660cbe51276e86dbdab17228733dbcdb49249 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 29 Aug 2011 10:06:14 +0200 Subject: ath9k_hw: fix calibration on 5 ghz ADC calibrations cannot run on 5 GHz with fast clock enabled. They need to be disabled, otherwise they'll hang and IQ mismatch calibration will not be run either. Signed-off-by: Felix Fietkau Reported-by: Adrian Chadd Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9002_calib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 2d4c0910295..2d394af8217 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -41,7 +41,8 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah, case ADC_DC_CAL: /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */ if (!IS_CHAN_B(chan) && - !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) && + IS_CHAN_HT20(chan))) supported = true; break; } -- cgit v1.2.3-70-g09d2 From e2faeec2de9e2c73958e6ea6065dde1e8cd6f3a2 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Tue, 30 Aug 2011 20:58:56 -0400 Subject: e1000: Fix driver to be used on PA RISC C8000 workstations The checksum field in the EEPROM on HPPA is really not a checksum but a signature (0x16d6). So allow 0x16d6 as the matching checksum on HPPA systems. This issue is present on longterm/stable kernels, I have verified that this patch is applicable back to at least 2.6.32.y kernels. v2- changed ifdef to use CONFIG_PARISC instead of __hppa__ CC: Guy Martin CC: Rolf Eike Beer CC: Matt Turner Reported-by: Mikulas Patocka Signed-off-by: Jeff Kirsher Acked-by: Jesse Brandeburg Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_hw.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 8545c7aa93e..a5a89ecb6f3 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -4026,6 +4026,12 @@ s32 e1000_validate_eeprom_checksum(struct e1000_hw *hw) checksum += eeprom_data; } +#ifdef CONFIG_PARISC + /* This is a signature and not a checksum on HP c8000 */ + if ((hw->subsystem_vendor_id == 0x103C) && (eeprom_data == 0x16d6)) + return E1000_SUCCESS; + +#endif if (checksum == (u16) EEPROM_SUM) return E1000_SUCCESS; else { -- cgit v1.2.3-70-g09d2 From aa9d842c5f2da6cdef2777f2f062f61898be89d3 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 10 Aug 2011 10:05:49 +0200 Subject: mfd: Rename wm8350 static gpio_set_debounce() The kernel already has a function with this name declared in asm-generic/gpio.h. So if this header leaks into wm8350/gpio.c we get drivers/mfd/wm8350-gpio.c:40:12: error: conflicting types for 'gpio_set_debounce' include/asm-generic/gpio.h:156:12: note: previous declaration of 'gpio_set_debounce' was here Fix this by adding a wm8350_ prefix to the function. Signed-off-by: Sascha Hauer Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8350-gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c index ebf99bef392..d584f6b4d6e 100644 --- a/drivers/mfd/wm8350-gpio.c +++ b/drivers/mfd/wm8350-gpio.c @@ -37,7 +37,7 @@ static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir) return ret; } -static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db) +static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db) { if (db == WM8350_GPIO_DEBOUNCE_ON) return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE, @@ -210,7 +210,7 @@ int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func, goto err; if (gpio_set_polarity(wm8350, gpio, pol)) goto err; - if (gpio_set_debounce(wm8350, gpio, debounce)) + if (wm8350_gpio_set_debounce(wm8350, gpio, debounce)) goto err; if (gpio_set_dir(wm8350, gpio, dir)) goto err; -- cgit v1.2.3-70-g09d2 From 66cc5b8e50af87b0bbd0f179d76d2826f4549c13 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Thu, 11 Aug 2011 22:33:12 -0500 Subject: mfd: Copy the device pointer to the twl4030-madc structure Worst case this fixes the following error: [ 72.086212] (NULL device *): conversion timeout! Best case it prevents a crash Signed-off-by: Kyle Manna Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-madc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index b5d598c3aa7..cb44b53dee3 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -706,6 +706,8 @@ static int __devinit twl4030_madc_probe(struct platform_device *pdev) if (!madc) return -ENOMEM; + madc->dev = &pdev->dev; + /* * Phoenix provides 2 interrupt lines. The first one is connected to * the OMAP. The other one can be connected to the other processor such -- cgit v1.2.3-70-g09d2 From d0e84caeb4cd535923884735906e5730329505b4 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Thu, 11 Aug 2011 22:33:14 -0500 Subject: mfd: Check for twl4030-madc NULL pointer If the twl4030-madc device wasn't registered, and another device, such as twl4030-madc-hwmon, calls twl4030_madc_conversion() a NULL pointer is dereferenced. Signed-off-by: Kyle Manna Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-madc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index cb44b53dee3..7cbf2aa9e64 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -510,8 +510,9 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) u8 ch_msb, ch_lsb; int ret; - if (!req) + if (!req || !twl4030_madc) return -EINVAL; + mutex_lock(&twl4030_madc->lock); if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { ret = -EINVAL; -- cgit v1.2.3-70-g09d2 From fa948761e685fb03823b3029e5b6bdb52229d6ce Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 15 Aug 2011 12:42:03 +0200 Subject: mfd: Fix initialisation of tps65910 interrupts Fix regression introduced by commit a2974732ca7614aaf0baf9d6dd3ad893d50ce1c5 (TPS65911: Add new irq definitions) which caused irq_num to be incorrectly set for tps65910. Cc: stable@kernel.org Signed-off-by: Johan Hovold Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65910-irq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index 2bfad5c86cc..a56be931551 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -178,8 +178,10 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, switch (tps65910_chip_id(tps65910)) { case TPS65910: tps65910->irq_num = TPS65910_NUM_IRQ; + break; case TPS65911: tps65910->irq_num = TPS65911_NUM_IRQ; + break; } /* Register with genirq */ -- cgit v1.2.3-70-g09d2 From 7eb3154e6caf7945ce60c196637b7ac06213befd Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Thu, 18 Aug 2011 16:37:35 +0900 Subject: mfd: Set MAX8997 irq pointer Required platform information is not handed to max8997-irq.c properly. This patch enables to hand over such information to max8997-irq.c so that max8997-irq functions properly. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Samuel Ortiz --- drivers/mfd/max8997.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 5d1fca0277e..f83103b8970 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -135,10 +135,13 @@ static int max8997_i2c_probe(struct i2c_client *i2c, max8997->dev = &i2c->dev; max8997->i2c = i2c; max8997->type = id->driver_data; + max8997->irq = i2c->irq; if (!pdata) goto err; + max8997->irq_base = pdata->irq_base; + max8997->ono = pdata->ono; max8997->wakeup = pdata->wakeup; mutex_init(&max8997->iolock); @@ -152,6 +155,8 @@ static int max8997_i2c_probe(struct i2c_client *i2c, pm_runtime_set_active(max8997->dev); + max8997_irq_init(max8997); + mfd_add_devices(max8997->dev, -1, max8997_devs, ARRAY_SIZE(max8997_devs), NULL, 0); -- cgit v1.2.3-70-g09d2 From e600cffe618ff0da29ae1f8b8d3824ce0e2409fc Mon Sep 17 00:00:00 2001 From: Anand Gadiyar Date: Thu, 18 Aug 2011 16:14:31 +0530 Subject: mfd: Make omap-usb-host TLL mode work again This code section seems to have been accidentally copy pasted. It causes incorrect bits to be set up in the TLL_CHANNEL_CONF register and prevents the TLL mode from working correctly. Cc: stable@kernel.org Signed-off-by: Anand Gadiyar Cc: Keshava Munegowda Acked-by: Felipe Balbi Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 29601e7d606..0f19ab14de8 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -676,7 +676,6 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); - reg |= (1 << (i + 1)); } else continue; -- cgit v1.2.3-70-g09d2 From 417e206b16e18bc729346b6db668031498975b8e Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 19 Aug 2011 16:57:54 +0800 Subject: mfd: Fix omap-usb-host build failure The patch fixes the build failure: drivers/mfd/omap-usb-host.c:1034:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1034:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' drivers/mfd/omap-usb-host.c:1034:1: warning: parameter names (without types) in function declaration drivers/mfd/omap-usb-host.c:1040:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1040:1: warning: type defaults to 'int' in declaration of 'EXPORT_SYMBOL_GPL' drivers/mfd/omap-usb-host.c:1040:1: warning: parameter names (without types) in function declaration drivers/mfd/omap-usb-host.c:1045:13: error: 'THIS_MODULE' undeclared here (not in a function) drivers/mfd/omap-usb-host.c:1050:15: error: expected declaration specifiers or '...' before string constant drivers/mfd/omap-usb-host.c:1050:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1050:1: warning: type defaults to 'int' in declaration of 'MODULE_AUTHOR' drivers/mfd/omap-usb-host.c:1050:15: warning: function declaration isn't a prototype drivers/mfd/omap-usb-host.c:1051:14: error: expected declaration specifiers or '...' before string constant drivers/mfd/omap-usb-host.c:1051:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1051:1: warning: type defaults to 'int' in declaration of 'MODULE_ALIAS' drivers/mfd/omap-usb-host.c:1051:14: warning: function declaration isn't a prototype drivers/mfd/omap-usb-host.c:1052:16: error: expected declaration specifiers or '...' before string constant drivers/mfd/omap-usb-host.c:1052:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1052:1: warning: type defaults to 'int' in declaration of 'MODULE_LICENSE' drivers/mfd/omap-usb-host.c:1052:16: warning: function declaration isn't a prototype drivers/mfd/omap-usb-host.c:1053:20: error: expected declaration specifiers or '...' before string constant drivers/mfd/omap-usb-host.c:1053:1: warning: data definition has no type or storage class drivers/mfd/omap-usb-host.c:1053:1: warning: type defaults to 'int' in declaration of 'MODULE_DESCRIPTION' drivers/mfd/omap-usb-host.c:1053:20: warning: function declaration isn't a prototype make[2]: *** [drivers/mfd/omap-usb-host.o] Error 1 CC fs/proc/namespaces.o make[1]: *** [drivers/mfd] Error 2 make: *** [drivers] Error 2 make: *** Waiting for unfinished jobs.... Signed-off-by: Ming Lei Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 0f19ab14de8..86e14583a08 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 3512069eefd3c3424b12f21a68fd473c3fd57220 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 8 Sep 2011 09:38:14 -0700 Subject: Input: wacom - add POINTER and DIRECT device properties Adds INPUT_PROP_POINTER or INPUT_PROP_DIRECT as necessary to the hardware supported by the Wacom driver. The DIRECT property is assigned to devices with an embedded screen (i.e. touchscreens and display tablets). The POINTER property is assigned to those without embedded screens. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-wacom.c | 2 ++ drivers/input/tablet/wacom_wac.c | 25 ++++++++++++++++++++++++- drivers/input/touchscreen/wacom_w8001.c | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 06888323828..5b9267dd3d6 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -383,6 +383,8 @@ move_on: hidinput = list_entry(hdev->inputs.next, struct hid_input, list); input = hidinput->input; + __set_bit(INPUT_PROP_POINTER, input->propbit); + /* Basics */ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 2d88316d0e5..c31e4e9f269 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1098,6 +1098,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); __set_bit(BTN_STYLUS2, input_dev->keybit); + + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; case WACOM_21UX2: @@ -1126,6 +1128,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, } input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); + + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + wacom_setup_cintiq(wacom_wac); break; @@ -1150,6 +1155,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, /* fall through */ case INTUOS: + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + wacom_setup_intuos(wacom_wac); break; @@ -1165,6 +1172,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); wacom_setup_intuos(wacom_wac); + + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; case TABLETPC2FG: @@ -1183,14 +1192,24 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case TABLETPC: __clear_bit(ABS_MISC, input_dev->absbit); + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + if (features->device_type != BTN_TOOL_PEN) break; /* no need to process stylus stuff */ /* fall through */ case PL: - case PTU: case DTU: + __set_bit(BTN_TOOL_PEN, input_dev->keybit); + __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); + __set_bit(BTN_STYLUS, input_dev->keybit); + __set_bit(BTN_STYLUS2, input_dev->keybit); + + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + break; + + case PTU: __set_bit(BTN_STYLUS2, input_dev->keybit); /* fall through */ @@ -1198,11 +1217,15 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOOL_PEN, input_dev->keybit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_STYLUS, input_dev->keybit); + + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + if (features->device_type == BTN_TOOL_DOUBLETAP) { __set_bit(BTN_LEFT, input_dev->keybit); __set_bit(BTN_FORWARD, input_dev->keybit); diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index c14412ef464..9941d39df43 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -383,6 +383,8 @@ static int w8001_setup(struct w8001 *w8001) dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); strlcat(w8001->name, "Wacom Serial", sizeof(w8001->name)); + __set_bit(INPUT_PROP_DIRECT, dev->propbit); + /* penabled? */ error = w8001_command(w8001, W8001_CMD_QUERY, true); if (!error) { -- cgit v1.2.3-70-g09d2 From 1c601beaf21671b5033169d04efeda462bf58f01 Mon Sep 17 00:00:00 2001 From: Pieter-Augustijn Van Malleghem Date: Fri, 9 Sep 2011 13:29:45 -0700 Subject: Input: bcm5974 - add MacBookAir4,1 trackpad support This patch adds trackpad support for the MacBookAir4,1, released in July 2011. It is very similar to the MacBookAir4,2 patch submitted by Joshua Dillon and Chase Douglas. Signed-off-by: Pieter-Augustijn Van Malleghem Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index da280189ef0..5ec617e28f7 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -67,6 +67,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 +/* MacbookAir4,1 (unibody, July 2011) */ +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249 +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b /* MacbookAir4,2 (unibody, July 2011) */ #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d @@ -112,6 +116,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), + /* MacbookAir4,1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS), /* MacbookAir4,2 */ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO), @@ -334,6 +342,18 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4750, 5280 }, { DIM_Y, DIM_Y / SN_COORD, -150, 6730 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4620, 5140 }, + { DIM_Y, DIM_Y / SN_COORD, -150, 6600 } + }, {} }; -- cgit v1.2.3-70-g09d2 From 8f9068609e8a5b4cbac9e0cf8332b5dcabf05422 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Fri, 9 Sep 2011 13:38:10 -0700 Subject: Input: wacom - fix touch parsing on newer Bamboos Bamboos with Product ID's > 0xD4 return values unrelated to pressure in touch 1 pressure field. They also report 2nd touch X/Y values shifted down 1 byte (where pressure was). This results in jumpy 1 finger touch and totally invalid 2nd finger data. For touch detection, switch to a Touch Present single bit that all versions of Bamboo support. For touch 2 offset, calculate offset based on a bit that is set different between the two packet layouts. Since touch pressure reports were removed from driver, there was no need to be reading pressure any more. Signed-off-by: Chris Bagwell Reviewed-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c31e4e9f269..0dc97ec15c2 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -800,20 +800,22 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) int i; for (i = 0; i < 2; i++) { - int p = data[9 * i + 2]; - bool touch = p && !wacom->shared->stylus_in_proximity; + int offset = (data[1] & 0x80) ? (8 * i) : (9 * i); + bool touch = data[offset + 3] & 0x80; - input_mt_slot(input, i); - input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); /* * Touch events need to be disabled while stylus is * in proximity because user's hand is resting on touchpad * and sending unwanted events. User expects tablet buttons * to continue working though. */ + touch = touch && !wacom->shared->stylus_in_proximity; + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); if (touch) { - int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff; - int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff; + int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff; + int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff; if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) { x <<= 5; y <<= 5; -- cgit v1.2.3-70-g09d2 From 40257b953fdd519c743138f3fbe3962d54991116 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 10 Sep 2011 06:02:12 -0700 Subject: hwmon: (pmbus) Fix low limit temperature alarms Temperature alarms are detected by checking the alarm bit and comparing temperature limits against the current temperature. For low limits, this comparison needs to be reversed (temp < limit instead of temp > limit). This was not taken into account, resulting in wrong alarms if a temperature fell below a low limit. Fix by adding a low limit flag in the limit data structure. When creating the sensor entry, the order of registers to compare is now reversed for low limits. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Cc: stable@kernel.org # 3.0+ --- drivers/hwmon/pmbus/pmbus_core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index a561c3a0e91..397fc59b568 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -978,6 +978,8 @@ static void pmbus_find_max_attr(struct i2c_client *client, struct pmbus_limit_attr { u16 reg; /* Limit register */ bool update; /* True if register needs updates */ + bool low; /* True if low limit; for limits with compare + functions only */ const char *attr; /* Attribute name */ const char *alarm; /* Alarm attribute name */ u32 sbit; /* Alarm attribute status bit */ @@ -1029,7 +1031,8 @@ static bool pmbus_add_limit_attrs(struct i2c_client *client, if (attr->compare) { pmbus_add_boolean_cmp(data, name, l->alarm, index, - cbase, cindex, + l->low ? cindex : cbase, + l->low ? cbase : cindex, attr->sbase + page, l->sbit); } else { pmbus_add_boolean_reg(data, name, @@ -1366,11 +1369,13 @@ static const struct pmbus_sensor_attr power_attributes[] = { static const struct pmbus_limit_attr temp_limit_attrs[] = { { .reg = PMBUS_UT_WARN_LIMIT, + .low = true, .attr = "min", .alarm = "min_alarm", .sbit = PB_TEMP_UT_WARNING, }, { .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, .attr = "lcrit", .alarm = "lcrit_alarm", .sbit = PB_TEMP_UT_FAULT, @@ -1399,11 +1404,13 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { static const struct pmbus_limit_attr temp_limit_attrs23[] = { { .reg = PMBUS_UT_WARN_LIMIT, + .low = true, .attr = "min", .alarm = "min_alarm", .sbit = PB_TEMP_UT_WARNING, }, { .reg = PMBUS_UT_FAULT_LIMIT, + .low = true, .attr = "lcrit", .alarm = "lcrit_alarm", .sbit = PB_TEMP_UT_FAULT, -- cgit v1.2.3-70-g09d2 From 3401dc6eba788ebc7c14ce51018d775b1c263399 Mon Sep 17 00:00:00 2001 From: George Date: Sat, 3 Sep 2011 10:58:47 -0500 Subject: rtlwifi: rtl8192su: Fix problem connecting to HT-enabled AP The driver fails to connect to 802.11n-enabled APs. The patch fixes Bug #42262. Signed-off-by: George Signed-off-by: Larry Finger Cc: Stable [2.6.39+] Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/rtl8192cu/trx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 906e7aa55bc..3e52a549622 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -549,15 +549,16 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { - if (tcb_desc->packet_bw) { + if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { SET_TX_DESC_DATA_BW(txdesc, 1); SET_TX_DESC_DATA_SC(txdesc, 3); + } else if(rate_flag & IEEE80211_TX_RC_40_MHZ_WIDTH){ + SET_TX_DESC_DATA_BW(txdesc, 1); + SET_TX_DESC_DATA_SC(txdesc, mac->cur_40_prime_sc); } else { SET_TX_DESC_DATA_BW(txdesc, 0); - if (rate_flag & IEEE80211_TX_RC_DUP_DATA) - SET_TX_DESC_DATA_SC(txdesc, - mac->cur_40_prime_sc); - } + SET_TX_DESC_DATA_SC(txdesc, 0); + } } else { SET_TX_DESC_DATA_BW(txdesc, 0); SET_TX_DESC_DATA_SC(txdesc, 0); -- cgit v1.2.3-70-g09d2 From bac2555c6d86387132930af4d14cb47c4dd3f4f7 Mon Sep 17 00:00:00 2001 From: George Date: Sat, 3 Sep 2011 10:58:48 -0500 Subject: rtlwifi: Fix problem when switching connections The driver fails to clear encryption keys making it impossible to switch connections. Signed-off-by: George Signed-off-by: Larry Finger Cc: Stable [2.6.39+] Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 1bdc1aa305c..04c4e9eb6ee 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -610,6 +610,11 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + + rtl_cam_reset_all_entry(hw); mac->vendor = PEER_UNKNOWN; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, @@ -1063,6 +1068,9 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, *or clear all entry here. */ rtl_cam_delete_one_entry(hw, mac_addr, key_idx); + + rtl_cam_reset_sec_info(hw); + break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, -- cgit v1.2.3-70-g09d2 From 6a6b3f3e13decfc4b97263a83ea4e80ac8cc89ae Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 9 Sep 2011 10:41:08 +0530 Subject: ath9k: Fix kernel panic on unplugging the device when the device is yanked out ath_pci_remove starts doing the cleanups, unregistering the hardware etc. so we should bail out immediately when we get drv_flush callback from mac80211 when the card is being unplugged. the panic occurs after we had associated to an AP. EIP: 0060:[] EFLAGS: 00010246 CPU: 0 EIP is at ath_reset+0xa0/0x1c0 [ath9k] EAX: 00000000 EBX: 000697c0 ECX: 00000002 EDX: f3c3ccf0 ESI: 00000000 EDI: 00000000 EBP: f43e7b78 ESP: f43e7b50 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process kworker/u:2 (pid: 182, ti=f43e6000 task=f3c3c7c0 task.ti=f43e6000) Stack: 0000002a 00000000 00000000 003e7b78 0000000f eaaa8500 ffffffea eaaa97c0 eaaaa000 00000001 f43e7ba8 fb315d23 f99e7721 ecece680 eaaac738 eaaa8500 eaaaa020 000000c8 000000c8 00000000 eaaa8d58 eaaa8500 f43e7bd0 fb080b29 Call Trace: [] ath9k_flush+0x103/0x170 [ath9k] [] __ieee80211_recalc_idle+0x2c9/0x400 [mac80211] [] ieee80211_recalc_idle+0x2e/0x60 [mac80211] [] ieee80211_mgd_deauth+0x173/0x210 [mac80211] [] ieee80211_deauth+0x19/0x20 [mac80211] [] __cfg80211_mlme_deauth+0xf3/0x140 [cfg80211] [] ? __mutex_lock_common+0x1f0/0x380 [] __cfg80211_disconnect+0x18d/0x1f0 [cfg80211] [] cfg80211_netdev_notifier_call+0x159/0x5c0 [cfg80211] [] ? packet_notifier+0x174/0x1f0 [] notifier_call_chain+0x82/0xb0 [] raw_notifier_call_chain+0x1f/0x30 [] call_netdevice_notifiers+0x2c/0x60 [] ? trace_hardirqs_on_caller+0xf4/0x180 [] __dev_close_many+0x4c/0xd0 [] dev_close_many+0x6d/0xc0 [] rollback_registered_many+0x93/0x1c0 [] ? trace_hardirqs_on+0xb/0x10 [] unregister_netdevice_many+0x15/0x50 [] ieee80211_remove_interfaces+0x7b/0xb0 [mac80211] [] ieee80211_unregister_hw+0x4b/0x110 [mac80211] [] ath9k_deinit_device+0x3a/0x60 [ath9k] [] ath_pci_remove+0x46/0x90 [ath9k] [] pci_device_remove+0x44/0x100 [] __device_release_driver+0x64/0xb0 [] device_release_driver+0x27/0x40 [] bus_remove_device+0x7b/0xa0 [] device_del+0xf1/0x180 [] device_unregister+0x10/0x20 [] pci_stop_bus_device+0x6e/0x80 [] pci_remove_bus_device+0x12/0xa0 [] pciehp_unconfigure_device+0x89/0x180 [] ? mark_held_locks+0x64/0x100 [] ? __mutex_unlock_slowpath+0xaf/0x140 [] pciehp_disable_slot+0x64/0x1b0 [] pciehp_power_thread+0xd0/0x100 [] ? process_one_work+0x100/0x4d0 [] process_one_work+0x17c/0x4d0 [] ? process_one_work+0x100/0x4d0 [] ? queue_interrupt_event+0xa0/0xa0 [] worker_thread+0x13b/0x320 [] ? trace_hardirqs_on+0xb/0x10 [] ? manage_workers+0x1e0/0x1e0 [] kthread+0x84/0x90 [] ? __init_kthread_worker+0x60/0x60 [] kernel_thread_helper+0x6/0x10 Cc: Rajkumar Manoharan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 6530694a59a..722967b86cf 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2303,6 +2303,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) mutex_lock(&sc->mutex); cancel_delayed_work_sync(&sc->tx_complete_work); + if (ah->ah_flags & AH_UNPLUGGED) { + ath_dbg(common, ATH_DBG_ANY, "Device has been unplugged!\n"); + mutex_unlock(&sc->mutex); + return; + } + if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); mutex_unlock(&sc->mutex); -- cgit v1.2.3-70-g09d2 From 456fc37e4519f3f551830ce01c58ddaa35807204 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Sep 2011 21:08:25 +0200 Subject: iwlagn: fix stack corruption Alexander reported a strange crash in iwlagn that Meenakshi and Wey couldn't reproduce. I just ran into the same issue and tracked it down to stack corruption. This fixes it. The problem was introduced in commit 4b8b99b6e650d0527f3a123744b7459976581d14 Author: Wey-Yi Guy Date: Fri Jul 8 14:29:48 2011 -0700 iwlagn: radio sensor offset in le16 format Cc: Wey-Yi Guy Cc: Meenakshi Venkataraman Reported-by: Alexander Diewald Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index a895a099d08..56211006a18 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -167,7 +167,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); - memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(offset_calib)); + memcpy(&cmd.radio_sensor_offset, offset_calib, sizeof(*offset_calib)); if (!(cmd.radio_sensor_offset)) cmd.radio_sensor_offset = DEFAULT_RADIO_SENSOR_OFFSET; -- cgit v1.2.3-70-g09d2 From 282cdb325aea4ebbc42ce753b47cc96145eb54bc Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 12 Sep 2011 12:09:10 -0700 Subject: iwlagn: fix command queue timeout If the command queue is constantly busy, which can happen in P2P, the hangcheck timer will frequently find a command in it and will eventually reset the device because nothing sets the timestamp for this queue when commands are processed. Fix this by setting the timestamp when a command completes. Cc: stable@kernel.org #2.6.39, #3.0.0 #3.1.0 Signed-off-by: Johannes Berg SIgned-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c index a6b2b1db0b1..222d410c586 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c @@ -771,6 +771,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; + txq->time_stamp = jiffies; + iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ -- cgit v1.2.3-70-g09d2 From 477694e71113fd0694b6bb0bcc2d006b8ac62691 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 19 Jul 2011 16:25:42 +0200 Subject: x86, iommu: Mark DMAR IRQ as non-threaded Mark this lowlevel IRQ handler as non-threaded. This prevents a boot crash when "threadirqs" is on the kernel commandline. Also the interrupt handler is handling hardware critical events which should not be delayed into a thread. Signed-off-by: Thomas Gleixner Cc: stable@kernel.org Signed-off-by: Ingo Molnar --- drivers/iommu/dmar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 3dc9befa5ae..6dcc7e2d54d 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1388,7 +1388,7 @@ int dmar_set_interrupt(struct intel_iommu *iommu) return ret; } - ret = request_irq(irq, dmar_fault, 0, iommu->name, iommu); + ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu); if (ret) printk(KERN_ERR "IOMMU: can't request irq\n"); return ret; -- cgit v1.2.3-70-g09d2 From 1a4b1a41b8a3d5256019854e851beed063b34344 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 13 Sep 2011 15:16:33 -0300 Subject: pci: Don't crash when reading mpss from root complex In pcie_find_smpss(), we have the following statement: if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) || dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT)) The problem is that at least on my machine, this gets called for the root complex (virtual P2P bridge), and dev->bus->self is NULL since the parent bus for this is not itself anchor to a PCI device. This adds the necessary NULL check. Signed-off-by: Benjamin Herrenschmidt Acked-by: Jon Mason Signed-off-by: Linus Torvalds --- drivers/pci/probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b1187ff31d8..f3f94a5c068 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1351,7 +1351,8 @@ static int pcie_find_smpss(struct pci_dev *dev, void *data) * will occur as normal. */ if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) || - dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT)) + (dev->bus->self && + dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))) *smpss = 0; if (*smpss > dev->pcie_mpss) -- cgit v1.2.3-70-g09d2 From cd5bd3df1a6e7a68454734fb109c409101c20f42 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 14 Sep 2011 04:43:07 -0400 Subject: hwmon: (coretemp) Initialize tmin ttarget is initialized when the driver is loaded, but tmin is not. As a result, tempX_max_hyst attributes read 0. Fix this. Also use THERM_*_THRESHOLD* constants in these initializations instead of hard-coding the constants. Signed-off-by: Jean Delvare Cc: "R, Durgadoss" Cc: Guenter Roeck Cc: Fenghua Yu Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 59d83e83da7..41125767613 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -601,7 +601,12 @@ static int create_core_data(struct platform_data *pdata, err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx); if (!err) { tdata->attr_size += MAX_THRESH_ATTRS; - tdata->ttarget = tdata->tjmax - ((eax >> 16) & 0x7f) * 1000; + tdata->tmin = tdata->tjmax - + ((eax & THERM_MASK_THRESHOLD0) >> + THERM_SHIFT_THRESHOLD0) * 1000; + tdata->ttarget = tdata->tjmax - + ((eax & THERM_MASK_THRESHOLD1) >> + THERM_SHIFT_THRESHOLD1) * 1000; } pdata->core_data[attr_no] = tdata; -- cgit v1.2.3-70-g09d2 From ff02b13f6867af72682d7a9bb9bd705f9af2bab0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 14 Sep 2011 06:08:06 +1000 Subject: drm/ttm: request zeroed system memory pages for new TT buffer objects Fixes an information leak to userspace, we were handing out un-zeroed pages for any newly created TTM_PL_TT buffer. Reported-by: Marcin Slusarz Signed-off-by: Ben Skeggs Tested-by: Marcin Slusarz Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index a4d38d85909..ef06194c5aa 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -394,7 +394,8 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { if (bo->ttm == NULL) { - ret = ttm_bo_add_ttm(bo, false); + bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); + ret = ttm_bo_add_ttm(bo, zero); if (ret) goto out_err; } -- cgit v1.2.3-70-g09d2 From 87463ff83bcda210d8f0ae440bd64d1548f852e7 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Tue, 13 Sep 2011 11:27:35 +0200 Subject: drm/radeon: Don't read from CP ring write pointer registers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently this doesn't always work reliably, e.g. at resume time. Just initialize to 0, so the ring is considered empty. Tested with hibernation on Sumo and Cayman cards. Should fix https://bugs.launchpad.net/ubuntu/+source/linux/+bug/820746/ . Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 4 ++-- drivers/gpu/drm/radeon/ni.c | 12 ++++++------ drivers/gpu/drm/radeon/r100.c | 6 ++---- drivers/gpu/drm/radeon/r600.c | 4 ++-- 4 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index dc0a5b56c81..f10d1c1c255 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1404,7 +1404,8 @@ int evergreen_cp_resume(struct radeon_device *rdev) /* Initialize the ring buffer's read and write pointers */ WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); WREG32(CP_RB_RPTR_WR, 0); - WREG32(CP_RB_WPTR, 0); + rdev->cp.wptr = 0; + WREG32(CP_RB_WPTR, rdev->cp.wptr); /* set the wb address wether it's enabled or not */ WREG32(CP_RB_RPTR_ADDR, @@ -1426,7 +1427,6 @@ int evergreen_cp_resume(struct radeon_device *rdev) WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); rdev->cp.rptr = RREG32(CP_RB_RPTR); - rdev->cp.wptr = RREG32(CP_RB_WPTR); evergreen_cp_start(rdev); rdev->cp.ready = true; diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index cbf57d75d92..99fbd793c08 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1187,7 +1187,8 @@ int cayman_cp_resume(struct radeon_device *rdev) /* Initialize the ring buffer's read and write pointers */ WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA); - WREG32(CP_RB0_WPTR, 0); + rdev->cp.wptr = 0; + WREG32(CP_RB0_WPTR, rdev->cp.wptr); /* set the wb address wether it's enabled or not */ WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC); @@ -1207,7 +1208,6 @@ int cayman_cp_resume(struct radeon_device *rdev) WREG32(CP_RB0_BASE, rdev->cp.gpu_addr >> 8); rdev->cp.rptr = RREG32(CP_RB0_RPTR); - rdev->cp.wptr = RREG32(CP_RB0_WPTR); /* ring1 - compute only */ /* Set ring buffer size */ @@ -1220,7 +1220,8 @@ int cayman_cp_resume(struct radeon_device *rdev) /* Initialize the ring buffer's read and write pointers */ WREG32(CP_RB1_CNTL, tmp | RB_RPTR_WR_ENA); - WREG32(CP_RB1_WPTR, 0); + rdev->cp1.wptr = 0; + WREG32(CP_RB1_WPTR, rdev->cp1.wptr); /* set the wb address wether it's enabled or not */ WREG32(CP_RB1_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET) & 0xFFFFFFFC); @@ -1232,7 +1233,6 @@ int cayman_cp_resume(struct radeon_device *rdev) WREG32(CP_RB1_BASE, rdev->cp1.gpu_addr >> 8); rdev->cp1.rptr = RREG32(CP_RB1_RPTR); - rdev->cp1.wptr = RREG32(CP_RB1_WPTR); /* ring2 - compute only */ /* Set ring buffer size */ @@ -1245,7 +1245,8 @@ int cayman_cp_resume(struct radeon_device *rdev) /* Initialize the ring buffer's read and write pointers */ WREG32(CP_RB2_CNTL, tmp | RB_RPTR_WR_ENA); - WREG32(CP_RB2_WPTR, 0); + rdev->cp2.wptr = 0; + WREG32(CP_RB2_WPTR, rdev->cp2.wptr); /* set the wb address wether it's enabled or not */ WREG32(CP_RB2_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET) & 0xFFFFFFFC); @@ -1257,7 +1258,6 @@ int cayman_cp_resume(struct radeon_device *rdev) WREG32(CP_RB2_BASE, rdev->cp2.gpu_addr >> 8); rdev->cp2.rptr = RREG32(CP_RB2_RPTR); - rdev->cp2.wptr = RREG32(CP_RB2_WPTR); /* start the rings */ cayman_cp_start(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index f2204cb1ccd..11e44a3479e 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -990,7 +990,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) /* Force read & write ptr to 0 */ WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA | RADEON_RB_NO_UPDATE); WREG32(RADEON_CP_RB_RPTR_WR, 0); - WREG32(RADEON_CP_RB_WPTR, 0); + rdev->cp.wptr = 0; + WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr); /* set the wb address whether it's enabled or not */ WREG32(R_00070C_CP_RB_RPTR_ADDR, @@ -1007,9 +1008,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) WREG32(RADEON_CP_RB_CNTL, tmp); udelay(10); rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR); - rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR); - /* protect against crazy HW on resume */ - rdev->cp.wptr &= rdev->cp.ptr_mask; /* Set cp mode to bus mastering & enable cp*/ WREG32(RADEON_CP_CSQ_MODE, REG_SET(RADEON_INDIRECT2_START, indirect2_start) | diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index aa5571b73aa..c68427612e3 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2209,7 +2209,8 @@ int r600_cp_resume(struct radeon_device *rdev) /* Initialize the ring buffer's read and write pointers */ WREG32(CP_RB_CNTL, tmp | RB_RPTR_WR_ENA); WREG32(CP_RB_RPTR_WR, 0); - WREG32(CP_RB_WPTR, 0); + rdev->cp.wptr = 0; + WREG32(CP_RB_WPTR, rdev->cp.wptr); /* set the wb address whether it's enabled or not */ WREG32(CP_RB_RPTR_ADDR, @@ -2231,7 +2232,6 @@ int r600_cp_resume(struct radeon_device *rdev) WREG32(CP_DEBUG, (1 << 27) | (1 << 28)); rdev->cp.rptr = RREG32(CP_RB_RPTR); - rdev->cp.wptr = RREG32(CP_RB_WPTR); r600_cp_start(rdev); rdev->cp.ready = true; -- cgit v1.2.3-70-g09d2 From db318d7a8a910657f10ffdf223c971af20a9b09c Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Tue, 13 Sep 2011 11:29:12 +0200 Subject: drm/radeon: Unreference GEM object outside of spinlock in page flip error path. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should fix https://bugzilla.redhat.com/show_bug.cgi?id=726277 . Signed-off-by: Michel Dänzer cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6cc17fb96a5..6adb3e58aff 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -473,8 +473,8 @@ pflip_cleanup: spin_lock_irqsave(&dev->event_lock, flags); radeon_crtc->unpin_work = NULL; unlock_free: - drm_gem_object_unreference_unlocked(old_radeon_fb->obj); spin_unlock_irqrestore(&dev->event_lock, flags); + drm_gem_object_unreference_unlocked(old_radeon_fb->obj); radeon_fence_unref(&work->fence); kfree(work); -- cgit v1.2.3-70-g09d2 From d4c32f355cec2647efb65e4b24e630bd2386f787 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 14 Sep 2011 16:21:47 -0700 Subject: drivers/rtc/rtc-imxdi.c needs linux/sched.h Include linux/sched.h to fix below build error. CC drivers/rtc/rtc-imxdi.o drivers/rtc/rtc-imxdi.c: In function 'di_write_wait': drivers/rtc/rtc-imxdi.c:168: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function) drivers/rtc/rtc-imxdi.c:168: error: (Each undeclared identifier is reported only once drivers/rtc/rtc-imxdi.c:168: error: for each function it appears in.) drivers/rtc/rtc-imxdi.c:168: error: implicit declaration of function 'signal_pending' drivers/rtc/rtc-imxdi.c:168: error: implicit declaration of function 'schedule_timeout' drivers/rtc/rtc-imxdi.c: In function 'dryice_norm_irq': drivers/rtc/rtc-imxdi.c:329: error: 'TASK_INTERRUPTIBLE' undeclared (first use in this function) Signed-off-by: Axel Lin Cc: Baruch Siach Cc: Wan ZongShun Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-imxdi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 2dd3c016327..d93a9608b1f 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include /* DryIce Register Definitions */ -- cgit v1.2.3-70-g09d2 From 83ede96e98f5a7eb3ed07c78cb1dd166581eb864 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Wed, 14 Sep 2011 16:22:06 -0700 Subject: cris: fix a build error in drivers/tty/serial/crisv10.c Fix these errors: drivers/tty/serial/crisv10.c:4453: error: 'if_ser0' undeclared (first use in this function): 2 errors in 2 logs drivers/tty/serial/crisv10.c:4453: error: (Each undeclared identifier is reported only once: 2 errors in 2 logs drivers/tty/serial/crisv10.c:4453: error: for each function it appears in.): 2 errors in 2 logs "if_ser0" is a typo, it should be "if_serial_0". Signed-off-by: WANG Cong Cc: Mikael Starvik Cc: Jesper Nilsson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/tty/serial/crisv10.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 225123b37f1..58be715913c 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4450,7 +4450,7 @@ static int __init rs_init(void) #if defined(CONFIG_ETRAX_RS485) #if defined(CONFIG_ETRAX_RS485_ON_PA) - if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, + if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit, rs485_pa_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); @@ -4459,7 +4459,7 @@ static int __init rs_init(void) } #endif #if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, + if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, rs485_port_g_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); -- cgit v1.2.3-70-g09d2 From 1ebe9dad947d3158676f5ae55fc8b4f05b85c527 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 14 Sep 2011 16:22:12 -0700 Subject: drivers/misc/pti.c: give 'comm' function scope in pti_control_frame_built_and_sent() In drivers/misc/pti.c::pti_control_frame_built_and_sent() we assign 'comm' to 'thread_name_p' if (!thread_name). The problem is that 'comm' then goes out of scope and later we use 'thread_name_p' which now refers to an out-of-scope variable. To fix that, simply move 'comm' up to have function scope. Signed-off-by: Jesper Juhl Cc: Greg Kroah-Hartman Cc: J Freyensee Cc: Jeremy Rocher Cc: Sergei Trofimovich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/pti.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 06df1877ad0..0b56e3f4357 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -165,6 +165,11 @@ static void pti_write_to_aperture(struct pti_masterchannel *mc, static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc, const char *thread_name) { + /* + * Since we access the comm member in current's task_struct, we only + * need to be as large as what 'comm' in that structure is. + */ + char comm[TASK_COMM_LEN]; struct pti_masterchannel mccontrol = {.master = CONTROL_ID, .channel = 0}; const char *thread_name_p; @@ -172,13 +177,6 @@ static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc, u8 control_frame[CONTROL_FRAME_LEN]; if (!thread_name) { - /* - * Since we access the comm member in current's task_struct, - * we only need to be as large as what 'comm' in that - * structure is. - */ - char comm[TASK_COMM_LEN]; - if (!in_interrupt()) get_task_comm(comm, current); else -- cgit v1.2.3-70-g09d2 From 7a5caabd090b8f7d782c40fc1c048d798f2b6fd7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 14 Sep 2011 16:22:16 -0700 Subject: drivers/leds/ledtrig-timer.c: fix broken sysfs delay handling Fix regression introduced by commit 5ada28bf7675 ("led-class: always implement blinking") which broke sysfs delay handling by not storing the updated value. Consequently it was only possible to set one of the delays through the sysfs interface as the other delay was automatically restored to it's default value. Reading the parameters always gave the defaults. Signed-off-by: Johan Hovold Acked-by: Florian Fainelli Acked-by: Richard Purdie Cc: [2.6.37+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/ledtrig-timer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index d87c9d02f78..328c64c0841 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -41,6 +41,7 @@ static ssize_t led_delay_on_store(struct device *dev, if (count == size) { led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); + led_cdev->blink_delay_on = state; ret = count; } @@ -69,6 +70,7 @@ static ssize_t led_delay_off_store(struct device *dev, if (count == size) { led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); + led_cdev->blink_delay_off = state; ret = count; } -- cgit v1.2.3-70-g09d2 From 88cee8fd77af28d414b983798dd30c8950c71e31 Mon Sep 17 00:00:00 2001 From: Donggeun Kim Date: Wed, 14 Sep 2011 16:22:19 -0700 Subject: drivers/rtc/rtc-s3c.c: fix no occurrence of alarm interrupt The driver does not generate an alarm interrupt even though a time for an alarm is set. This results from disabling rtc_clk after setting the alarm time. To generate an alarm interrupt the driver should maintain its enabled state for rtc_clk the until alarm interrupt occurs. This patch permits generation of an alarm interrupt. [akpm@linux-foundation.org: make s3c_rtc_alarm_clk_lock local to s3c_rtc_alarm_clk_enable()] Signed-off-by: Donggeun Kim Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 4e7c04e773e..7639ab906f0 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -51,6 +51,27 @@ static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); +static void s3c_rtc_alarm_clk_enable(bool enable) +{ + static DEFINE_SPINLOCK(s3c_rtc_alarm_clk_lock); + static bool alarm_clk_enabled; + unsigned long irq_flags; + + spin_lock_irqsave(&s3c_rtc_alarm_clk_lock, irq_flags); + if (enable) { + if (!alarm_clk_enabled) { + clk_enable(rtc_clk); + alarm_clk_enabled = true; + } + } else { + if (alarm_clk_enabled) { + clk_disable(rtc_clk); + alarm_clk_enabled = false; + } + } + spin_unlock_irqrestore(&s3c_rtc_alarm_clk_lock, irq_flags); +} + /* IRQ Handlers */ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) @@ -64,6 +85,9 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); clk_disable(rtc_clk); + + s3c_rtc_alarm_clk_enable(false); + return IRQ_HANDLED; } @@ -97,6 +121,8 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); clk_disable(rtc_clk); + s3c_rtc_alarm_clk_enable(enabled); + return 0; } -- cgit v1.2.3-70-g09d2 From e71f5cc402ecb42b407ae52add7b173bf1c53daa Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Wed, 14 Sep 2011 16:22:23 -0700 Subject: drivers/cpufreq/pcc-cpufreq.c: avoid NULL pointer dereference per_cpu(processors, n) can be NULL, resulting in: Loading CPUFreq modules[ 437.661360] BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] pcc_cpufreq_cpu_init+0x74/0x220 [pcc_cpufreq] It's better to avoid the oops by failing the driver, and allowing the system to boot. Signed-off-by: Naga Chumbalkar Cc: Dave Jones Cc: Len Brown Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cpufreq/pcc-cpufreq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c index 7b0603eb012..cdc02ac8f41 100644 --- a/drivers/cpufreq/pcc-cpufreq.c +++ b/drivers/cpufreq/pcc-cpufreq.c @@ -261,6 +261,9 @@ static int pcc_get_offset(int cpu) pr = per_cpu(processors, cpu); pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu); + if (!pr) + return -ENODEV; + status = acpi_evaluate_object(pr->handle, "PCCP", NULL, &buffer); if (ACPI_FAILURE(status)) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 4f5b04800a224aadb6cffcbbc3d3fa26e2367c7f Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 14 Sep 2011 16:22:29 -0700 Subject: drivers/gpio/gpio-generic.c: fix build errors Building a kernel with hotplug disabled results in a link failure: `bgpio_remove' referenced in section `___ksymtab_gpl+bgpio_remove' of drivers/built-in.o: defined in discarded section `.devexit.text' of drivers/built-in.o This is because of bgpio_remove() is exported. It is illegal to export symbols which are discarded either at link time or as part of an init/exit section. Fix this by dropping the __devexit attributation from bgpio_remove(). Also drop the __devinit attributation from bgpio_init(). Signed-off-by: Russell King Cc: Grant Likely Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpio/gpio-generic.c | 15 +++++---------- include/linux/basic_mmio_gpio.h | 15 +++++---------- 2 files changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 231714def4d..4e24436b0f8 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -351,7 +351,7 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, return 0; } -int __devexit bgpio_remove(struct bgpio_chip *bgc) +int bgpio_remove(struct bgpio_chip *bgc) { int err = gpiochip_remove(&bgc->gc); @@ -361,15 +361,10 @@ int __devexit bgpio_remove(struct bgpio_chip *bgc) } EXPORT_SYMBOL_GPL(bgpio_remove); -int __devinit bgpio_init(struct bgpio_chip *bgc, - struct device *dev, - unsigned long sz, - void __iomem *dat, - void __iomem *set, - void __iomem *clr, - void __iomem *dirout, - void __iomem *dirin, - bool big_endian) +int bgpio_init(struct bgpio_chip *bgc, struct device *dev, + unsigned long sz, void __iomem *dat, void __iomem *set, + void __iomem *clr, void __iomem *dirout, void __iomem *dirin, + bool big_endian) { int ret; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index 98999cf107c..feb91219674 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -63,15 +63,10 @@ static inline struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc) return container_of(gc, struct bgpio_chip, gc); } -int __devexit bgpio_remove(struct bgpio_chip *bgc); -int __devinit bgpio_init(struct bgpio_chip *bgc, - struct device *dev, - unsigned long sz, - void __iomem *dat, - void __iomem *set, - void __iomem *clr, - void __iomem *dirout, - void __iomem *dirin, - bool big_endian); +int bgpio_remove(struct bgpio_chip *bgc); +int bgpio_init(struct bgpio_chip *bgc, struct device *dev, + unsigned long sz, void __iomem *dat, void __iomem *set, + void __iomem *clr, void __iomem *dirout, void __iomem *dirin, + bool big_endian); #endif /* __BASIC_MMIO_GPIO_H */ -- cgit v1.2.3-70-g09d2 From 773659483685d652970583384a0294948e57f8b3 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 14 Sep 2011 05:10:00 -0400 Subject: xen/irq: Alter the locking to use a mutex instead of a spinlock. When we allocate/change the IRQ informations, we do not need to use spinlocks. We can use a mutex (which is what the generic IRQ code does for allocations/changes). Fixes a slew of: BUG: sleeping function called from invalid context at /linux/kernel/mutex.c:271 in_atomic(): 1, irqs_disabled(): 0, pid: 3216, name: xenstored 2 locks held by xenstored/3216: #0: (&u->bind_mutex){......}, at: [] evtchn_ioctl+0x30/0x3a0 [xen_evtchn] #1: (irq_mapping_update_lock){......}, at: [] bind_evtchn_to_irq+0x24/0x90 Pid: 3216, comm: xenstored Not tainted 3.1.0-rc6-00021-g437a3d1 #2 Call Trace: [] __might_sleep+0x100/0x130 [] mutex_lock_nested+0x2f/0x50 [] __irq_alloc_descs+0x49/0x200 [] ? evtchn_ioctl+0x30/0x3a0 [xen_evtchn] [] xen_allocate_irq_dynamic+0x34/0x70 [] bind_evtchn_to_irq+0x5d/0x90 [] ? evtchn_bind_to_user+0x60/0x60 [xen_evtchn] [] bind_evtchn_to_irqhandler+0x32/0x80 [] evtchn_bind_to_user+0x49/0x60 [xen_evtchn] [] evtchn_ioctl+0x144/0x3a0 [xen_evtchn] [] ? vfsmount_lock_local_unlock+0x50/0x80 [] do_vfs_ioctl+0x9a/0x5e0 [] ? mntput+0x1f/0x30 [] ? fput+0x199/0x240 [] sys_ioctl+0xa1/0xb0 [] system_call_fastpath+0x16/0x1b Reported-by: Jim Burns Acked-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index da70f5c32eb..7523719bf8a 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -54,7 +54,7 @@ * This lock protects updates to the following mapping and reference-count * arrays. The lock does not need to be acquired to read the mapping tables. */ -static DEFINE_SPINLOCK(irq_mapping_update_lock); +static DEFINE_MUTEX(irq_mapping_update_lock); static LIST_HEAD(xen_irq_list_head); @@ -631,7 +631,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, int irq = -1; struct physdev_irq irq_op; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); irq = find_irq_by_gsi(gsi); if (irq != -1) { @@ -684,7 +684,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, handle_edge_irq, name); out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; } @@ -710,7 +710,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, { int irq, ret; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); irq = xen_allocate_irq_dynamic(); if (irq == -1) @@ -724,10 +724,10 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, if (ret < 0) goto error_irq; out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; error_irq: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); xen_free_irq(irq); return -1; } @@ -740,7 +740,7 @@ int xen_destroy_irq(int irq) struct irq_info *info = info_for_irq(irq); int rc = -ENOENT; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); desc = irq_to_desc(irq); if (!desc) @@ -766,7 +766,7 @@ int xen_destroy_irq(int irq) xen_free_irq(irq); out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return rc; } @@ -776,7 +776,7 @@ int xen_irq_from_pirq(unsigned pirq) struct irq_info *info; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); list_for_each_entry(info, &xen_irq_list_head, list) { if (info == NULL || info->type != IRQT_PIRQ) @@ -787,7 +787,7 @@ int xen_irq_from_pirq(unsigned pirq) } irq = -1; out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; } @@ -802,7 +802,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) { int irq; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); irq = evtchn_to_irq[evtchn]; @@ -818,7 +818,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) } out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; } @@ -829,7 +829,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) struct evtchn_bind_ipi bind_ipi; int evtchn, irq; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); irq = per_cpu(ipi_to_irq, cpu)[ipi]; @@ -853,7 +853,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) } out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; } @@ -878,7 +878,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) struct evtchn_bind_virq bind_virq; int evtchn, irq; - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); irq = per_cpu(virq_to_irq, cpu)[virq]; @@ -903,7 +903,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) } out: - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); return irq; } @@ -913,7 +913,7 @@ static void unbind_from_irq(unsigned int irq) struct evtchn_close close; int evtchn = evtchn_from_irq(irq); - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); if (VALID_EVTCHN(evtchn)) { close.port = evtchn; @@ -943,7 +943,7 @@ static void unbind_from_irq(unsigned int irq) xen_free_irq(irq); - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); } int bind_evtchn_to_irqhandler(unsigned int evtchn, @@ -1279,7 +1279,7 @@ void rebind_evtchn_irq(int evtchn, int irq) will also be masked. */ disable_irq(irq); - spin_lock(&irq_mapping_update_lock); + mutex_lock(&irq_mapping_update_lock); /* After resume the irq<->evtchn mappings are all cleared out */ BUG_ON(evtchn_to_irq[evtchn] != -1); @@ -1289,7 +1289,7 @@ void rebind_evtchn_irq(int evtchn, int irq) xen_irq_info_evtchn_init(irq, evtchn); - spin_unlock(&irq_mapping_update_lock); + mutex_unlock(&irq_mapping_update_lock); /* new event channels are always bound to cpu 0 */ irq_set_affinity(irq, cpumask_of(0)); -- cgit v1.2.3-70-g09d2 From dfacf1387ceb6d7d6df614b18016fd1f347a1996 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:39 +0000 Subject: bnx2x: fix BRB thresholds for dropless_fc mode Fix the thresholds according to 5778x HW and increase rx_ring size to suit new thresholds in dropless_fc mode. Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x.h | 84 +++++++++++++++++++++++++++++++++++++----- drivers/net/bnx2x/bnx2x_cmn.c | 10 ++--- drivers/net/bnx2x/bnx2x_main.c | 33 ++++++++++++----- 3 files changed, 102 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index c423504a755..85297326506 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -315,6 +315,14 @@ union db_prod { u32 raw; }; +/* dropless fc FW/HW related params */ +#define BRB_SIZE(bp) (CHIP_IS_E3(bp) ? 1024 : 512) +#define MAX_AGG_QS(bp) (CHIP_IS_E1(bp) ? \ + ETH_MAX_AGGREGATION_QUEUES_E1 :\ + ETH_MAX_AGGREGATION_QUEUES_E1H_E2) +#define FW_DROP_LEVEL(bp) (3 + MAX_SPQ_PENDING + MAX_AGG_QS(bp)) +#define FW_PREFETCH_CNT 16 +#define DROPLESS_FC_HEADROOM 100 /* MC hsi */ #define BCM_PAGE_SHIFT 12 @@ -331,15 +339,35 @@ union db_prod { /* SGE ring related macros */ #define NUM_RX_SGE_PAGES 2 #define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge)) -#define MAX_RX_SGE_CNT (RX_SGE_CNT - 2) +#define NEXT_PAGE_SGE_DESC_CNT 2 +#define MAX_RX_SGE_CNT (RX_SGE_CNT - NEXT_PAGE_SGE_DESC_CNT) /* RX_SGE_CNT is promised to be a power of 2 */ #define RX_SGE_MASK (RX_SGE_CNT - 1) #define NUM_RX_SGE (RX_SGE_CNT * NUM_RX_SGE_PAGES) #define MAX_RX_SGE (NUM_RX_SGE - 1) #define NEXT_SGE_IDX(x) ((((x) & RX_SGE_MASK) == \ - (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1) + (MAX_RX_SGE_CNT - 1)) ? \ + (x) + 1 + NEXT_PAGE_SGE_DESC_CNT : \ + (x) + 1) #define RX_SGE(x) ((x) & MAX_RX_SGE) +/* + * Number of required SGEs is the sum of two: + * 1. Number of possible opened aggregations (next packet for + * these aggregations will probably consume SGE immidiatelly) + * 2. Rest of BRB blocks divided by 2 (block will consume new SGE only + * after placement on BD for new TPA aggregation) + * + * Takes into account NEXT_PAGE_SGE_DESC_CNT "next" elements on each page + */ +#define NUM_SGE_REQ (MAX_AGG_QS(bp) + \ + (BRB_SIZE(bp) - MAX_AGG_QS(bp)) / 2) +#define NUM_SGE_PG_REQ ((NUM_SGE_REQ + MAX_RX_SGE_CNT - 1) / \ + MAX_RX_SGE_CNT) +#define SGE_TH_LO(bp) (NUM_SGE_REQ + \ + NUM_SGE_PG_REQ * NEXT_PAGE_SGE_DESC_CNT) +#define SGE_TH_HI(bp) (SGE_TH_LO(bp) + DROPLESS_FC_HEADROOM) + /* Manipulate a bit vector defined as an array of u64 */ /* Number of bits in one sge_mask array element */ @@ -551,24 +579,43 @@ struct bnx2x_fastpath { #define NUM_TX_RINGS 16 #define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types)) -#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) +#define NEXT_PAGE_TX_DESC_CNT 1 +#define MAX_TX_DESC_CNT (TX_DESC_CNT - NEXT_PAGE_TX_DESC_CNT) #define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) #define MAX_TX_BD (NUM_TX_BD - 1) #define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2) #define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \ - (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) + (MAX_TX_DESC_CNT - 1)) ? \ + (x) + 1 + NEXT_PAGE_TX_DESC_CNT : \ + (x) + 1) #define TX_BD(x) ((x) & MAX_TX_BD) #define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT) /* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */ #define NUM_RX_RINGS 8 #define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd)) -#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2) +#define NEXT_PAGE_RX_DESC_CNT 2 +#define MAX_RX_DESC_CNT (RX_DESC_CNT - NEXT_PAGE_RX_DESC_CNT) #define RX_DESC_MASK (RX_DESC_CNT - 1) #define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) #define MAX_RX_BD (NUM_RX_BD - 1) #define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) -#define MIN_RX_AVAIL 128 + +/* dropless fc calculations for BDs + * + * Number of BDs should as number of buffers in BRB: + * Low threshold takes into account NEXT_PAGE_RX_DESC_CNT + * "next" elements on each page + */ +#define NUM_BD_REQ BRB_SIZE(bp) +#define NUM_BD_PG_REQ ((NUM_BD_REQ + MAX_RX_DESC_CNT - 1) / \ + MAX_RX_DESC_CNT) +#define BD_TH_LO(bp) (NUM_BD_REQ + \ + NUM_BD_PG_REQ * NEXT_PAGE_RX_DESC_CNT + \ + FW_DROP_LEVEL(bp)) +#define BD_TH_HI(bp) (BD_TH_LO(bp) + DROPLESS_FC_HEADROOM) + +#define MIN_RX_AVAIL ((bp)->dropless_fc ? BD_TH_HI(bp) + 128 : 128) #define MIN_RX_SIZE_TPA_HW (CHIP_IS_E1(bp) ? \ ETH_MIN_RX_CQES_WITH_TPA_E1 : \ @@ -579,7 +626,9 @@ struct bnx2x_fastpath { MIN_RX_AVAIL)) #define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ - (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1) + (MAX_RX_DESC_CNT - 1)) ? \ + (x) + 1 + NEXT_PAGE_RX_DESC_CNT : \ + (x) + 1) #define RX_BD(x) ((x) & MAX_RX_BD) /* @@ -589,14 +638,31 @@ struct bnx2x_fastpath { #define CQE_BD_REL (sizeof(union eth_rx_cqe) / sizeof(struct eth_rx_bd)) #define NUM_RCQ_RINGS (NUM_RX_RINGS * CQE_BD_REL) #define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe)) -#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1) +#define NEXT_PAGE_RCQ_DESC_CNT 1 +#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - NEXT_PAGE_RCQ_DESC_CNT) #define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS) #define MAX_RCQ_BD (NUM_RCQ_BD - 1) #define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2) #define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \ - (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) + (MAX_RCQ_DESC_CNT - 1)) ? \ + (x) + 1 + NEXT_PAGE_RCQ_DESC_CNT : \ + (x) + 1) #define RCQ_BD(x) ((x) & MAX_RCQ_BD) +/* dropless fc calculations for RCQs + * + * Number of RCQs should be as number of buffers in BRB: + * Low threshold takes into account NEXT_PAGE_RCQ_DESC_CNT + * "next" elements on each page + */ +#define NUM_RCQ_REQ BRB_SIZE(bp) +#define NUM_RCQ_PG_REQ ((NUM_BD_REQ + MAX_RCQ_DESC_CNT - 1) / \ + MAX_RCQ_DESC_CNT) +#define RCQ_TH_LO(bp) (NUM_RCQ_REQ + \ + NUM_RCQ_PG_REQ * NEXT_PAGE_RCQ_DESC_CNT + \ + FW_DROP_LEVEL(bp)) +#define RCQ_TH_HI(bp) (RCQ_TH_LO(bp) + DROPLESS_FC_HEADROOM) + /* This is needed for determining of last_max */ #define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b)) diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 37e5790681a..2a33d2433c3 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -987,8 +987,6 @@ void __bnx2x_link_report(struct bnx2x *bp) void bnx2x_init_rx_rings(struct bnx2x *bp) { int func = BP_FUNC(bp); - int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : - ETH_MAX_AGGREGATION_QUEUES_E1H_E2; u16 ring_prod; int i, j; @@ -1001,7 +999,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) if (!fp->disable_tpa) { /* Fill the per-aggregtion pool */ - for (i = 0; i < max_agg_queues; i++) { + for (i = 0; i < MAX_AGG_QS(bp); i++) { struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i]; struct sw_rx_bd *first_buf = @@ -1041,7 +1039,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp) bnx2x_free_rx_sge_range(bp, fp, ring_prod); bnx2x_free_tpa_pool(bp, fp, - max_agg_queues); + MAX_AGG_QS(bp)); fp->disable_tpa = 1; ring_prod = 0; break; @@ -1137,9 +1135,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) bnx2x_free_rx_bds(fp); if (!fp->disable_tpa) - bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ? - ETH_MAX_AGGREGATION_QUEUES_E1 : - ETH_MAX_AGGREGATION_QUEUES_E1H_E2); + bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp)); } } diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index f74582a22c6..3f93e866610 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -2756,8 +2756,14 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp, u16 tpa_agg_size = 0; if (!fp->disable_tpa) { - pause->sge_th_hi = 250; - pause->sge_th_lo = 150; + pause->sge_th_lo = SGE_TH_LO(bp); + pause->sge_th_hi = SGE_TH_HI(bp); + + /* validate SGE ring has enough to cross high threshold */ + WARN_ON(bp->dropless_fc && + pause->sge_th_hi + FW_PREFETCH_CNT > + MAX_RX_SGE_CNT * NUM_RX_SGE_PAGES); + tpa_agg_size = min_t(u32, (min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff); @@ -2771,10 +2777,21 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp, /* pause - not for e1 */ if (!CHIP_IS_E1(bp)) { - pause->bd_th_hi = 350; - pause->bd_th_lo = 250; - pause->rcq_th_hi = 350; - pause->rcq_th_lo = 250; + pause->bd_th_lo = BD_TH_LO(bp); + pause->bd_th_hi = BD_TH_HI(bp); + + pause->rcq_th_lo = RCQ_TH_LO(bp); + pause->rcq_th_hi = RCQ_TH_HI(bp); + /* + * validate that rings have enough entries to cross + * high thresholds + */ + WARN_ON(bp->dropless_fc && + pause->bd_th_hi + FW_PREFETCH_CNT > + bp->rx_ring_size); + WARN_ON(bp->dropless_fc && + pause->rcq_th_hi + FW_PREFETCH_CNT > + NUM_RCQ_RINGS * MAX_RCQ_DESC_CNT); pause->pri_map = 1; } @@ -2802,9 +2819,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp, * For PF Clients it should be the maximum avaliable number. * VF driver(s) may want to define it to a smaller value. */ - rxq_init->max_tpa_queues = - (CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : - ETH_MAX_AGGREGATION_QUEUES_E1H_E2); + rxq_init->max_tpa_queues = MAX_AGG_QS(bp); rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT; rxq_init->fw_sb_id = fp->fw_sb_id; -- cgit v1.2.3-70-g09d2 From 5f837363457a2280530373267f86092625d15a4d Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:40 +0000 Subject: bnx2x: decrease print level to debug It may happen every link toggle. Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_stats.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c index 771f6803b23..f5d9b4213ca 100644 --- a/drivers/net/bnx2x/bnx2x_stats.c +++ b/drivers/net/bnx2x/bnx2x_stats.c @@ -710,7 +710,8 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp) break; case MAC_TYPE_NONE: /* unreached */ - BNX2X_ERR("stats updated by DMAE but no MAC active\n"); + DP(BNX2X_MSG_STATS, + "stats updated by DMAE but no MAC active\n"); return -1; default: /* unreached */ -- cgit v1.2.3-70-g09d2 From c2188952fc7d2ca54bb8aca1bc502618a7488baf Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Tue, 30 Aug 2011 00:08:41 +0000 Subject: bnx2x: fix rx ring size report Store the size in bp, read from bp when queried. Signed-off-by: Dmitry Kravkov Signed-off-by: Vladislav Zolotarov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_cmn.c | 17 +++++++++++------ drivers/net/bnx2x/bnx2x_ethtool.c | 5 +---- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 2a33d2433c3..c4cbf973641 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -3091,15 +3091,20 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) struct bnx2x_fastpath *fp = &bp->fp[index]; int ring_size = 0; u8 cos; + int rx_ring_size = 0; /* if rx_ring_size specified - use it */ - int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : - MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp); + if (!bp->rx_ring_size) { - /* allocate at least number of buffers required by FW */ - rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA : - MIN_RX_SIZE_TPA, - rx_ring_size); + rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp); + + /* allocate at least number of buffers required by FW */ + rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA, rx_ring_size); + + bp->rx_ring_size = rx_ring_size; + } else + rx_ring_size = bp->rx_ring_size; /* Common */ sb = &bnx2x_fp(bp, index, status_blk); diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 221863059da..0ceb6c7b123 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -1310,10 +1310,7 @@ static void bnx2x_get_ringparam(struct net_device *dev, if (bp->rx_ring_size) ering->rx_pending = bp->rx_ring_size; else - if (bp->state == BNX2X_STATE_OPEN && bp->num_queues) - ering->rx_pending = MAX_RX_AVAIL/bp->num_queues; - else - ering->rx_pending = MAX_RX_AVAIL; + ering->rx_pending = MAX_RX_AVAIL; ering->rx_mini_pending = 0; ering->rx_jumbo_pending = 0; -- cgit v1.2.3-70-g09d2 From 3395a033a7c2f1a089fae7e89bf108764b59529c Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:42 +0000 Subject: bnx2x: fix MF for 4-port devices Number of VNs for 4-port devices is 2 instead of 4 Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x.h | 15 +++++++------- drivers/net/bnx2x/bnx2x_main.c | 43 +++++++++++++++++++++++++---------------- drivers/net/bnx2x/bnx2x_stats.c | 4 ++-- 3 files changed, 36 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 85297326506..2621a1c5635 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1166,11 +1166,12 @@ struct bnx2x { #define BP_PORT(bp) (bp->pfid & 1) #define BP_FUNC(bp) (bp->pfid) #define BP_ABS_FUNC(bp) (bp->pf_num) -#define BP_E1HVN(bp) (bp->pfid >> 1) -#define BP_VN(bp) (BP_E1HVN(bp)) /*remove when approved*/ -#define BP_L_ID(bp) (BP_E1HVN(bp) << 2) -#define BP_FW_MB_IDX(bp) (BP_PORT(bp) +\ - BP_VN(bp) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1)) +#define BP_VN(bp) ((bp)->pfid >> 1) +#define BP_MAX_VN_NUM(bp) (CHIP_MODE_IS_4_PORT(bp) ? 2 : 4) +#define BP_L_ID(bp) (BP_VN(bp) << 2) +#define BP_FW_MB_IDX_VN(bp, vn) (BP_PORT(bp) +\ + (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1)) +#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp)) struct net_device *dev; struct pci_dev *pdev; @@ -1833,7 +1834,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, #define MAX_DMAE_C_PER_PORT 8 #define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ - BP_E1HVN(bp)) + BP_VN(bp)) #define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ E1HVN_MAX) @@ -1859,7 +1860,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, /* must be used on a CID before placing it on a HW ring */ #define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \ - (BP_E1HVN(bp) << BNX2X_SWCID_SHIFT) | \ + (BP_VN(bp) << BNX2X_SWCID_SHIFT) | \ (x)) #define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 3f93e866610..9633e9b6853 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -407,8 +407,8 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type, opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET); opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0); - opcode |= ((BP_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT) | - (BP_E1HVN(bp) << DMAE_COMMAND_DST_VN_SHIFT)); + opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) | + (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT)); opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT); #ifdef __BIG_ENDIAN @@ -1419,7 +1419,7 @@ static void bnx2x_hc_int_enable(struct bnx2x *bp) if (!CHIP_IS_E1(bp)) { /* init leading/trailing edge */ if (IS_MF(bp)) { - val = (0xee0f | (1 << (BP_E1HVN(bp) + 4))); + val = (0xee0f | (1 << (BP_VN(bp) + 4))); if (bp->port.pmf) /* enable nig and gpio3 attention */ val |= 0x1100; @@ -1471,7 +1471,7 @@ static void bnx2x_igu_int_enable(struct bnx2x *bp) /* init leading/trailing edge */ if (IS_MF(bp)) { - val = (0xee0f | (1 << (BP_E1HVN(bp) + 4))); + val = (0xee0f | (1 << (BP_VN(bp) + 4))); if (bp->port.pmf) /* enable nig and gpio3 attention */ val |= 0x1100; @@ -2287,7 +2287,7 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) int vn; bp->vn_weight_sum = 0; - for (vn = VN_0; vn < E1HVN_MAX; vn++) { + for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) { u32 vn_cfg = bp->mf_config[vn]; u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> FUNC_MF_CFG_MIN_BW_SHIFT) * 100; @@ -2320,12 +2320,18 @@ static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) CMNG_FLAGS_PER_PORT_FAIRNESS_VN; } +/* returns func by VN for current port */ +static inline int func_by_vn(struct bnx2x *bp, int vn) +{ + return 2 * vn + BP_PORT(bp); +} + static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn) { struct rate_shaping_vars_per_vn m_rs_vn; struct fairness_vars_per_vn m_fair_vn; u32 vn_cfg = bp->mf_config[vn]; - int func = 2*vn + BP_PORT(bp); + int func = func_by_vn(bp, vn); u16 vn_min_rate, vn_max_rate; int i; @@ -2422,7 +2428,7 @@ void bnx2x_read_mf_cfg(struct bnx2x *bp) * * and there are 2 functions per port */ - for (vn = VN_0; vn < E1HVN_MAX; vn++) { + for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) { int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp); if (func >= E1H_FUNC_MAX) @@ -2454,7 +2460,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type) /* calculate and set min-max rate for each vn */ if (bp->port.pmf) - for (vn = VN_0; vn < E1HVN_MAX; vn++) + for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) bnx2x_init_vn_minmax(bp, vn); /* always enable rate shaping and fairness */ @@ -2473,16 +2479,15 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type) static inline void bnx2x_link_sync_notify(struct bnx2x *bp) { - int port = BP_PORT(bp); int func; int vn; /* Set the attention towards other drivers on the same port */ - for (vn = VN_0; vn < E1HVN_MAX; vn++) { - if (vn == BP_E1HVN(bp)) + for (vn = VN_0; vn < BP_MAX_VN_NUM(bp); vn++) { + if (vn == BP_VN(bp)) continue; - func = ((vn << 1) | port); + func = func_by_vn(bp, vn); REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); } @@ -2577,7 +2582,7 @@ static void bnx2x_pmf_update(struct bnx2x *bp) bnx2x_dcbx_pmf_update(bp); /* enable nig attention */ - val = (0xff0f | (1 << (BP_E1HVN(bp) + 4))); + val = (0xff0f | (1 << (BP_VN(bp) + 4))); if (bp->common.int_block == INT_BLOCK_HC) { REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); @@ -6686,12 +6691,16 @@ static int bnx2x_init_hw_func(struct bnx2x *bp) if (CHIP_MODE_IS_4_PORT(bp)) dsb_idx = BP_FUNC(bp); else - dsb_idx = BP_E1HVN(bp); + dsb_idx = BP_VN(bp); prod_offset = (CHIP_INT_MODE_IS_BC(bp) ? IGU_BC_BASE_DSB_PROD + dsb_idx : IGU_NORM_BASE_DSB_PROD + dsb_idx); + /* + * igu prods come in chunks of E1HVN_MAX (4) - + * does not matters what is the current chip mode + */ for (i = 0; i < (num_segs * E1HVN_MAX); i += E1HVN_MAX) { addr = IGU_REG_PROD_CONS_MEMORY + @@ -7585,7 +7594,7 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode) u32 val; /* The mac address is written to entries 1-4 to preserve entry 0 which is used by the PMF */ - u8 entry = (BP_E1HVN(bp) + 1)*8; + u8 entry = (BP_VN(bp) + 1)*8; val = (mac_addr[0] << 8) | mac_addr[1]; EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val); @@ -8792,13 +8801,13 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp) { int pfid = BP_FUNC(bp); - int vn = BP_E1HVN(bp); int igu_sb_id; u32 val; u8 fid, igu_sb_cnt = 0; bp->igu_base_sb = 0xff; if (CHIP_INT_MODE_IS_BC(bp)) { + int vn = BP_VN(bp); igu_sb_cnt = bp->igu_sb_cnt; bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) * FP_SB_MAX_E1x; @@ -9488,7 +9497,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_ov = 0; bp->mf_mode = 0; - vn = BP_E1HVN(bp); + vn = BP_VN(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n", diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c index f5d9b4213ca..9908f2bbcf7 100644 --- a/drivers/net/bnx2x/bnx2x_stats.c +++ b/drivers/net/bnx2x/bnx2x_stats.c @@ -1392,7 +1392,7 @@ static void bnx2x_port_stats_base_init(struct bnx2x *bp) static void bnx2x_func_stats_base_init(struct bnx2x *bp) { - int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX; + int vn, vn_max = IS_MF(bp) ? BP_MAX_VN_NUM(bp) : E1VN_MAX; u32 func_stx; /* sanity */ @@ -1405,7 +1405,7 @@ static void bnx2x_func_stats_base_init(struct bnx2x *bp) func_stx = bp->func_stx; for (vn = VN_0; vn < vn_max; vn++) { - int mb_idx = CHIP_IS_E1x(bp) ? 2*vn + BP_PORT(bp) : vn; + int mb_idx = BP_FW_MB_IDX_VN(bp, vn); bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param); bnx2x_func_stats_init(bp); -- cgit v1.2.3-70-g09d2 From 7a06a122322c89544774e789a11aa671423e9362 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:43 +0000 Subject: bnx2x: don't reset device while reading its configuration. Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 24 +++++++++++++++--------- drivers/net/bnx2x/bnx2x_reg.h | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 9633e9b6853..00dc8f0fc3a 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -5822,7 +5822,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp) * take the UNDI lock to protect undi_unload flow from accessing * registers while we're resetting the chip */ - bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET); bnx2x_reset_common(bp); REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); @@ -5834,7 +5834,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp) } REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val); - bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET); bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON); @@ -8570,10 +8570,12 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp) /* Check if there is any driver already loaded */ val = REG_RD(bp, MISC_REG_UNPREPARED); if (val == 0x1) { - /* Check if it is the UNDI driver + + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET); + /* + * Check if it is the UNDI driver * UNDI driver initializes CID offset for normal bell to 0x7 */ - bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); if (val == 0x7) { u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; @@ -8611,9 +8613,6 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp) bnx2x_fw_command(bp, reset_code, 0); } - /* now it's safe to release the lock */ - bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); - bnx2x_undi_int_disable(bp); port = BP_PORT(bp); @@ -8663,8 +8662,10 @@ static void __devinit bnx2x_undi_unload(struct bnx2x *bp) bp->fw_seq = (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & DRV_MSG_SEQ_NUMBER_MASK); - } else - bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + } + + /* now it's safe to release the lock */ + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET); } } @@ -9440,6 +9441,10 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bp->igu_base_sb = 0; } else { bp->common.int_block = INT_BLOCK_IGU; + + /* do not allow device reset during IGU info preocessing */ + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET); + val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION); if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) { @@ -9471,6 +9476,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) bnx2x_get_igu_cam_info(bp); + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RESET); } /* diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 40266c14e6d..dac217d478f 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -5766,7 +5766,7 @@ #define HW_LOCK_RESOURCE_RECOVERY_LEADER_0 8 #define HW_LOCK_RESOURCE_RECOVERY_LEADER_1 9 #define HW_LOCK_RESOURCE_SPIO 2 -#define HW_LOCK_RESOURCE_UNDI 5 +#define HW_LOCK_RESOURCE_RESET 5 #define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT (0x1<<4) #define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR (0x1<<5) #define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (0x1<<18) -- cgit v1.2.3-70-g09d2 From 0735f2fc8c49f1fbbbb245d038582922984ed3d5 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:44 +0000 Subject: bnx2x: init fw_seq after undi_unload is done Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 00dc8f0fc3a..94382a78c95 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -9623,13 +9623,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) /* port info */ bnx2x_get_port_hwinfo(bp); - if (!BP_NOMCP(bp)) { - bp->fw_seq = - (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & - DRV_MSG_SEQ_NUMBER_MASK); - BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); - } - /* Get MAC addresses */ bnx2x_get_mac_hwinfo(bp); @@ -9795,6 +9788,14 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp) if (!BP_NOMCP(bp)) bnx2x_undi_unload(bp); + /* init fw_seq after undi_unload! */ + if (!BP_NOMCP(bp)) { + bp->fw_seq = + (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } + if (CHIP_REV_IS_FPGA(bp)) dev_err(&bp->pdev->dev, "FPGA detected\n"); -- cgit v1.2.3-70-g09d2 From a5c53dbcde9a156e8303acc6ecb2296bf609fe38 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Tue, 30 Aug 2011 00:08:45 +0000 Subject: bnx2x: don't access removed registers on 57712 and above Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 94382a78c95..0b68d02fe45 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -10290,17 +10290,21 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, /* clean indirect addresses */ pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, PCICFG_VENDOR_ID_OFFSET); - /* Clean the following indirect addresses for all functions since it + /* + * Clean the following indirect addresses for all functions since it * is not used by the driver. */ REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0); - REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0); - REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0); - REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0); - REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0); + + if (CHIP_IS_E1x(bp)) { + REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0); + } /* * Enable internal target-read (in case we are probed after PF FLR). -- cgit v1.2.3-70-g09d2 From 150966ad56291776a1f3fed86000a027e0794922 Mon Sep 17 00:00:00 2001 From: Ariel Elior Date: Tue, 30 Aug 2011 00:08:46 +0000 Subject: bnx2x: Fix for a host coalescing bug which impared latency. Seperated Rx and Tx coalescing to different state machines. Signed-off-by: Ariel Elior Signed-off-by: Eilon Greenstein Signed-off-by: Dmitry Kravkov Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x.h | 25 +++++++++---------------- drivers/net/bnx2x/bnx2x_main.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 2621a1c5635..e46df5331c5 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -751,24 +751,17 @@ struct bnx2x_fastpath { #define FP_CSB_FUNC_OFF \ offsetof(struct cstorm_status_block_c, func) -#define HC_INDEX_TOE_RX_CQ_CONS 0 /* Formerly Ustorm TOE CQ index */ - /* (HC_INDEX_U_TOE_RX_CQ_CONS) */ -#define HC_INDEX_ETH_RX_CQ_CONS 1 /* Formerly Ustorm ETH CQ index */ - /* (HC_INDEX_U_ETH_RX_CQ_CONS) */ -#define HC_INDEX_ETH_RX_BD_CONS 2 /* Formerly Ustorm ETH BD index */ - /* (HC_INDEX_U_ETH_RX_BD_CONS) */ - -#define HC_INDEX_TOE_TX_CQ_CONS 4 /* Formerly Cstorm TOE CQ index */ - /* (HC_INDEX_C_TOE_TX_CQ_CONS) */ -#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5 /* Formerly Cstorm ETH CQ index */ - /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ -#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6 /* Formerly Cstorm ETH CQ index */ - /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ -#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7 /* Formerly Cstorm ETH CQ index */ - /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ +#define HC_INDEX_ETH_RX_CQ_CONS 1 -#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0 +#define HC_INDEX_OOO_TX_CQ_CONS 4 + +#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5 + +#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6 +#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7 + +#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0 #define BNX2X_RX_SB_INDEX \ (&fp->sb_index_values[HC_INDEX_ETH_RX_CQ_CONS]) diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 0b68d02fe45..c027e9341a1 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4828,6 +4828,37 @@ void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm, hc_sm->time_to_expire = 0xFFFFFFFF; } + +/* allocates state machine ids. */ +static inline +void bnx2x_map_sb_state_machines(struct hc_index_data *index_data) +{ + /* zero out state machine indices */ + /* rx indices */ + index_data[HC_INDEX_ETH_RX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID; + + /* tx indices */ + index_data[HC_INDEX_OOO_TX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags &= ~HC_INDEX_DATA_SM_ID; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags &= ~HC_INDEX_DATA_SM_ID; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags &= ~HC_INDEX_DATA_SM_ID; + + /* map indices */ + /* rx indices */ + index_data[HC_INDEX_ETH_RX_CQ_CONS].flags |= + SM_RX_ID << HC_INDEX_DATA_SM_ID_SHIFT; + + /* tx indices */ + index_data[HC_INDEX_OOO_TX_CQ_CONS].flags |= + SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags |= + SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags |= + SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT; + index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags |= + SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT; +} + static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, u8 vf_valid, int fw_sb_id, int igu_sb_id) { @@ -4859,6 +4890,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, hc_sm_p = sb_data_e2.common.state_machine; sb_data_p = (u32 *)&sb_data_e2; data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); + bnx2x_map_sb_state_machines(sb_data_e2.index_data); } else { memset(&sb_data_e1x, 0, sizeof(struct hc_status_block_data_e1x)); @@ -4873,6 +4905,7 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, hc_sm_p = sb_data_e1x.common.state_machine; sb_data_p = (u32 *)&sb_data_e1x; data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); + bnx2x_map_sb_state_machines(sb_data_e1x.index_data); } bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID], -- cgit v1.2.3-70-g09d2 From 02009afc223aae43b8e18918fc816e4520791537 Mon Sep 17 00:00:00 2001 From: Kavan Smith Date: Wed, 31 Aug 2011 05:12:05 +0000 Subject: ipheth: iPhone 4 Verizon CDMA USB Product ID add Add USB product ID for iPhone 4 CDMA Verizon Tested on at least 2 devices Signed-off-by: Kavan Smith Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 15772b1b6a9..13c1f044b40 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,6 +59,7 @@ #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 +#define USB_PRODUCT_IPHONE_4_VZW 0x129c #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -98,6 +99,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); -- cgit v1.2.3-70-g09d2 From c482e6c064613b3fd40758ef6c33318462b83789 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:47:49 +0000 Subject: bnx2x: Fix ETS bandwidth ETS bandwidth of 0% is not allowed by driver, so provide alternative HW configuration for this case. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index d45b1555a60..9d381db1651 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -778,9 +778,9 @@ static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp, { u32 nig_reg_adress_crd_weight = 0; u32 pbf_reg_adress_crd_weight = 0; - /* Calculate and set BW for this COS*/ - const u32 cos_bw_nig = (bw * min_w_val_nig) / total_bw; - const u32 cos_bw_pbf = (bw * min_w_val_pbf) / total_bw; + /* Calculate and set BW for this COS - use 1 instead of 0 for BW */ + const u32 cos_bw_nig = ((bw ? bw : 1) * min_w_val_nig) / total_bw; + const u32 cos_bw_pbf = ((bw ? bw : 1) * min_w_val_pbf) / total_bw; switch (cos_entry) { case 0: @@ -852,18 +852,12 @@ static int bnx2x_ets_e3b0_get_total_bw( /* Calculate total BW requested */ for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) { if (bnx2x_cos_state_bw == ets_params->cos[cos_idx].state) { - - if (0 == ets_params->cos[cos_idx].params.bw_params.bw) { - DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW" - "was set to 0\n"); - return -EINVAL; + *total_bw += + ets_params->cos[cos_idx].params.bw_params.bw; } - *total_bw += - ets_params->cos[cos_idx].params.bw_params.bw; - } } - /*Check taotl BW is valid */ + /* Check total BW is valid */ if ((100 != *total_bw) || (0 == *total_bw)) { if (0 == *total_bw) { DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW" -- cgit v1.2.3-70-g09d2 From 6b1f3900fc0909fbf3bd672242378015f76b3df8 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:47:54 +0000 Subject: bnx2x: Enable FEC for 57810-KR Enable FEC(Forward Error Correction) for 57810-KR to reduce link errors. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 6 ++++++ drivers/net/bnx2x/bnx2x_reg.h | 3 +++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 9d381db1651..f7a7ac3e889 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -3624,6 +3624,12 @@ static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16); + /* Advertised and set FEC (Forward Error Correction) */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2, + (MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY | + MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ)); + /* Enable CL37 BAM */ if (REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index dac217d478f..057738623ba 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -6853,6 +6853,9 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_WC_REG_IEEE0BLK_AUTONEGNP 0x7 #define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT0 0x10 #define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1 0x11 +#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT2 0x12 +#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_ABILITY 0x4000 +#define MDIO_WC_REG_AN_IEEE1BLK_AN_ADV2_FEC_REQ 0x8000 #define MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150 0x96 #define MDIO_WC_REG_XGXSBLK0_XGXSCONTROL 0x8000 #define MDIO_WC_REG_XGXSBLK0_MISCCONTROL1 0x800e -- cgit v1.2.3-70-g09d2 From 0582242049c67d59c3a95cd1cba8995fa955c858 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:47:58 +0000 Subject: bnx2x: Remove fiber remote fault detection Remove remote fault detection as a tactic retreat due to link issues involved with it. Once issue is resolved, this feature will be restored again. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index f7a7ac3e889..db5913da552 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -10638,8 +10638,7 @@ static struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_HW_LOCK_REQUIRED, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10765,8 +10764,7 @@ static struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_INIT_XGXS_FIRST | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_INIT_XGXS_FIRST, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10797,8 +10795,7 @@ static struct bnx2x_phy phy_8726 = { .addr = 0xff, .def_md_devad = 0, .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_INIT_XGXS_FIRST | - FLAGS_TX_ERROR_CHECK), + FLAGS_INIT_XGXS_FIRST), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10829,8 +10826,7 @@ static struct bnx2x_phy phy_8727 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, .addr = 0xff, .def_md_devad = 0, - .flags = (FLAGS_FAN_FAILURE_DET_REQ | - FLAGS_TX_ERROR_CHECK), + .flags = FLAGS_FAN_FAILURE_DET_REQ, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, -- cgit v1.2.3-70-g09d2 From 4d7e25d6cc4312b1f949123fea7026fd56441513 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:48:03 +0000 Subject: bnx2x: Fix XMAC loopback test Change XMAC loopback type from CORE LOCAL to LINE LOCAL for the BCM578xx due to intermittent problem with the loopback with this configuration. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 2 +- drivers/net/bnx2x/bnx2x_reg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index db5913da552..342807585c2 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -1720,7 +1720,7 @@ static int bnx2x_xmac_enable(struct link_params *params, /* Check loopback mode */ if (lb) - val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK; + val |= XMAC_CTRL_REG_LINE_LOCAL_LPBK; REG_WR(bp, xmac_base + XMAC_REG_CTRL, val); bnx2x_set_xumac_nig(params, ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1); diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 057738623ba..750e8445dac 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -5320,7 +5320,7 @@ #define XCM_REG_XX_OVFL_EVNT_ID 0x20058 #define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS (0x1<<0) #define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS (0x1<<1) -#define XMAC_CTRL_REG_CORE_LOCAL_LPBK (0x1<<3) +#define XMAC_CTRL_REG_LINE_LOCAL_LPBK (0x1<<2) #define XMAC_CTRL_REG_RX_EN (0x1<<1) #define XMAC_CTRL_REG_SOFT_RESET (0x1<<6) #define XMAC_CTRL_REG_TX_EN (0x1<<0) -- cgit v1.2.3-70-g09d2 From ab505dec96340946079d1288f49041bea9f259ff Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:48:06 +0000 Subject: bnx2x: Fix 578xx link LED Fix 1G link LED for the BCM578xx-SFI/KR. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_link.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 342807585c2..ba15bdc5a1a 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -5924,7 +5924,7 @@ int bnx2x_set_led(struct link_params *params, (tmp | EMAC_LED_OVERRIDE)); /* * return here without enabling traffic - * LED blink andsetting rate in ON mode. + * LED blink and setting rate in ON mode. * In oper mode, enabling LED blink * and setting rate is needed. */ @@ -5936,7 +5936,11 @@ int bnx2x_set_led(struct link_params *params, * This is a work-around for HW issue found when link * is up in CL73 */ - REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); + if ((!CHIP_IS_E3(bp)) || + (CHIP_IS_E3(bp) && + mode == LED_MODE_ON)) + REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); + if (CHIP_IS_E1x(bp) || CHIP_IS_E2(bp) || (mode == LED_MODE_ON)) -- cgit v1.2.3-70-g09d2 From 8d661637407963d1990e53c36d53ace123219da3 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 7 Sep 2011 00:48:11 +0000 Subject: bnx2x: Fix ethtool advertisement Enable changing advertisement settings via ethtool. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Reviewed-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_ethtool.c | 43 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 0ceb6c7b123..cf3e47914dd 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -363,13 +363,50 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) } /* advertise the requested speed and duplex if supported */ - cmd->advertising &= bp->port.supported[cfg_idx]; + if (cmd->advertising & ~(bp->port.supported[cfg_idx])) { + DP(NETIF_MSG_LINK, "Advertisement parameters " + "are not supported\n"); + return -EINVAL; + } bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG; - bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL; - bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg | + bp->link_params.req_duplex[cfg_idx] = cmd->duplex; + bp->port.advertising[cfg_idx] = (ADVERTISED_Autoneg | cmd->advertising); + if (cmd->advertising) { + + bp->link_params.speed_cap_mask[cfg_idx] = 0; + if (cmd->advertising & ADVERTISED_10baseT_Half) { + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF; + } + if (cmd->advertising & ADVERTISED_10baseT_Full) + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL; + if (cmd->advertising & ADVERTISED_100baseT_Full) + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL; + + if (cmd->advertising & ADVERTISED_100baseT_Half) { + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF; + } + if (cmd->advertising & ADVERTISED_1000baseT_Half) { + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G; + } + if (cmd->advertising & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseKX_Full)) + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G; + + if (cmd->advertising & (ADVERTISED_10000baseT_Full | + ADVERTISED_10000baseKX4_Full | + ADVERTISED_10000baseKR_Full)) + bp->link_params.speed_cap_mask[cfg_idx] |= + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G; + } } else { /* forced speed */ /* advertise the requested speed and duplex if supported */ switch (speed) { -- cgit v1.2.3-70-g09d2 From 86c432ca5d6da90a26ac8d3e680f2268b502d9c5 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 1 Sep 2011 12:09:29 +0000 Subject: Revert "sfc: Use write-combining to reduce TX latency" and follow-ups This reverts commits 65f0b417dee94f779ce9b77102b7d73c93723b39, d88d6b05fee3cc78e5b0273eb58c31201dcc6b76, fcfa060468a4edcf776f0c1211d826d5de1668c1, 747df2258b1b9a2e25929ef496262c339c380009 and 867955f5682f7157fdafe8670804b9f8ea077bc7. Depending on the processor model, write-combining may result in reordering that the NIC will not tolerate. This typically results in a DMA error event and reset by the driver, logged as: sfc 0000:0e:00.0: eth2: TX DMA Q reports TX_EV_PKT_ERR. sfc 0000:0e:00.0: eth2: resetting (ALL) Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/efx.c | 18 ++--------------- drivers/net/sfc/io.h | 15 ++++---------- drivers/net/sfc/mcdi.c | 46 ++++++++++++++++--------------------------- drivers/net/sfc/nic.c | 7 ------- drivers/net/sfc/nic.h | 2 -- drivers/net/sfc/siena.c | 25 ++++------------------- drivers/net/sfc/workarounds.h | 2 -- 7 files changed, 27 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index faca764aa21..b59abc706d9 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1050,7 +1050,6 @@ static int efx_init_io(struct efx_nic *efx) { struct pci_dev *pci_dev = efx->pci_dev; dma_addr_t dma_mask = efx->type->max_dma_mask; - bool use_wc; int rc; netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); @@ -1101,21 +1100,8 @@ static int efx_init_io(struct efx_nic *efx) rc = -EIO; goto fail3; } - - /* bug22643: If SR-IOV is enabled then tx push over a write combined - * mapping is unsafe. We need to disable write combining in this case. - * MSI is unsupported when SR-IOV is enabled, and the firmware will - * have removed the MSI capability. So write combining is safe if - * there is an MSI capability. - */ - use_wc = (!EFX_WORKAROUND_22643(efx) || - pci_find_capability(pci_dev, PCI_CAP_ID_MSI)); - if (use_wc) - efx->membase = ioremap_wc(efx->membase_phys, - efx->type->mem_map_size); - else - efx->membase = ioremap_nocache(efx->membase_phys, - efx->type->mem_map_size); + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); if (!efx->membase) { netif_err(efx, probe, efx->net_dev, "could not map memory BAR at %llx+%x\n", diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index cc978803d48..dc45110b245 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -48,9 +48,9 @@ * replacing the low 96 bits with zero does not affect functionality. * - If the host writes to the last dword address of such a register * (i.e. the high 32 bits) the underlying register will always be - * written. If the collector and the current write together do not - * provide values for all 128 bits of the register, the low 96 bits - * will be written as zero. + * written. If the collector does not hold values for the low 96 + * bits of the register, they will be written as zero. Writing to + * the last qword does not have this effect and must not be done. * - If the host writes to the address of any other part of such a * register while the collector already holds values for some other * register, the write is discarded and the collector maintains its @@ -103,7 +103,6 @@ static inline void efx_writeo(struct efx_nic *efx, efx_oword_t *value, _efx_writed(efx, value->u32[2], reg + 8); _efx_writed(efx, value->u32[3], reg + 12); #endif - wmb(); mmiowb(); spin_unlock_irqrestore(&efx->biu_lock, flags); } @@ -126,7 +125,6 @@ static inline void efx_sram_writeq(struct efx_nic *efx, void __iomem *membase, __raw_writel((__force u32)value->u32[0], membase + addr); __raw_writel((__force u32)value->u32[1], membase + addr + 4); #endif - wmb(); mmiowb(); spin_unlock_irqrestore(&efx->biu_lock, flags); } @@ -141,7 +139,6 @@ static inline void efx_writed(struct efx_nic *efx, efx_dword_t *value, /* No lock required */ _efx_writed(efx, value->u32[0], reg); - wmb(); } /* Read a 128-bit CSR, locking as appropriate. */ @@ -152,7 +149,6 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, spin_lock_irqsave(&efx->biu_lock, flags); value->u32[0] = _efx_readd(efx, reg + 0); - rmb(); value->u32[1] = _efx_readd(efx, reg + 4); value->u32[2] = _efx_readd(efx, reg + 8); value->u32[3] = _efx_readd(efx, reg + 12); @@ -175,7 +171,6 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, value->u64[0] = (__force __le64)__raw_readq(membase + addr); #else value->u32[0] = (__force __le32)__raw_readl(membase + addr); - rmb(); value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); #endif spin_unlock_irqrestore(&efx->biu_lock, flags); @@ -242,14 +237,12 @@ static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value, #ifdef EFX_USE_QWORD_IO _efx_writeq(efx, value->u64[0], reg + 0); - _efx_writeq(efx, value->u64[1], reg + 8); #else _efx_writed(efx, value->u32[0], reg + 0); _efx_writed(efx, value->u32[1], reg + 4); +#endif _efx_writed(efx, value->u32[2], reg + 8); _efx_writed(efx, value->u32[3], reg + 12); -#endif - wmb(); } #define efx_writeo_page(efx, value, reg, page) \ _efx_writeo_page(efx, value, \ diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 3dd45ed61f0..81a42539746 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -50,20 +50,6 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) return &nic_data->mcdi; } -static inline void -efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg) -{ - struct siena_nic_data *nic_data = efx->nic_data; - value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg); -} - -static inline void -efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg) -{ - struct siena_nic_data *nic_data = efx->nic_data; - __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg); -} - void efx_mcdi_init(struct efx_nic *efx) { struct efx_mcdi_iface *mcdi; @@ -84,8 +70,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, size_t inlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned pdu = MCDI_PDU(efx); - unsigned doorbell = MCDI_DOORBELL(efx); + unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); unsigned int i; efx_dword_t hdr; u32 xflags, seqno; @@ -106,28 +92,29 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, MCDI_HEADER_SEQ, seqno, MCDI_HEADER_XFLAGS, xflags); - efx_mcdi_writed(efx, &hdr, pdu); + efx_writed(efx, &hdr, pdu); for (i = 0; i < inlen; i += 4) - efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i), - pdu + 4 + i); + _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); + + /* Ensure the payload is written out before the header */ + wmb(); /* ring the doorbell with a distinctive value */ - EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc); - efx_mcdi_writed(efx, &hdr, doorbell); + _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); } static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned int pdu = MCDI_PDU(efx); + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); int i; BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); BUG_ON(outlen & 3 || outlen >= 0x100); for (i = 0; i < outlen; i += 4) - efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i); + *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); } static int efx_mcdi_poll(struct efx_nic *efx) @@ -135,7 +122,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsigned int time, finish; unsigned int respseq, respcmd, error; - unsigned int pdu = MCDI_PDU(efx); + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); unsigned int rc, spins; efx_dword_t reg; @@ -161,7 +148,8 @@ static int efx_mcdi_poll(struct efx_nic *efx) time = get_seconds(); - efx_mcdi_readd(efx, ®, pdu); + rmb(); + efx_readd(efx, ®, pdu); /* All 1's indicates that shared memory is in reset (and is * not a valid header). Wait for it to come out reset before @@ -188,7 +176,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) respseq, mcdi->seqno); rc = EIO; } else if (error) { - efx_mcdi_readd(efx, ®, pdu + 4); + efx_readd(efx, ®, pdu + 4); switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { #define TRANSLATE_ERROR(name) \ case MC_CMD_ERR_ ## name: \ @@ -222,21 +210,21 @@ out: /* Test and clear MC-rebooted flag for this port/function */ int efx_mcdi_poll_reboot(struct efx_nic *efx) { - unsigned int addr = MCDI_REBOOT_FLAG(efx); + unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); efx_dword_t reg; uint32_t value; if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) return false; - efx_mcdi_readd(efx, ®, addr); + efx_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); - efx_mcdi_writed(efx, ®, addr); + efx_writed(efx, ®, addr); if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index bafa23a6874..3edfbaf5f02 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1936,13 +1936,6 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) size = min_t(size_t, table->step, 16); - if (table->offset >= efx->type->mem_map_size) { - /* No longer mapped; return dummy data */ - memcpy(buf, "\xde\xc0\xad\xde", 4); - buf += table->rows * size; - continue; - } - for (i = 0; i < table->rows; i++) { switch (table->step) { case 4: /* 32-bit register or SRAM */ diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index 4bd1f2839df..7443f99c977 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -143,12 +143,10 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) /** * struct siena_nic_data - Siena NIC state * @mcdi: Management-Controller-to-Driver Interface - * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable. * @wol_filter_id: Wake-on-LAN packet filter id */ struct siena_nic_data { struct efx_mcdi_iface mcdi; - void __iomem *mcdi_smem; int wol_filter_id; }; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 5735e84c69d..2c3bd93fab5 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -250,26 +250,12 @@ static int siena_probe_nic(struct efx_nic *efx) efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; - /* Initialise MCDI */ - nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys + - FR_CZ_MC_TREG_SMEM, - FR_CZ_MC_TREG_SMEM_STEP * - FR_CZ_MC_TREG_SMEM_ROWS); - if (!nic_data->mcdi_smem) { - netif_err(efx, probe, efx->net_dev, - "could not map MCDI at %llx+%x\n", - (unsigned long long)efx->membase_phys + - FR_CZ_MC_TREG_SMEM, - FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS); - rc = -ENOMEM; - goto fail1; - } efx_mcdi_init(efx); /* Recover from a failed assertion before probing */ rc = efx_mcdi_handle_assertion(efx); if (rc) - goto fail2; + goto fail1; /* Let the BMC know that the driver is now in charge of link and * filter settings. We must do this before we reset the NIC */ @@ -324,7 +310,6 @@ fail4: fail3: efx_mcdi_drv_attach(efx, false, NULL); fail2: - iounmap(nic_data->mcdi_smem); fail1: kfree(efx->nic_data); return rc; @@ -404,8 +389,6 @@ static int siena_init_nic(struct efx_nic *efx) static void siena_remove_nic(struct efx_nic *efx) { - struct siena_nic_data *nic_data = efx->nic_data; - efx_nic_free_buffer(efx, &efx->irq_status); siena_reset_hw(efx, RESET_TYPE_ALL); @@ -415,8 +398,7 @@ static void siena_remove_nic(struct efx_nic *efx) efx_mcdi_drv_attach(efx, false, NULL); /* Tear down the private nic state */ - iounmap(nic_data->mcdi_smem); - kfree(nic_data); + kfree(efx->nic_data); efx->nic_data = NULL; } @@ -656,7 +638,8 @@ const struct efx_nic_type siena_a0_nic_type = { .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, - .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */ + .mem_map_size = (FR_CZ_MC_TREG_SMEM + + FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, .buf_tbl_base = FR_BZ_BUF_FULL_TBL, diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 99ff11400ce..e4dd3a7f304 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -38,8 +38,6 @@ #define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS /* Legacy interrupt storm when interrupt fifo fills */ #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA -/* Write combining and sriov=enabled are incompatible */ -#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA /* Spurious parity errors in TSORT buffers */ #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A -- cgit v1.2.3-70-g09d2 From 483f97f8b2b7f0ab09e14c06fe327d5e346fac28 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 1 Sep 2011 12:09:59 +0000 Subject: sfc: Use 64-bit writes for TX push where possible This was originally done as part of commit 65f0b417dee94f779ce9b77102b7d73c93723b39 ("sfc: Use write-combining to reduce TX latency"), but that had to be reverted. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/io.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index dc45110b245..751d1ec112c 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -48,9 +48,9 @@ * replacing the low 96 bits with zero does not affect functionality. * - If the host writes to the last dword address of such a register * (i.e. the high 32 bits) the underlying register will always be - * written. If the collector does not hold values for the low 96 - * bits of the register, they will be written as zero. Writing to - * the last qword does not have this effect and must not be done. + * written. If the collector and the current write together do not + * provide values for all 128 bits of the register, the low 96 bits + * will be written as zero. * - If the host writes to the address of any other part of such a * register while the collector already holds values for some other * register, the write is discarded and the collector maintains its @@ -237,12 +237,13 @@ static inline void _efx_writeo_page(struct efx_nic *efx, efx_oword_t *value, #ifdef EFX_USE_QWORD_IO _efx_writeq(efx, value->u64[0], reg + 0); + _efx_writeq(efx, value->u64[1], reg + 8); #else _efx_writed(efx, value->u32[0], reg + 0); _efx_writed(efx, value->u32[1], reg + 4); -#endif _efx_writed(efx, value->u32[2], reg + 8); _efx_writed(efx, value->u32[3], reg + 12); +#endif } #define efx_writeo_page(efx, value, reg, page) \ _efx_writeo_page(efx, value, \ -- cgit v1.2.3-70-g09d2 From 5229d87edcd80a3bceb0708ebd767faff2e589a9 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Thu, 1 Sep 2011 14:20:07 +0000 Subject: pch_gbe: fixed the issue which receives an unnecessary packet. This patch fixed the issue which receives an unnecessary packet before link When using PHY of GMII, an unnecessary packet is received, And it becomes impossible to receive a packet after link up. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index eac3c5ca973..48ff87c455a 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -717,13 +717,6 @@ static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter) iowrite32(rdba, &hw->reg->RX_DSC_BASE); iowrite32(rdlen, &hw->reg->RX_DSC_SIZE); iowrite32((rdba + rdlen), &hw->reg->RX_DSC_SW_P); - - /* Enables Receive DMA */ - rxdma = ioread32(&hw->reg->DMA_CTRL); - rxdma |= PCH_GBE_RX_DMA_EN; - iowrite32(rxdma, &hw->reg->DMA_CTRL); - /* Enables Receive */ - iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN); } /** @@ -1097,6 +1090,19 @@ void pch_gbe_update_stats(struct pch_gbe_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } +static void pch_gbe_start_receive(struct pch_gbe_hw *hw) +{ + u32 rxdma; + + /* Enables Receive DMA */ + rxdma = ioread32(&hw->reg->DMA_CTRL); + rxdma |= PCH_GBE_RX_DMA_EN; + iowrite32(rxdma, &hw->reg->DMA_CTRL); + /* Enables Receive */ + iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN); + return; +} + /** * pch_gbe_intr - Interrupt Handler * @irq: Interrupt number @@ -1717,6 +1723,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) pch_gbe_alloc_tx_buffers(adapter, tx_ring); pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count); adapter->tx_queue_len = netdev->tx_queue_len; + pch_gbe_start_receive(&adapter->hw); mod_timer(&adapter->watchdog_timer, jiffies); -- cgit v1.2.3-70-g09d2 From 124d770a6459be21b84445f6ebf7dbfb60d43585 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Thu, 1 Sep 2011 14:20:08 +0000 Subject: pch_gbe: added the process of FIFO over run error This patch added the processing which should be done to hardware, when a FIFO over run error occurred. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe.h | 12 +- drivers/net/pch_gbe/pch_gbe_main.c | 271 +++++++++++++++++++++++-------------- 2 files changed, 179 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h index 59fac77d0db..a09a07197eb 100644 --- a/drivers/net/pch_gbe/pch_gbe.h +++ b/drivers/net/pch_gbe/pch_gbe.h @@ -127,8 +127,8 @@ struct pch_gbe_regs { /* Reset */ #define PCH_GBE_ALL_RST 0x80000000 /* All reset */ -#define PCH_GBE_TX_RST 0x40000000 /* TX MAC, TX FIFO, TX DMA reset */ -#define PCH_GBE_RX_RST 0x04000000 /* RX MAC, RX FIFO, RX DMA reset */ +#define PCH_GBE_TX_RST 0x00008000 /* TX MAC, TX FIFO, TX DMA reset */ +#define PCH_GBE_RX_RST 0x00004000 /* RX MAC, RX FIFO, RX DMA reset */ /* TCP/IP Accelerator Control */ #define PCH_GBE_EX_LIST_EN 0x00000008 /* External List Enable */ @@ -276,6 +276,9 @@ struct pch_gbe_regs { #define PCH_GBE_RX_DMA_EN 0x00000002 /* Enables Receive DMA */ #define PCH_GBE_TX_DMA_EN 0x00000001 /* Enables Transmission DMA */ +/* RX DMA STATUS */ +#define PCH_GBE_IDLE_CHECK 0xFFFFFFFE + /* Wake On LAN Status */ #define PCH_GBE_WLS_BR 0x00000008 /* Broadcas Address */ #define PCH_GBE_WLS_MLT 0x00000004 /* Multicast Address */ @@ -471,6 +474,7 @@ struct pch_gbe_tx_desc { struct pch_gbe_buffer { struct sk_buff *skb; dma_addr_t dma; + unsigned char *rx_buffer; unsigned long time_stamp; u16 length; bool mapped; @@ -511,6 +515,9 @@ struct pch_gbe_tx_ring { struct pch_gbe_rx_ring { struct pch_gbe_rx_desc *desc; dma_addr_t dma; + unsigned char *rx_buff_pool; + dma_addr_t rx_buff_pool_logic; + unsigned int rx_buff_pool_size; unsigned int size; unsigned int count; unsigned int next_to_use; @@ -622,6 +629,7 @@ struct pch_gbe_adapter { unsigned long rx_buffer_len; unsigned long tx_queue_len; bool have_msi; + bool rx_stop_flag; }; extern const char pch_driver_version[]; diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 48ff87c455a..39ce0ee44ad 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -20,7 +20,6 @@ #include "pch_gbe.h" #include "pch_gbe_api.h" -#include #define DRV_VERSION "1.00" const char pch_driver_version[] = DRV_VERSION; @@ -34,6 +33,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */ #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 +#define PCH_GBE_RESERVE_MEMORY 0x200000 /* 2MB */ /* Macros for ML7223 */ #define PCI_VENDOR_ID_ROHM 0x10db @@ -52,6 +52,7 @@ const char pch_driver_version[] = DRV_VERSION; ) /* Ethertype field values */ +#define PCH_GBE_MAX_RX_BUFFER_SIZE 0x2880 #define PCH_GBE_MAX_JUMBO_FRAME_SIZE 10318 #define PCH_GBE_FRAME_SIZE_2048 2048 #define PCH_GBE_FRAME_SIZE_4096 4096 @@ -83,10 +84,12 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_INT_ENABLE_MASK ( \ PCH_GBE_INT_RX_DMA_CMPLT | \ PCH_GBE_INT_RX_DSC_EMP | \ + PCH_GBE_INT_RX_FIFO_ERR | \ PCH_GBE_INT_WOL_DET | \ PCH_GBE_INT_TX_CMPLT \ ) +#define PCH_GBE_INT_DISABLE_ALL 0 static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; @@ -138,6 +141,27 @@ static void pch_gbe_wait_clr_bit(void *reg, u32 bit) if (!tmp) pr_err("Error: busy bit is not cleared\n"); } + +/** + * pch_gbe_wait_clr_bit_irq - Wait to clear a bit for interrupt context + * @reg: Pointer of register + * @busy: Busy bit + */ +static int pch_gbe_wait_clr_bit_irq(void *reg, u32 bit) +{ + u32 tmp; + int ret = -1; + /* wait busy */ + tmp = 20; + while ((ioread32(reg) & bit) && --tmp) + udelay(5); + if (!tmp) + pr_err("Error: busy bit is not cleared\n"); + else + ret = 0; + return ret; +} + /** * pch_gbe_mac_mar_set - Set MAC address register * @hw: Pointer to the HW structure @@ -189,6 +213,17 @@ static void pch_gbe_mac_reset_hw(struct pch_gbe_hw *hw) return; } +static void pch_gbe_mac_reset_rx(struct pch_gbe_hw *hw) +{ + /* Read the MAC address. and store to the private data */ + pch_gbe_mac_read_mac_addr(hw); + iowrite32(PCH_GBE_RX_RST, &hw->reg->RESET); + pch_gbe_wait_clr_bit_irq(&hw->reg->RESET, PCH_GBE_RX_RST); + /* Setup the MAC address */ + pch_gbe_mac_mar_set(hw, hw->mac.addr, 0); + return; +} + /** * pch_gbe_mac_init_rx_addrs - Initialize receive address's * @hw: Pointer to the HW structure @@ -671,13 +706,8 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter) tcpip = ioread32(&hw->reg->TCPIP_ACC); - if (netdev->features & NETIF_F_RXCSUM) { - tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF; - tcpip |= PCH_GBE_RX_TCPIPACC_EN; - } else { - tcpip |= PCH_GBE_RX_TCPIPACC_OFF; - tcpip &= ~PCH_GBE_RX_TCPIPACC_EN; - } + tcpip |= PCH_GBE_RX_TCPIPACC_OFF; + tcpip &= ~PCH_GBE_RX_TCPIPACC_EN; iowrite32(tcpip, &hw->reg->TCPIP_ACC); return; } @@ -1090,6 +1120,35 @@ void pch_gbe_update_stats(struct pch_gbe_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } +static void pch_gbe_stop_receive(struct pch_gbe_adapter *adapter) +{ + struct pch_gbe_hw *hw = &adapter->hw; + u32 rxdma; + u16 value; + int ret; + + /* Disable Receive DMA */ + rxdma = ioread32(&hw->reg->DMA_CTRL); + rxdma &= ~PCH_GBE_RX_DMA_EN; + iowrite32(rxdma, &hw->reg->DMA_CTRL); + /* Wait Rx DMA BUS is IDLE */ + ret = pch_gbe_wait_clr_bit_irq(&hw->reg->RX_DMA_ST, PCH_GBE_IDLE_CHECK); + if (ret) { + /* Disable Bus master */ + pci_read_config_word(adapter->pdev, PCI_COMMAND, &value); + value &= ~PCI_COMMAND_MASTER; + pci_write_config_word(adapter->pdev, PCI_COMMAND, value); + /* Stop Receive */ + pch_gbe_mac_reset_rx(hw); + /* Enable Bus master */ + value |= PCI_COMMAND_MASTER; + pci_write_config_word(adapter->pdev, PCI_COMMAND, value); + } else { + /* Stop Receive */ + pch_gbe_mac_reset_rx(hw); + } +} + static void pch_gbe_start_receive(struct pch_gbe_hw *hw) { u32 rxdma; @@ -1129,7 +1188,15 @@ static irqreturn_t pch_gbe_intr(int irq, void *data) if (int_st & PCH_GBE_INT_RX_FRAME_ERR) adapter->stats.intr_rx_frame_err_count++; if (int_st & PCH_GBE_INT_RX_FIFO_ERR) - adapter->stats.intr_rx_fifo_err_count++; + if (!adapter->rx_stop_flag) { + adapter->stats.intr_rx_fifo_err_count++; + pr_debug("Rx fifo over run\n"); + adapter->rx_stop_flag = true; + int_en = ioread32(&hw->reg->INT_EN); + iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR), + &hw->reg->INT_EN); + pch_gbe_stop_receive(adapter); + } if (int_st & PCH_GBE_INT_RX_DMA_ERR) adapter->stats.intr_rx_dma_err_count++; if (int_st & PCH_GBE_INT_TX_FIFO_ERR) @@ -1141,7 +1208,7 @@ static irqreturn_t pch_gbe_intr(int irq, void *data) /* When Rx descriptor is empty */ if ((int_st & PCH_GBE_INT_RX_DSC_EMP)) { adapter->stats.intr_rx_dsc_empty_count++; - pr_err("Rx descriptor is empty\n"); + pr_debug("Rx descriptor is empty\n"); int_en = ioread32(&hw->reg->INT_EN); iowrite32((int_en & ~PCH_GBE_INT_RX_DSC_EMP), &hw->reg->INT_EN); if (hw->mac.tx_fc_enable) { @@ -1191,29 +1258,23 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter, unsigned int i; unsigned int bufsz; - bufsz = adapter->rx_buffer_len + PCH_GBE_DMA_ALIGN; + bufsz = adapter->rx_buffer_len + NET_IP_ALIGN; i = rx_ring->next_to_use; while ((cleaned_count--)) { buffer_info = &rx_ring->buffer_info[i]; - skb = buffer_info->skb; - if (skb) { - skb_trim(skb, 0); - } else { - skb = netdev_alloc_skb(netdev, bufsz); - if (unlikely(!skb)) { - /* Better luck next round */ - adapter->stats.rx_alloc_buff_failed++; - break; - } - /* 64byte align */ - skb_reserve(skb, PCH_GBE_DMA_ALIGN); - - buffer_info->skb = skb; - buffer_info->length = adapter->rx_buffer_len; + skb = netdev_alloc_skb(netdev, bufsz); + if (unlikely(!skb)) { + /* Better luck next round */ + adapter->stats.rx_alloc_buff_failed++; + break; } + /* align */ + skb_reserve(skb, NET_IP_ALIGN); + buffer_info->skb = skb; + buffer_info->dma = dma_map_single(&pdev->dev, - skb->data, + buffer_info->rx_buffer, buffer_info->length, DMA_FROM_DEVICE); if (dma_mapping_error(&adapter->pdev->dev, buffer_info->dma)) { @@ -1246,6 +1307,36 @@ pch_gbe_alloc_rx_buffers(struct pch_gbe_adapter *adapter, return; } +static int +pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter, + struct pch_gbe_rx_ring *rx_ring, int cleaned_count) +{ + struct pci_dev *pdev = adapter->pdev; + struct pch_gbe_buffer *buffer_info; + unsigned int i; + unsigned int bufsz; + unsigned int size; + + bufsz = adapter->rx_buffer_len; + + size = rx_ring->count * bufsz + PCH_GBE_RESERVE_MEMORY; + rx_ring->rx_buff_pool = dma_alloc_coherent(&pdev->dev, size, + &rx_ring->rx_buff_pool_logic, + GFP_KERNEL); + if (!rx_ring->rx_buff_pool) { + pr_err("Unable to allocate memory for the receive poll buffer\n"); + return -ENOMEM; + } + memset(rx_ring->rx_buff_pool, 0, size); + rx_ring->rx_buff_pool_size = size; + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + buffer_info->rx_buffer = rx_ring->rx_buff_pool + bufsz * i; + buffer_info->length = bufsz; + } + return 0; +} + /** * pch_gbe_alloc_tx_buffers - Allocate transmit buffers * @adapter: Board private structure @@ -1386,7 +1477,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, unsigned int i; unsigned int cleaned_count = 0; bool cleaned = false; - struct sk_buff *skb, *new_skb; + struct sk_buff *skb; u8 dma_status; u16 gbec_status; u32 tcp_ip_status; @@ -1407,13 +1498,12 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, rx_desc->gbec_status = DSC_INIT16; buffer_info = &rx_ring->buffer_info[i]; skb = buffer_info->skb; + buffer_info->skb = NULL; /* unmap dma */ dma_unmap_single(&pdev->dev, buffer_info->dma, buffer_info->length, DMA_FROM_DEVICE); buffer_info->mapped = false; - /* Prefetch the packet */ - prefetch(skb->data); pr_debug("RxDecNo = 0x%04x Status[DMA:0x%02x GBE:0x%04x " "TCP:0x%08x] BufInf = 0x%p\n", @@ -1433,70 +1523,16 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, pr_err("Receive CRC Error\n"); } else { /* get receive length */ - /* length convert[-3] */ - length = (rx_desc->rx_words_eob) - 3; - - /* Decide the data conversion method */ - if (!(netdev->features & NETIF_F_RXCSUM)) { - /* [Header:14][payload] */ - if (NET_IP_ALIGN) { - /* Because alignment differs, - * the new_skb is newly allocated, - * and data is copied to new_skb.*/ - new_skb = netdev_alloc_skb(netdev, - length + NET_IP_ALIGN); - if (!new_skb) { - /* dorrop error */ - pr_err("New skb allocation " - "Error\n"); - goto dorrop; - } - skb_reserve(new_skb, NET_IP_ALIGN); - memcpy(new_skb->data, skb->data, - length); - skb = new_skb; - } else { - /* DMA buffer is used as SKB as it is.*/ - buffer_info->skb = NULL; - } - } else { - /* [Header:14][padding:2][payload] */ - /* The length includes padding length */ - length = length - PCH_GBE_DMA_PADDING; - if ((length < copybreak) || - (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) { - /* Because alignment differs, - * the new_skb is newly allocated, - * and data is copied to new_skb. - * Padding data is deleted - * at the time of a copy.*/ - new_skb = netdev_alloc_skb(netdev, - length + NET_IP_ALIGN); - if (!new_skb) { - /* dorrop error */ - pr_err("New skb allocation " - "Error\n"); - goto dorrop; - } - skb_reserve(new_skb, NET_IP_ALIGN); - memcpy(new_skb->data, skb->data, - ETH_HLEN); - memcpy(&new_skb->data[ETH_HLEN], - &skb->data[ETH_HLEN + - PCH_GBE_DMA_PADDING], - length - ETH_HLEN); - skb = new_skb; - } else { - /* Padding data is deleted - * by moving header data.*/ - memmove(&skb->data[PCH_GBE_DMA_PADDING], - &skb->data[0], ETH_HLEN); - skb_reserve(skb, NET_IP_ALIGN); - buffer_info->skb = NULL; - } - } - /* The length includes FCS length */ - length = length - ETH_FCS_LEN; + /* length convert[-3], length includes FCS length */ + length = (rx_desc->rx_words_eob) - 3 - ETH_FCS_LEN; + if (rx_desc->rx_words_eob & 0x02) + length = length - 4; + /* + * buffer_info->rx_buffer: [Header:14][payload] + * skb->data: [Reserve:2][Header:14][payload] + */ + memcpy(skb->data, buffer_info->rx_buffer, length); + /* update status of driver */ adapter->stats.rx_bytes += length; adapter->stats.rx_packets++; @@ -1515,7 +1551,6 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, pr_debug("Receive skb->ip_summed: %d length: %d\n", skb->ip_summed, length); } -dorrop: /* return some buffers to hardware, one at a time is too slow */ if (unlikely(cleaned_count >= PCH_GBE_RX_BUFFER_WRITE)) { pch_gbe_alloc_rx_buffers(adapter, rx_ring, @@ -1720,6 +1755,11 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) pr_err("Error: can't bring device up\n"); return err; } + err = pch_gbe_alloc_rx_buffers_pool(adapter, rx_ring, rx_ring->count); + if (err) { + pr_err("Error: can't bring device up\n"); + return err; + } pch_gbe_alloc_tx_buffers(adapter, tx_ring); pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count); adapter->tx_queue_len = netdev->tx_queue_len; @@ -1741,6 +1781,7 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) void pch_gbe_down(struct pch_gbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; + struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring; /* signal that we're down so the interrupt handler does not * reschedule our watchdog timer */ @@ -1759,6 +1800,12 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter) pch_gbe_reset(adapter); pch_gbe_clean_tx_ring(adapter, adapter->tx_ring); pch_gbe_clean_rx_ring(adapter, adapter->rx_ring); + + pci_free_consistent(adapter->pdev, rx_ring->rx_buff_pool_size, + rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic); + rx_ring->rx_buff_pool_logic = 0; + rx_ring->rx_buff_pool_size = 0; + rx_ring->rx_buff_pool = NULL; } /** @@ -2011,6 +2058,8 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu) { struct pch_gbe_adapter *adapter = netdev_priv(netdev); int max_frame; + unsigned long old_rx_buffer_len = adapter->rx_buffer_len; + int err; max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || @@ -2025,14 +2074,24 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu) else if (max_frame <= PCH_GBE_FRAME_SIZE_8192) adapter->rx_buffer_len = PCH_GBE_FRAME_SIZE_8192; else - adapter->rx_buffer_len = PCH_GBE_MAX_JUMBO_FRAME_SIZE; - netdev->mtu = new_mtu; - adapter->hw.mac.max_frame_size = max_frame; + adapter->rx_buffer_len = PCH_GBE_MAX_RX_BUFFER_SIZE; - if (netif_running(netdev)) - pch_gbe_reinit_locked(adapter); - else + if (netif_running(netdev)) { + pch_gbe_down(adapter); + err = pch_gbe_up(adapter); + if (err) { + adapter->rx_buffer_len = old_rx_buffer_len; + pch_gbe_up(adapter); + return -ENOMEM; + } else { + netdev->mtu = new_mtu; + adapter->hw.mac.max_frame_size = max_frame; + } + } else { pch_gbe_reset(adapter); + netdev->mtu = new_mtu; + adapter->hw.mac.max_frame_size = max_frame; + } pr_debug("max_frame : %d rx_buffer_len : %d mtu : %d max_frame_size : %d\n", max_frame, (u32) adapter->rx_buffer_len, netdev->mtu, @@ -2110,6 +2169,7 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) int work_done = 0; bool poll_end_flag = false; bool cleaned = false; + u32 int_en; pr_debug("budget : %d\n", budget); @@ -2117,8 +2177,15 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) if (!netif_carrier_ok(netdev)) { poll_end_flag = true; } else { - cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget); + if (adapter->rx_stop_flag) { + adapter->rx_stop_flag = false; + pch_gbe_start_receive(&adapter->hw); + int_en = ioread32(&adapter->hw.reg->INT_EN); + iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR), + &adapter->hw.reg->INT_EN); + } + cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); if (cleaned) work_done = budget; -- cgit v1.2.3-70-g09d2 From 7756332f5b64c9c1535712b9679792e8bd4f0019 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Thu, 1 Sep 2011 14:20:09 +0000 Subject: pch_gbe: support ML7831 IOH Support new device OKI SEMICONDUCTOR ML7831 IOH(Input/Output Hub) ML7831 is for general purpose use. ML7831 is companion chip for Intel Atom E6xx series. ML7831 is completely compatible for Intel EG20T PCH. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/Kconfig | 11 ++++++----- drivers/net/pch_gbe/pch_gbe_main.c | 10 ++++++++++ 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8d0314dbd94..a44874e24f2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2535,7 +2535,7 @@ config S6GMAC source "drivers/net/stmmac/Kconfig" config PCH_GBE - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE" + tristate "Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE" depends on PCI select MII ---help--- @@ -2548,10 +2548,11 @@ config PCH_GBE This driver enables Gigabit Ethernet function. This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7223. - ML7223 IOH is for MP(Media Phone) use. - ML7223 is companion chip for Intel Atom E6xx series. - ML7223 is completely compatible for Intel EG20T PCH. + Output Hub), ML7223/ML7831. + ML7223 IOH is for MP(Media Phone) use. ML7831 IOH is for general + purpose use. + ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7223/ML7831 is completely compatible for Intel EG20T PCH. config FTGMAC100 tristate "Faraday FTGMAC100 Gigabit Ethernet support" diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 39ce0ee44ad..567ff10889b 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -39,6 +39,9 @@ const char pch_driver_version[] = DRV_VERSION; #define PCI_VENDOR_ID_ROHM 0x10db #define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013 +/* Macros for ML7831 */ +#define PCI_DEVICE_ID_ROHM_ML7831_GBE 0x8802 + #define PCH_GBE_TX_WEIGHT 64 #define PCH_GBE_RX_WEIGHT 64 #define PCH_GBE_RX_BUFFER_WRITE 16 @@ -2526,6 +2529,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = (0xFFFF00) }, + {.vendor = PCI_VENDOR_ID_ROHM, + .device = PCI_DEVICE_ID_ROHM_ML7831_GBE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_NETWORK_ETHERNET << 8), + .class_mask = (0xFFFF00) + }, /* required last entry */ {0} }; -- cgit v1.2.3-70-g09d2 From 4cc122ac913dbd662403a4a173c41e0d59ab5bdd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 15 Sep 2011 17:21:15 -0300 Subject: spi/imx: Fix spi-imx when the hardware SPI chipselects are used commit 22a85e4cd51 (spi/imx: add device tree probe support) broke spi-imx usage when the SPI chipselect is the one internal to the controller. On a mx31pdk board the following error is seen: Registering mxc_nand as whole device ------------[ cut here ]------------ WARNING: at drivers/gpio/gpiolib.c:101 gpio_ensure_requested+0x4c/0xf4() autorequest GPIO-0 Modules linked in: [] (unwind_backtrace+0x0/0xf4) from [] (warn_slowpath_common+0x4c/0x64) [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_fmt+0x30/0x40) [] (warn_slowpath_fmt+0x30/0x40) from [] (gpio_ensure_requested+0x4c/0xf4) [] (gpio_ensure_requested+0x4c/0xf4) from [] (gpio_direction_output+0xa0/0x138) [] (gpio_direction_output+0xa0/0x138) from [] (spi_imx_setup+0x38/0x4c) [] (spi_imx_setup+0x38/0x4c) from [] (spi_setup+0x38/0x50) [] (spi_setup+0x38/0x50) from [] (spi_add_device+0x94/0x124) [] (spi_add_device+0x94/0x124) from [] (spi_new_device+0x74/0xac) [] (spi_new_device+0x74/0xac) from [] (spi_match_master_to_boardinfo+0x20/0x40) [] (spi_match_master_to_boardinfo+0x20/0x40) from [] (spi_register_master+0xb0/0x104) [] (spi_register_master+0xb0/0x104) from [] (spi_bitbang_start+0x104/0x17c) [] (spi_bitbang_start+0x104/0x17c) from [] (spi_imx_probe+0x2fc/0x404) [] (spi_imx_probe+0x2fc/0x404) from [] (platform_drv_probe+0x18/0x1c) [] (platform_drv_probe+0x18/0x1c) from [] (driver_probe_device+0x78/0x174) [] (driver_probe_device+0x78/0x174) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x60/0x8c) [] (bus_for_each_dev+0x60/0x8c) from [] (bus_add_driver+0xa0/0x288) [] (bus_add_driver+0xa0/0x288) from [] (driver_register+0x78/0x18c) [] (driver_register+0x78/0x18c) from [] (do_one_initcall+0x34/0x178) [] (do_one_initcall+0x34/0x178) from [] (kernel_init+0x74/0x118) [] (kernel_init+0x74/0x118) from [] (kernel_thread_exit+0x0/0x8) ---[ end trace 759f924b30fd5a44 ]--- Fix this issue by using the original chip select logic and make spi-imx to work again. Tested on a mx31pdk that uses the hardware SPI chipselect pins and also on a mx27pdk that uses GPIO as SPI chipselect. Signed-off-by: Fabio Estevam Signed-off-by: Grant Likely --- drivers/spi/spi-imx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 8ac6542aedc..fa594d604ac 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -786,9 +786,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); if (cs_gpio < 0) cs_gpio = mxc_platform_info->chipselect[i]; + + spi_imx->chipselect[i] = cs_gpio; if (cs_gpio < 0) continue; - spi_imx->chipselect[i] = cs_gpio; + ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); if (ret) { while (i > 0) { -- cgit v1.2.3-70-g09d2 From bcac364a24c894c4cf8cf219b7863c192cd34079 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Sat, 27 Aug 2011 21:33:16 -0700 Subject: target: Fix race between multiple invocations of target_qf_do_work() When work is scheduled with schedule_work(), the work can end up running on multiple CPUs at the same time -- this happens if the work is already running on one CPU and schedule_work() is called on another CPU. This leads to list corruption with target_qf_do_work(), which is roughly doing: spin_lock(...); list_for_each_entry_safe(...) { list_del(...); spin_unlock(...); // do stuff spin_lock(...); } With multiple CPUs running this code, one CPU can end up deleting the list entry that the other CPU is about to work on. Fix this by splicing the list entries onto a local list and then operating on that in the work function. This way, each invocation of target_qf_do_work() operates on its own local list and so multiple invocations don't corrupt each other's list. This also avoids dropping and reacquiring the lock for each list entry. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 8d0c58ea631..a4b0a8d27f2 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -977,15 +977,17 @@ static void target_qf_do_work(struct work_struct *work) { struct se_device *dev = container_of(work, struct se_device, qf_work_queue); + LIST_HEAD(qf_cmd_list); struct se_cmd *cmd, *cmd_tmp; spin_lock_irq(&dev->qf_cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &dev->qf_cmd_list, se_qf_node) { + list_splice_init(&dev->qf_cmd_list, &qf_cmd_list); + spin_unlock_irq(&dev->qf_cmd_lock); + list_for_each_entry_safe(cmd, cmd_tmp, &qf_cmd_list, se_qf_node) { list_del(&cmd->se_qf_node); atomic_dec(&dev->dev_qf_count); smp_mb__after_atomic_dec(); - spin_unlock_irq(&dev->qf_cmd_lock); pr_debug("Processing %s cmd: %p QUEUE_FULL in work queue" " context: %s\n", cmd->se_tfo->get_fabric_name(), cmd, @@ -997,10 +999,7 @@ static void target_qf_do_work(struct work_struct *work) * has been added to head of queue */ transport_add_cmd_to_queue(cmd, cmd->t_state); - - spin_lock_irq(&dev->qf_cmd_lock); } - spin_unlock_irq(&dev->qf_cmd_lock); } unsigned char *transport_dump_cmd_direction(struct se_cmd *cmd) -- cgit v1.2.3-70-g09d2 From 079587b4eb4d3b78a4d65d142f662aa9d7eedab4 Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Fri, 26 Aug 2011 09:25:25 -0700 Subject: tcm_fc: Invalidation of DDP context for FCoE target in error conditions Problem: HW DDP context wasn;t invalidated in case of ABORTS, etc... This leads to the problem where memory pages which are used for DDP as user descriptor could get reused for some other purpose (such as to satisfy new memory allocation request either by kernel or user mode threads) and since HW DDP context was not invalidated, HW continue to write to those pages, hence causing memory corruption. Fix: Either on incoming ABORTS or due to exchange time out, allowed the target to cleanup HW DDP context if it was setup for respective ft_cmd. Added new function to perform this cleanup, furthur it can be enhanced for other cleanup activity. Additinal Notes: To avoid calling ddp_done from multiple places, composed the functionality in helper function "ft_invl_hw_context" and it is being called from multiple places. Cleaned up code in function "ft_recv_write_data" w.r.t DDP. Signed-off-by: Kiran Patil Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tfc_io.c | 62 ++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index c37f4cd9645..d35ea5a3d56 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c @@ -219,43 +219,41 @@ void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) if (cmd->was_ddp_setup) { BUG_ON(!ep); BUG_ON(!lport); - } - - /* - * Doesn't expect payload if DDP is setup. Payload - * is expected to be copied directly to user buffers - * due to DDP (Large Rx offload), - */ - buf = fc_frame_payload_get(fp, 1); - if (buf) - pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " + /* + * Since DDP (Large Rx offload) was setup for this request, + * payload is expected to be copied directly to user buffers. + */ + buf = fc_frame_payload_get(fp, 1); + if (buf) + pr_err("%s: xid 0x%x, f_ctl 0x%x, cmd->sg %p, " "cmd->sg_cnt 0x%x. DDP was setup" " hence not expected to receive frame with " - "payload, Frame will be dropped if " - "'Sequence Initiative' bit in f_ctl is " + "payload, Frame will be dropped if" + "'Sequence Initiative' bit in f_ctl is" "not set\n", __func__, ep->xid, f_ctl, cmd->sg, cmd->sg_cnt); - /* - * Invalidate HW DDP context if it was setup for respective - * command. Invalidation of HW DDP context is requited in both - * situation (success and error). - */ - ft_invl_hw_context(cmd); + /* + * Invalidate HW DDP context if it was setup for respective + * command. Invalidation of HW DDP context is requited in both + * situation (success and error). + */ + ft_invl_hw_context(cmd); - /* - * If "Sequence Initiative (TSI)" bit set in f_ctl, means last - * write data frame is received successfully where payload is - * posted directly to user buffer and only the last frame's - * header is posted in receive queue. - * - * If "Sequence Initiative (TSI)" bit is not set, means error - * condition w.r.t. DDP, hence drop the packet and let explict - * ABORTS from other end of exchange timer trigger the recovery. - */ - if (f_ctl & FC_FC_SEQ_INIT) - goto last_frame; - else - goto drop; + /* + * If "Sequence Initiative (TSI)" bit set in f_ctl, means last + * write data frame is received successfully where payload is + * posted directly to user buffer and only the last frame's + * header is posted in receive queue. + * + * If "Sequence Initiative (TSI)" bit is not set, means error + * condition w.r.t. DDP, hence drop the packet and let explict + * ABORTS from other end of exchange timer trigger the recovery. + */ + if (f_ctl & FC_FC_SEQ_INIT) + goto last_frame; + else + goto drop; + } rel_off = ntohl(fh->fh_parm_offset); frame_len = fr_len(fp); -- cgit v1.2.3-70-g09d2 From 58fc73d10f3e92bfcd1e9a8391eb3e49b68df8e5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 26 Aug 2011 09:25:38 -0700 Subject: tcm_fc: Work queue based approach instead of managing own thread and event based mechanism Problem: Changed from wake_up_interruptible -> wake_up_process and wait_event_interruptible-> schedule_timeout_interruptible broke the FCoE target. Earlier approach of wake_up_interruptible was also looking at 'queue_cnt' which is not necessary, because it increment of 'queue_cnt' with wake_up_inetrriptible / waker_up_process introduces race condition. Fix: Instead of fixing the code which used wake_up_process and remove 'queue_cnt', using work_queue based approach is cleaner and acheives same result. As well, work queue based approach has less programming overhead and OS manages threads which processes work queues. This patch is developed by Christoph Hellwig and reviwed+validated by Kiran Patil. Signed-off-by: Christoph Hellwig Signed-off-by: Kiran Patil Signed-off-by: Nicholas Bellinger --- drivers/target/tcm_fc/tcm_fc.h | 12 +----- drivers/target/tcm_fc/tfc_cmd.c | 90 +++++----------------------------------- drivers/target/tcm_fc/tfc_conf.c | 7 ++-- 3 files changed, 16 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index bd4fe21a23b..3749d8b4b42 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -98,8 +98,7 @@ struct ft_tpg { struct list_head list; /* linkage in ft_lport_acl tpg_list */ struct list_head lun_list; /* head of LUNs */ struct se_portal_group se_tpg; - struct task_struct *thread; /* processing thread */ - struct se_queue_obj qobj; /* queue for processing thread */ + struct workqueue_struct *workqueue; }; struct ft_lport_acl { @@ -110,16 +109,10 @@ struct ft_lport_acl { struct se_wwn fc_lport_wwn; }; -enum ft_cmd_state { - FC_CMD_ST_NEW = 0, - FC_CMD_ST_REJ -}; - /* * Commands */ struct ft_cmd { - enum ft_cmd_state state; u32 lun; /* LUN from request */ struct ft_sess *sess; /* session held for cmd */ struct fc_seq *seq; /* sequence in exchange mgr */ @@ -127,7 +120,7 @@ struct ft_cmd { struct fc_frame *req_frame; unsigned char *cdb; /* pointer to CDB inside frame */ u32 write_data_len; /* data received on writes */ - struct se_queue_req se_req; + struct work_struct work; /* Local sense buffer */ unsigned char ft_sense_buffer[TRANSPORT_SENSE_BUFFER]; u32 was_ddp_setup:1; /* Set only if ddp is setup */ @@ -177,7 +170,6 @@ int ft_is_state_remove(struct se_cmd *); /* * other internal functions. */ -int ft_thread(void *); void ft_recv_req(struct ft_sess *, struct fc_frame *); struct ft_tpg *ft_lport_find_tpg(struct fc_lport *); struct ft_node_acl *ft_acl_get(struct ft_tpg *, struct fc_rport_priv *); diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 5654dc22f7a..80fbcde00cb 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -62,8 +62,8 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) int count; se_cmd = &cmd->se_cmd; - pr_debug("%s: cmd %p state %d sess %p seq %p se_cmd %p\n", - caller, cmd, cmd->state, cmd->sess, cmd->seq, se_cmd); + pr_debug("%s: cmd %p sess %p seq %p se_cmd %p\n", + caller, cmd, cmd->sess, cmd->seq, se_cmd); pr_debug("%s: cmd %p cdb %p\n", caller, cmd, cmd->cdb); pr_debug("%s: cmd %p lun %d\n", caller, cmd, cmd->lun); @@ -90,38 +90,6 @@ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); } -static void ft_queue_cmd(struct ft_sess *sess, struct ft_cmd *cmd) -{ - struct ft_tpg *tpg = sess->tport->tpg; - struct se_queue_obj *qobj = &tpg->qobj; - unsigned long flags; - - qobj = &sess->tport->tpg->qobj; - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - list_add_tail(&cmd->se_req.qr_list, &qobj->qobj_list); - atomic_inc(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - - wake_up_process(tpg->thread); -} - -static struct ft_cmd *ft_dequeue_cmd(struct se_queue_obj *qobj) -{ - unsigned long flags; - struct se_queue_req *qr; - - spin_lock_irqsave(&qobj->cmd_queue_lock, flags); - if (list_empty(&qobj->qobj_list)) { - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return NULL; - } - qr = list_first_entry(&qobj->qobj_list, struct se_queue_req, qr_list); - list_del(&qr->qr_list); - atomic_dec(&qobj->queue_cnt); - spin_unlock_irqrestore(&qobj->cmd_queue_lock, flags); - return container_of(qr, struct ft_cmd, se_req); -} - static void ft_free_cmd(struct ft_cmd *cmd) { struct fc_frame *fp; @@ -282,9 +250,7 @@ u32 ft_get_task_tag(struct se_cmd *se_cmd) int ft_get_cmd_state(struct se_cmd *se_cmd) { - struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); - - return cmd->state; + return 0; } int ft_is_state_remove(struct se_cmd *se_cmd) @@ -505,6 +471,8 @@ int ft_queue_tm_resp(struct se_cmd *se_cmd) return 0; } +static void ft_send_work(struct work_struct *work); + /* * Handle incoming FCP command. */ @@ -523,7 +491,9 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp) goto busy; } cmd->req_frame = fp; /* hold frame during cmd */ - ft_queue_cmd(sess, cmd); + + INIT_WORK(&cmd->work, ft_send_work); + queue_work(sess->tport->tpg->workqueue, &cmd->work); return; busy: @@ -563,12 +533,13 @@ void ft_recv_req(struct ft_sess *sess, struct fc_frame *fp) /* * Send new command to target. */ -static void ft_send_cmd(struct ft_cmd *cmd) +static void ft_send_work(struct work_struct *work) { + struct ft_cmd *cmd = container_of(work, struct ft_cmd, work); struct fc_frame_header *fh = fc_frame_header_get(cmd->req_frame); struct se_cmd *se_cmd; struct fcp_cmnd *fcp; - int data_dir; + int data_dir = 0; u32 data_len; int task_attr; int ret; @@ -675,42 +646,3 @@ static void ft_send_cmd(struct ft_cmd *cmd) err: ft_send_resp_code_and_free(cmd, FCP_CMND_FIELDS_INVALID); } - -/* - * Handle request in the command thread. - */ -static void ft_exec_req(struct ft_cmd *cmd) -{ - pr_debug("cmd state %x\n", cmd->state); - switch (cmd->state) { - case FC_CMD_ST_NEW: - ft_send_cmd(cmd); - break; - default: - break; - } -} - -/* - * Processing thread. - * Currently one thread per tpg. - */ -int ft_thread(void *arg) -{ - struct ft_tpg *tpg = arg; - struct se_queue_obj *qobj = &tpg->qobj; - struct ft_cmd *cmd; - - while (!kthread_should_stop()) { - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); - if (kthread_should_stop()) - goto out; - - cmd = ft_dequeue_cmd(qobj); - if (cmd) - ft_exec_req(cmd); - } - -out: - return 0; -} diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index b15879d43e2..8fa39b74f22 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -327,7 +327,6 @@ static struct se_portal_group *ft_add_tpg( tpg->index = index; tpg->lport_acl = lacl; INIT_LIST_HEAD(&tpg->lun_list); - transport_init_queue_obj(&tpg->qobj); ret = core_tpg_register(&ft_configfs->tf_ops, wwn, &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL); @@ -336,8 +335,8 @@ static struct se_portal_group *ft_add_tpg( return NULL; } - tpg->thread = kthread_run(ft_thread, tpg, "ft_tpg%lu", index); - if (IS_ERR(tpg->thread)) { + tpg->workqueue = alloc_workqueue("tcm_fc", 0, 1); + if (!tpg->workqueue) { kfree(tpg); return NULL; } @@ -356,7 +355,7 @@ static void ft_del_tpg(struct se_portal_group *se_tpg) pr_debug("del tpg %s\n", config_item_name(&tpg->se_tpg.tpg_group.cg_item)); - kthread_stop(tpg->thread); + destroy_workqueue(tpg->workqueue); /* Wait for sessions to be freed thru RCU, for BUG_ON below */ synchronize_rcu(); -- cgit v1.2.3-70-g09d2 From 33a48ab105a75d37021e422a0a3283241099b142 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 7 Sep 2011 14:41:03 +0000 Subject: ibmveth: Fix DMA unmap error Commit 6e8ab30ec677 (ibmveth: Add scatter-gather support) introduced a DMA mapping API inconsistency resulting in dma_unmap_page getting called on memory mapped via dma_map_single. This was seen when CONFIG_DMA_API_DEBUG was enabled. Fix up this API usage inconsistency. Signed-off-by: Brian King Acked-by: Anton Blanchard Cc: # v2.6.37+ Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 3e667926940..dcf65d8f10d 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1026,7 +1026,12 @@ retry_bounce: netdev->stats.tx_bytes += skb->len; } - for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++) + dma_unmap_single(&adapter->vdev->dev, + descs[0].fields.address, + descs[0].fields.flags_len & IBMVETH_BUF_LEN_MASK, + DMA_TO_DEVICE); + + for (i = 1; i < skb_shinfo(skb)->nr_frags + 1; i++) dma_unmap_page(&adapter->vdev->dev, descs[i].fields.address, descs[i].fields.flags_len & IBMVETH_BUF_LEN_MASK, DMA_TO_DEVICE); -- cgit v1.2.3-70-g09d2 From b93da27f5234198433345e40b39ff59797bc6f6e Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Sep 2011 14:41:04 +0000 Subject: ibmveth: Fix issue with DMA mapping failure descs[].fields.address is 32bit which truncates any dma mapping errors so dma_mapping_error() fails to catch it. Use a dma_addr_t to do the comparison. With this patch I was able to transfer many gigabytes of data with IOMMU fault injection set at 10% probability. Signed-off-by: Anton Blanchard Cc: # v2.6.37+ Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index dcf65d8f10d..5b8b411d5a8 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -930,6 +930,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, union ibmveth_buf_desc descs[6]; int last, i; int force_bounce = 0; + dma_addr_t dma_addr; /* * veth handles a maximum of 6 segments including the header, so @@ -994,17 +995,16 @@ retry_bounce: } /* Map the header */ - descs[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data, - skb_headlen(skb), - DMA_TO_DEVICE); - if (dma_mapping_error(&adapter->vdev->dev, descs[0].fields.address)) + dma_addr = dma_map_single(&adapter->vdev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (dma_mapping_error(&adapter->vdev->dev, dma_addr)) goto map_failed; descs[0].fields.flags_len = desc_flags | skb_headlen(skb); + descs[0].fields.address = dma_addr; /* Map the frags */ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - unsigned long dma_addr; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; dma_addr = dma_map_page(&adapter->vdev->dev, frag->page, -- cgit v1.2.3-70-g09d2 From 91aae1e5c407d4fc79f6983e6c6ba04756c004cb Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Sep 2011 14:41:05 +0000 Subject: ibmveth: Checksum offload is always disabled Commit b9367bf3ee6d (net: ibmveth: convert to hw_features) reversed a check in ibmveth_set_csum_offload that results in checksum offload never being enabled. Signed-off-by: Anton Blanchard Cc: # 3.0+ Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 5b8b411d5a8..07830f918ae 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -812,7 +812,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) } else adapter->fw_ipv6_csum_support = data; - if (ret != H_SUCCESS || ret6 != H_SUCCESS) + if (ret == H_SUCCESS || ret6 == H_SUCCESS) adapter->rx_csum = data; else rc1 = -EIO; -- cgit v1.2.3-70-g09d2 From fb82fd204b6e6c67661bbd37df032edafb2da56e Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 7 Sep 2011 14:41:06 +0000 Subject: ibmveth: Fix checksum offload failure handling Fix a number of issues in ibmveth_set_csum_offload: - set_attr6 and clr_attr6 may be used uninitialised - We store the result of the IPV4 checksum change in ret but overwrite it in a couple of places before checking it again later. Add ret4 to make it obvious what we are doing. - We weren't clearing the NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM flags if the enable of that hypervisor feature failed. Signed-off-by: Anton Blanchard Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 07830f918ae..8dd5fccef72 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -757,7 +757,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) struct ibmveth_adapter *adapter = netdev_priv(dev); unsigned long set_attr, clr_attr, ret_attr; unsigned long set_attr6, clr_attr6; - long ret, ret6; + long ret, ret4, ret6; int rc1 = 0, rc2 = 0; int restart = 0; @@ -770,6 +770,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) set_attr = 0; clr_attr = 0; + set_attr6 = 0; + clr_attr6 = 0; if (data) { set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM; @@ -784,16 +786,20 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) && !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) && (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) { - ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr, + ret4 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, set_attr, &ret_attr); - if (ret != H_SUCCESS) { + if (ret4 != H_SUCCESS) { netdev_err(dev, "unable to change IPv4 checksum " "offload settings. %d rc=%ld\n", - data, ret); + data, ret4); + + h_illan_attributes(adapter->vdev->unit_address, + set_attr, clr_attr, &ret_attr); + + if (data == 1) + dev->features &= ~NETIF_F_IP_CSUM; - ret = h_illan_attributes(adapter->vdev->unit_address, - set_attr, clr_attr, &ret_attr); } else { adapter->fw_ipv4_csum_support = data; } @@ -804,15 +810,18 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) if (ret6 != H_SUCCESS) { netdev_err(dev, "unable to change IPv6 checksum " "offload settings. %d rc=%ld\n", - data, ret); + data, ret6); + + h_illan_attributes(adapter->vdev->unit_address, + set_attr6, clr_attr6, &ret_attr); + + if (data == 1) + dev->features &= ~NETIF_F_IPV6_CSUM; - ret = h_illan_attributes(adapter->vdev->unit_address, - set_attr6, clr_attr6, - &ret_attr); } else adapter->fw_ipv6_csum_support = data; - if (ret == H_SUCCESS || ret6 == H_SUCCESS) + if (ret4 == H_SUCCESS || ret6 == H_SUCCESS) adapter->rx_csum = data; else rc1 = -EIO; -- cgit v1.2.3-70-g09d2 From 7cabafcea793c003503a118da58da358b0692930 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 14 Sep 2011 16:47:50 +0200 Subject: ipw2x00: fix rtnl mutex deadlock This fix regression introduced by: commit: ecb4433550f0620f3d1471ae7099037ede30a91e Author: Stanislaw Gruszka Date: Fri Aug 12 14:00:59 2011 +0200 mac80211: fix suspend/resume races with unregister hw Above commit add rtnl_lock() into wiphy_register(), what cause deadlock when initializing ipw2x00 driver, which itself call wiphy_register() from register_netdev() internal callback with rtnl mutex taken. To fix move wiphy_register() outside register_netdev(). This solution have side effect of not creating /sys/class/net/wlanX/phy80211 link, but that's a minor issue we can live with. Bisected-by: Witold Baryluk Bisected-by: Michael Witten Tested-by: Witold Baryluk Tested-by: Michael Witten Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2x00/ipw2100.c | 21 ++++++++++++------ drivers/net/wireless/ipw2x00/ipw2200.c | 39 ++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 3774dd03474..ef9ad79d1bf 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1901,17 +1901,19 @@ static void ipw2100_down(struct ipw2100_priv *priv) /* Called by register_netdev() */ static int ipw2100_net_init(struct net_device *dev) +{ + struct ipw2100_priv *priv = libipw_priv(dev); + + return ipw2100_up(priv, 1); +} + +static int ipw2100_wdev_init(struct net_device *dev) { struct ipw2100_priv *priv = libipw_priv(dev); const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct wireless_dev *wdev = &priv->ieee->wdev; - int ret; int i; - ret = ipw2100_up(priv, 1); - if (ret) - return ret; - memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); /* fill-out priv->ieee->bg_band */ @@ -6350,9 +6352,13 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, "Error calling register_netdev.\n"); goto fail; } + registered = 1; + + err = ipw2100_wdev_init(dev); + if (err) + goto fail; mutex_lock(&priv->action_mutex); - registered = 1; IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev)); @@ -6389,7 +6395,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, fail_unlock: mutex_unlock(&priv->action_mutex); - + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->bg_band.channels); fail: if (dev) { if (registered) diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 87813c33bdc..4ffebede5e0 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -11424,17 +11424,24 @@ static void ipw_bg_down(struct work_struct *work) /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) +{ + int rc = 0; + struct ipw_priv *priv = libipw_priv(dev); + + mutex_lock(&priv->mutex); + if (ipw_up(priv)) + rc = -EIO; + mutex_unlock(&priv->mutex); + + return rc; +} + +static int ipw_wdev_init(struct net_device *dev) { int i, rc = 0; struct ipw_priv *priv = libipw_priv(dev); const struct libipw_geo *geo = libipw_get_geo(priv->ieee); struct wireless_dev *wdev = &priv->ieee->wdev; - mutex_lock(&priv->mutex); - - if (ipw_up(priv)) { - rc = -EIO; - goto out; - } memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN); @@ -11519,13 +11526,9 @@ static int ipw_net_init(struct net_device *dev) set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev); /* With that information in place, we can now register the wiphy... */ - if (wiphy_register(wdev->wiphy)) { + if (wiphy_register(wdev->wiphy)) rc = -EIO; - goto out; - } - out: - mutex_unlock(&priv->mutex); return rc; } @@ -11832,14 +11835,22 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, goto out_remove_sysfs; } + err = ipw_wdev_init(net_dev); + if (err) { + IPW_ERROR("failed to register wireless device\n"); + goto out_unregister_netdev; + } + #ifdef CONFIG_IPW2200_PROMISCUOUS if (rtap_iface) { err = ipw_prom_alloc(priv); if (err) { IPW_ERROR("Failed to register promiscuous network " "device (error %d).\n", err); - unregister_netdev(priv->net_dev); - goto out_remove_sysfs; + wiphy_unregister(priv->ieee->wdev.wiphy); + kfree(priv->ieee->a_band.channels); + kfree(priv->ieee->bg_band.channels); + goto out_unregister_netdev; } } #endif @@ -11851,6 +11862,8 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, return 0; + out_unregister_netdev: + unregister_netdev(priv->net_dev); out_remove_sysfs: sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); out_release_irq: -- cgit v1.2.3-70-g09d2 From d331eb51e4d4190b2178c30fcafea54a94a577e8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 14 Sep 2011 16:50:22 -0500 Subject: rt2800pci: Fix compiler error on PowerPC Using gcc 4.4.5 on a Powerbook G4 with a PPC cpu, a complicated if statement results in incorrect flow, whereas the equivalent switch statement works correctly. Signed-off-by: Larry Finger Cc: stable Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index ef67f6786a8..23568af4941 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3870,19 +3870,23 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) return -ENODEV; } - if (!rt2x00_rf(rt2x00dev, RF2820) && - !rt2x00_rf(rt2x00dev, RF2850) && - !rt2x00_rf(rt2x00dev, RF2720) && - !rt2x00_rf(rt2x00dev, RF2750) && - !rt2x00_rf(rt2x00dev, RF3020) && - !rt2x00_rf(rt2x00dev, RF2020) && - !rt2x00_rf(rt2x00dev, RF3021) && - !rt2x00_rf(rt2x00dev, RF3022) && - !rt2x00_rf(rt2x00dev, RF3052) && - !rt2x00_rf(rt2x00dev, RF3320) && - !rt2x00_rf(rt2x00dev, RF5370) && - !rt2x00_rf(rt2x00dev, RF5390)) { - ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); + switch (rt2x00dev->chip.rf) { + case RF2820: + case RF2850: + case RF2720: + case RF2750: + case RF3020: + case RF2020: + case RF3021: + case RF3022: + case RF3052: + case RF3320: + case RF5370: + case RF5390: + break; + default: + ERROR(rt2x00dev, "Invalid RF chipset 0x%x detected.\n", + rt2x00dev->chip.rf); return -ENODEV; } -- cgit v1.2.3-70-g09d2 From daabead1c32f331edcfb255fd973411c667977e8 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 14 Sep 2011 16:50:23 -0500 Subject: rtl2800usb: Fix incorrect storage of MAC address on big-endian platforms The eeprom data is stored in little-endian order in the rt2x00 library. As it was converted to cpu order in the read routines, the data need to be converted to LE on a big-endian platform. Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800lib.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 23568af4941..0019dfd8fb0 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3697,14 +3697,15 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, - (u32 *)&rt2x00dev->eeprom[i]); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, - (u32 *)&rt2x00dev->eeprom[i + 2]); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, - (u32 *)&rt2x00dev->eeprom[i + 4]); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, - (u32 *)&rt2x00dev->eeprom[i + 6]); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); + /* The returned value is in CPU order, but eeprom is le */ + rt2x00dev->eeprom[i] = cpu_to_le32(reg); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); + *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); + *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); + rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, ®); + *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); mutex_unlock(&rt2x00dev->csr_mutex); } -- cgit v1.2.3-70-g09d2 From 2249b011432ca3dcce112f0f71e0f531b4bb9347 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Thu, 15 Sep 2011 08:36:22 -0700 Subject: iwlagn: workaround bug crashing some APs This patch reverts commit 9b7688328422b88a7a15dc0dc123ad9ab1a6e22d which was introduced in 2.6.38-rc1. It works around a problem where the iwlagn driver stimulates a bug crashing (requiring power cycle to recover) some APs under heavy traffic. CC: stable@kernel.org #2.6.39, #3.0.0 #3.1.0 Signed-off-by: Don Fry SIgned-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index b0ae4de7f08..f9c3cd95d61 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2140,7 +2140,12 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_SPECTRUM_MGMT | IEEE80211_HW_REPORTS_TX_ACK_STATUS; + /* + * Including the following line will crash some AP's. This + * workaround removes the stimulus which causes the crash until + * the AP software can be fixed. hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF; + */ hw->flags |= IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS; -- cgit v1.2.3-70-g09d2 From 784eb99ebad91db4c8c231c4b17f203147ab827b Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 16 Sep 2011 01:31:28 -0700 Subject: target: Skip non hex characters for VPD=0x83 NAA IEEE Registered Extended This patch adds target_parse_naa_6h_vendor_specific() to address a bug where the conversion of PRODUCT SERIAL NUMBER to use hex2bin() in target_emulate_evpd_83() was not doing proper isxdigit() checking. This conversion of the vpd_unit_serial configifs attribute is done while generating a VPD=0x83 NAA IEEE Registered Extended DESIGNATOR format's 100 bits of unique VENDOR SPECIFIC IDENTIFIER + VENDOR SPECIFIC IDENTIFIER EXTENSION area. This patch allows vpd_unit_serial (VPD=0x80) and the T10 Vendor ID DESIGNATOR format (VPD=0x83) to continue to use free-form variable length ASCII values, and now skips any non hex characters for fixed length NAA IEEE Registered Extended DESIGNATOR format (VPD=0x83) requring the binary conversion. This was originally reported by Martin after the v3.1-rc1 change to use hex2bin() in commit 11650b859681e03fdbf26277fcfc5f1f62186703 where the use of non hex characters in vpd_unit_serial generated different values than the original v3.0 internal hex -> binary code. This v3.1 change caused a problem with filesystems who write a NAA DESIGNATOR onto it's ondisk metadata, and this patch will (again) change existing values to ensure that non hex characters are not included in the fixed length NAA DESIGNATOR. Note this patch still expects vpd_unit_serial to be set via existing userspace methods of uuid generation, and does not do strict formatting via configfs input. The original bug report and thread can be found here: NAA breakage http://www.spinics.net/lists/target-devel/msg00477.html The v3.1-rc1 formatting of VPD=0x83 w/o this patch: VPD INQUIRY: Device Identification page Designation descriptor number 1, descriptor length: 20 designator_type: NAA, code_set: Binary associated with the addressed logical unit NAA 6, IEEE Company_id: 0x1405 Vendor Specific Identifier: 0xffde35ebf Vendor Specific Identifier Extension: 0x3092f498ffa820f9 [0x6001405ffde35ebf3092f498ffa820f9] Designation descriptor number 2, descriptor length: 56 designator_type: T10 vendor identification, code_set: ASCII associated with the addressed logical unit vendor id: LIO-ORG vendor specific: IBLOCK:ffde35ec-3092-4980-a820-917636ca54f1 The v3.1-final formatting of VPD=0x83 w/ this patch: VPD INQUIRY: Device Identification page Designation descriptor number 1, descriptor length: 20 designator_type: NAA, code_set: Binary associated with the addressed logical unit NAA 6, IEEE Company_id: 0x1405 Vendor Specific Identifier: 0xffde35ec3 Vendor Specific Identifier Extension: 0x924980a82091763 [0x6001405ffde35ec30924980a82091763] Designation descriptor number 2, descriptor length: 56 designator_type: T10 vendor identification, code_set: ASCII associated with the addressed logical unit vendor id: LIO-ORG vendor specific: IBLOCK:ffde35ec-3092-4980-a820-917636ca54f1 (v2: Fix parsing code to dereference + check for string terminator instead of null pointer to ensure a zeroed payload for vpd_unit_serial less than 100 bits of NAA DESIGNATOR VENDOR SPECIFIC area. Also, remove the unnecessary bitwise assignment) Reported-by: Martin Svec Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_cdb.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 89ae923c5da..f04d4ef99dc 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -24,6 +24,7 @@ */ #include +#include #include #include @@ -154,6 +155,37 @@ target_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) return 0; } +static void +target_parse_naa_6h_vendor_specific(struct se_device *dev, unsigned char *buf_off) +{ + unsigned char *p = &dev->se_sub_dev->t10_wwn.unit_serial[0]; + unsigned char *buf = buf_off; + int cnt = 0, next = 1; + /* + * Generate up to 36 bits of VENDOR SPECIFIC IDENTIFIER starting on + * byte 3 bit 3-0 for NAA IEEE Registered Extended DESIGNATOR field + * format, followed by 64 bits of VENDOR SPECIFIC IDENTIFIER EXTENSION + * to complete the payload. These are based from VPD=0x80 PRODUCT SERIAL + * NUMBER set via vpd_unit_serial in target_core_configfs.c to ensure + * per device uniqeness. + */ + while (*p != '\0') { + if (cnt >= 13) + break; + if (!isxdigit(*p)) { + p++; + continue; + } + if (next != 0) { + buf[cnt++] |= hex_to_bin(*p++); + next = 0; + } else { + buf[cnt] = hex_to_bin(*p++) << 4; + next = 1; + } + } +} + /* * Device identification VPD, for a complete list of * DESIGNATOR TYPEs see spc4r17 Table 459. @@ -219,8 +251,7 @@ target_emulate_evpd_83(struct se_cmd *cmd, unsigned char *buf) * VENDOR_SPECIFIC_IDENTIFIER and * VENDOR_SPECIFIC_IDENTIFIER_EXTENTION */ - buf[off++] |= hex_to_bin(dev->se_sub_dev->t10_wwn.unit_serial[0]); - hex2bin(&buf[off], &dev->se_sub_dev->t10_wwn.unit_serial[1], 12); + target_parse_naa_6h_vendor_specific(dev, &buf[off]); len = 20; off = (len + 4); -- cgit v1.2.3-70-g09d2 From 2ff017f5b4299e24a7f22d9a336dd162bf52bb54 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 16 Sep 2011 01:44:54 -0700 Subject: iscsi-target: Disable markers + remove dangerous local scope array usage This patch makes iscsi-target explictly disable OFMarker=Yes and IFMarker=yes parameter key usage during iscsi login by setting IFMarkInt_Reject and OFMarkInt_Reject values in iscsi_enforce_integrity_rules() to effectively disable iscsi marker usage. With this patch, an initiator proposer asking to enable either marker parameter keys will be issued a 'No' response, and the target sets OFMarkInt + IFMarkInt parameter key response to 'Irrelevant'. With markers disabled during iscsi login, this patch removes the problematic on-stack local-scope array for marker intervals in iscsit_do_rx_data() + iscsit_do_tx_data(), and other related marker code in iscsi_target_util.c. This fixes a potentional stack smashing scenario with small range markers enabled and a large MRDSL as reported by DanC here: [bug report] target: stack can be smashed http://www.spinics.net/lists/target-devel/msg00453.html Reported-by: Dan Carpenter Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_parameters.c | 2 +- drivers/target/iscsi/iscsi_target_util.c | 248 +------------------------ 2 files changed, 7 insertions(+), 243 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 497b2e718a7..5b773160200 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -1430,7 +1430,7 @@ static int iscsi_enforce_integrity_rules( u8 DataSequenceInOrder = 0; u8 ErrorRecoveryLevel = 0, SessionType = 0; u8 IFMarker = 0, OFMarker = 0; - u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0; + u8 IFMarkInt_Reject = 1, OFMarkInt_Reject = 1; u32 FirstBurstLength = 0, MaxBurstLength = 0; struct iscsi_param *param = NULL; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index a0d23bc0fc9..1d1b4fe33e4 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -874,40 +874,6 @@ void iscsit_inc_session_usage_count(struct iscsi_session *sess) spin_unlock_bh(&sess->session_usage_lock); } -/* - * Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker - * array counts needed for sync and steering. - */ -static int iscsit_determine_sync_and_steering_counts( - struct iscsi_conn *conn, - struct iscsi_data_count *count) -{ - u32 length = count->data_length; - u32 marker, markint; - - count->sync_and_steering = 1; - - marker = (count->type == ISCSI_RX_DATA) ? - conn->of_marker : conn->if_marker; - markint = (count->type == ISCSI_RX_DATA) ? - (conn->conn_ops->OFMarkInt * 4) : - (conn->conn_ops->IFMarkInt * 4); - count->ss_iov_count = count->iov_count; - - while (length > 0) { - if (length >= marker) { - count->ss_iov_count += 3; - count->ss_marker_count += 2; - - length -= marker; - marker = markint; - } else - length = 0; - } - - return 0; -} - /* * Setup conn->if_marker and conn->of_marker values based upon * the initial marker-less interval. (see iSCSI v19 A.2) @@ -1431,8 +1397,7 @@ static int iscsit_do_rx_data( struct iscsi_data_count *count) { int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; - u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0; - struct kvec iov[count->ss_iov_count], *iov_p; + struct kvec *iov_p; struct msghdr msg; if (!conn || !conn->sock || !conn->conn_ops) @@ -1440,93 +1405,8 @@ static int iscsit_do_rx_data( memset(&msg, 0, sizeof(struct msghdr)); - if (count->sync_and_steering) { - int size = 0; - u32 i, orig_iov_count = 0; - u32 orig_iov_len = 0, orig_iov_loc = 0; - u32 iov_count = 0, per_iov_bytes = 0; - u32 *rx_marker, old_rx_marker = 0; - struct kvec *iov_record; - - memset(&rx_marker_val, 0, - count->ss_marker_count * sizeof(u32)); - memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); - - iov_record = count->iov; - orig_iov_count = count->iov_count; - rx_marker = &conn->of_marker; - - i = 0; - size = data; - orig_iov_len = iov_record[orig_iov_loc].iov_len; - while (size > 0) { - pr_debug("rx_data: #1 orig_iov_len %u," - " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); - pr_debug("rx_data: #2 rx_marker %u, size" - " %u\n", *rx_marker, size); - - if (orig_iov_len >= *rx_marker) { - iov[iov_count].iov_len = *rx_marker; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &rx_marker_val[rx_marker_iov++]; - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &rx_marker_val[rx_marker_iov++]; - old_rx_marker = *rx_marker; - - /* - * OFMarkInt is in 32-bit words. - */ - *rx_marker = (conn->conn_ops->OFMarkInt * 4); - size -= old_rx_marker; - orig_iov_len -= old_rx_marker; - per_iov_bytes += old_rx_marker; - - pr_debug("rx_data: #3 new_rx_marker" - " %u, size %u\n", *rx_marker, size); - } else { - iov[iov_count].iov_len = orig_iov_len; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - per_iov_bytes = 0; - *rx_marker -= orig_iov_len; - size -= orig_iov_len; - - if (size) - orig_iov_len = - iov_record[++orig_iov_loc].iov_len; - - pr_debug("rx_data: #4 new_rx_marker" - " %u, size %u\n", *rx_marker, size); - } - } - data += (rx_marker_iov * (MARKER_SIZE / 2)); - - iov_p = &iov[0]; - iov_len = iov_count; - - if (iov_count > count->ss_iov_count) { - pr_err("iov_count: %d, count->ss_iov_count:" - " %d\n", iov_count, count->ss_iov_count); - return -1; - } - if (rx_marker_iov > count->ss_marker_count) { - pr_err("rx_marker_iov: %d, count->ss_marker" - "_count: %d\n", rx_marker_iov, - count->ss_marker_count); - return -1; - } - } else { - iov_p = count->iov; - iov_len = count->iov_count; - } + iov_p = count->iov; + iov_len = count->iov_count; while (total_rx < data) { rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, @@ -1541,16 +1421,6 @@ static int iscsit_do_rx_data( rx_loop, total_rx, data); } - if (count->sync_and_steering) { - int j; - for (j = 0; j < rx_marker_iov; j++) { - pr_debug("rx_data: #5 j: %d, offset: %d\n", - j, rx_marker_val[j]); - conn->of_marker_offset = rx_marker_val[j]; - } - total_rx -= (rx_marker_iov * (MARKER_SIZE / 2)); - } - return total_rx; } @@ -1559,8 +1429,7 @@ static int iscsit_do_tx_data( struct iscsi_data_count *count) { int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; - u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0; - struct kvec iov[count->ss_iov_count], *iov_p; + struct kvec *iov_p; struct msghdr msg; if (!conn || !conn->sock || !conn->conn_ops) @@ -1573,98 +1442,8 @@ static int iscsit_do_tx_data( memset(&msg, 0, sizeof(struct msghdr)); - if (count->sync_and_steering) { - int size = 0; - u32 i, orig_iov_count = 0; - u32 orig_iov_len = 0, orig_iov_loc = 0; - u32 iov_count = 0, per_iov_bytes = 0; - u32 *tx_marker, old_tx_marker = 0; - struct kvec *iov_record; - - memset(&tx_marker_val, 0, - count->ss_marker_count * sizeof(u32)); - memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); - - iov_record = count->iov; - orig_iov_count = count->iov_count; - tx_marker = &conn->if_marker; - - i = 0; - size = data; - orig_iov_len = iov_record[orig_iov_loc].iov_len; - while (size > 0) { - pr_debug("tx_data: #1 orig_iov_len %u," - " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); - pr_debug("tx_data: #2 tx_marker %u, size" - " %u\n", *tx_marker, size); - - if (orig_iov_len >= *tx_marker) { - iov[iov_count].iov_len = *tx_marker; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - tx_marker_val[tx_marker_iov] = - (size - *tx_marker); - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &tx_marker_val[tx_marker_iov++]; - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &tx_marker_val[tx_marker_iov++]; - old_tx_marker = *tx_marker; - - /* - * IFMarkInt is in 32-bit words. - */ - *tx_marker = (conn->conn_ops->IFMarkInt * 4); - size -= old_tx_marker; - orig_iov_len -= old_tx_marker; - per_iov_bytes += old_tx_marker; - - pr_debug("tx_data: #3 new_tx_marker" - " %u, size %u\n", *tx_marker, size); - pr_debug("tx_data: #4 offset %u\n", - tx_marker_val[tx_marker_iov-1]); - } else { - iov[iov_count].iov_len = orig_iov_len; - iov[iov_count++].iov_base - = (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - per_iov_bytes = 0; - *tx_marker -= orig_iov_len; - size -= orig_iov_len; - - if (size) - orig_iov_len = - iov_record[++orig_iov_loc].iov_len; - - pr_debug("tx_data: #5 new_tx_marker" - " %u, size %u\n", *tx_marker, size); - } - } - - data += (tx_marker_iov * (MARKER_SIZE / 2)); - - iov_p = &iov[0]; - iov_len = iov_count; - - if (iov_count > count->ss_iov_count) { - pr_err("iov_count: %d, count->ss_iov_count:" - " %d\n", iov_count, count->ss_iov_count); - return -1; - } - if (tx_marker_iov > count->ss_marker_count) { - pr_err("tx_marker_iov: %d, count->ss_marker" - "_count: %d\n", tx_marker_iov, - count->ss_marker_count); - return -1; - } - } else { - iov_p = count->iov; - iov_len = count->iov_count; - } + iov_p = count->iov; + iov_len = count->iov_count; while (total_tx < data) { tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, @@ -1679,9 +1458,6 @@ static int iscsit_do_tx_data( tx_loop, total_tx, data); } - if (count->sync_and_steering) - total_tx -= (tx_marker_iov * (MARKER_SIZE / 2)); - return total_tx; } @@ -1702,12 +1478,6 @@ int rx_data( c.data_length = data; c.type = ISCSI_RX_DATA; - if (conn->conn_ops->OFMarker && - (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { - if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) - return -1; - } - return iscsit_do_rx_data(conn, &c); } @@ -1728,12 +1498,6 @@ int tx_data( c.data_length = data; c.type = ISCSI_TX_DATA; - if (conn->conn_ops->IFMarker && - (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { - if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) - return -1; - } - return iscsit_do_tx_data(conn, &c); } -- cgit v1.2.3-70-g09d2 From f39aa30d7741f40ad964341e9243dbbd7f8ff057 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 31 Aug 2011 10:45:46 +0800 Subject: firewire: ohci: add no MSI quirk for O2Micro controller This fixes https://bugs.launchpad.net/ubuntu/+source/linux/+bug/801719 . An O2Micro PCI Express FireWire controller, "FireWire (IEEE 1394) [0c00]: O2 Micro, Inc. Device [1217:11f7] (rev 05)" which is a combination device together with an SDHCI controller and some sort of storage controller, misses SBP-2 status writes from an attached FireWire HDD. This problem goes away if MSI is disabled for this FireWire controller. The device reportedly does not require QUIRK_CYCLE_TIMER. Signed-off-by: Ming Lei Signed-off-by: Stefan Richter (amended changelog) Cc: --- drivers/firewire/ohci.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 57cd3a406ed..fd7170a9ad2 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -290,6 +290,9 @@ static const struct { {PCI_VENDOR_ID_NEC, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, + {PCI_VENDOR_ID_O2, PCI_ANY_ID, PCI_ANY_ID, + QUIRK_NO_MSI}, + {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, QUIRK_CYCLE_TIMER}, -- cgit v1.2.3-70-g09d2 From 34b8686d278f00fb16234e74be44c253d6d6b676 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Fri, 16 Sep 2011 07:57:43 +0000 Subject: can: ti_hecc: include linux/io.h This fixes a build breakage for OMAP3 boards. Signed-off-by: Daniel Mack Cc: Wolfgang Grandegger Cc: netdev@vger.kernel.org Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/ti_hecc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index a81249246ec..2adc294f512 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3-70-g09d2 From 40b054970afcf067896d62cd6f7e617c62665304 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 16 Sep 2011 16:55:47 -0700 Subject: iscsi-target: Fix sendpage breakage with proper padding+DataDigest iovec offsets This patch fixes a bug in the iscsit_fe_sendpage_sg() transmit codepath that was originally introduced with the v3.1 iscsi-target merge that incorrectly uses hardcoded cmd->iov_data_count values to determine cmd->iov_data[] offsets for extra outgoing padding and DataDigest payload vectors. This code is obviously incorrect for the DataDigest enabled case with sendpage offload, and this fix ensures correct operation for padding + DataDigest, padding only, and DataDigest only cases. The bug was introduced during a pre-merge change in iscsit_fe_sendpage_sg() to natively use struct scatterlist instead of the legacy v3.0 struct se_mem logic. Cc: Andy Grover Cc: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_util.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1d1b4fe33e4..f00137f377b 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1256,7 +1256,7 @@ int iscsit_fe_sendpage_sg( struct kvec iov; u32 tx_hdr_size, data_len; u32 offset = cmd->first_data_sg_off; - int tx_sent; + int tx_sent, iov_off; send_hdr: tx_hdr_size = ISCSI_HDR_LEN; @@ -1276,9 +1276,19 @@ send_hdr: } data_len = cmd->tx_size - tx_hdr_size - cmd->padding; - if (conn->conn_ops->DataDigest) + /* + * Set iov_off used by padding and data digest tx_data() calls below + * in order to determine proper offset into cmd->iov_data[] + */ + if (conn->conn_ops->DataDigest) { data_len -= ISCSI_CRC_LEN; - + if (cmd->padding) + iov_off = (cmd->iov_data_count - 2); + else + iov_off = (cmd->iov_data_count - 1); + } else { + iov_off = (cmd->iov_data_count - 1); + } /* * Perform sendpage() for each page in the scatterlist */ @@ -1307,8 +1317,7 @@ send_pg: send_padding: if (cmd->padding) { - struct kvec *iov_p = - &cmd->iov_data[cmd->iov_data_count-1]; + struct kvec *iov_p = &cmd->iov_data[iov_off++]; tx_sent = tx_data(conn, iov_p, 1, cmd->padding); if (cmd->padding != tx_sent) { @@ -1322,8 +1331,7 @@ send_padding: send_datacrc: if (conn->conn_ops->DataDigest) { - struct kvec *iov_d = - &cmd->iov_data[cmd->iov_data_count]; + struct kvec *iov_d = &cmd->iov_data[iov_off]; tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); if (ISCSI_CRC_LEN != tx_sent) { -- cgit v1.2.3-70-g09d2 From c2b0c1e7fb69b54e704cb2dae5a80cc78a8cb0b2 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 6 Sep 2011 16:55:16 +0800 Subject: r8169: fix the reset setting for 8111evl rtl8111evl should stop any TLP requirement before resetting by enabling register 0x37 bit 7. Signed-off-by: Hayes Wang --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 02339b3352e..a1c90707a2d 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3988,6 +3988,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) while (RTL_R8(TxPoll) & NPQ) udelay(20); } else if (tp->mac_version == RTL_GIGA_MAC_VER_34) { + RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq); while (!(RTL_R32(TxConfig) & TXCFG_EMPTY)) udelay(100); } else { -- cgit v1.2.3-70-g09d2 From bbb8af75d0a6a5138ff00fe0b1b95c4824effd55 Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 6 Sep 2011 16:55:17 +0800 Subject: r8169: add MODULE_FIRMWARE for the firmware of 8111evl Add MODULE_FIRMWARE for the firmware of RTL8111E-VL Signed-off-by: Hayes Wang --- drivers/net/r8169.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index a1c90707a2d..b55fba7f3a0 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -710,6 +710,7 @@ MODULE_FIRMWARE(FIRMWARE_8168D_1); MODULE_FIRMWARE(FIRMWARE_8168D_2); MODULE_FIRMWARE(FIRMWARE_8168E_1); MODULE_FIRMWARE(FIRMWARE_8168E_2); +MODULE_FIRMWARE(FIRMWARE_8168E_3); MODULE_FIRMWARE(FIRMWARE_8105E_1); static int rtl8169_open(struct net_device *dev); -- cgit v1.2.3-70-g09d2 From 106633897e086e1b47126996aac1a427eb80eb1b Mon Sep 17 00:00:00 2001 From: Hayes Wang Date: Tue, 6 Sep 2011 16:55:14 +0800 Subject: r8169: fix WOL setting for 8105 and 8111evl rtl8105, rtl8111E, and rtl8111evl need enable RxConfig bit 1 ~ 3 for supporting wake on lan. Signed-off-by: Hayes Wang --- drivers/net/r8169.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index b55fba7f3a0..78c1d583279 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3320,9 +3320,16 @@ static void r810x_phy_power_up(struct rtl8169_private *tp) static void r810x_pll_power_down(struct rtl8169_private *tp) { + void __iomem *ioaddr = tp->mmio_addr; + if (__rtl8169_get_wol(tp) & WAKE_ANY) { rtl_writephy(tp, 0x1f, 0x0000); rtl_writephy(tp, MII_BMCR, 0x0000); + + if (tp->mac_version == RTL_GIGA_MAC_VER_29 || + tp->mac_version == RTL_GIGA_MAC_VER_30) + RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast | + AcceptMulticast | AcceptMyPhys); return; } @@ -3418,7 +3425,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp) rtl_writephy(tp, MII_BMCR, 0x0000); if (tp->mac_version == RTL_GIGA_MAC_VER_32 || - tp->mac_version == RTL_GIGA_MAC_VER_33) + tp->mac_version == RTL_GIGA_MAC_VER_33 || + tp->mac_version == RTL_GIGA_MAC_VER_34) RTL_W32(RxConfig, RTL_R32(RxConfig) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys); return; -- cgit v1.2.3-70-g09d2 From e03f33af79f0772156e1a1a1e36bdddf8012b2e4 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 25 Aug 2011 18:47:24 +0200 Subject: r8169: remove erroneous processing of always set bit. When set, RxFOVF (resp. RxBOVF) is always 1 (resp. 0). Signed-off-by: Francois Romieu Cc: Hayes --- drivers/net/r8169.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 78c1d583279..dff0bf09416 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -407,6 +407,7 @@ enum rtl_register_content { RxOK = 0x0001, /* RxStatusDesc */ + RxBOVF = (1 << 24), RxFOVF = (1 << 23), RxRWT = (1 << 22), RxRES = (1 << 21), @@ -682,6 +683,7 @@ struct rtl8169_private { struct mii_if_info mii; struct rtl8169_counters counters; u32 saved_wolopts; + u32 opts1_mask; struct rtl_fw { const struct firmware *fw; @@ -3786,6 +3788,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->intr_event = cfg->intr_event; tp->napi_event = cfg->napi_event; + tp->opts1_mask = (tp->mac_version != RTL_GIGA_MAC_VER_01) ? + ~(RxBOVF | RxFOVF) : ~0; + init_timer(&tp->timer); tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; @@ -5324,7 +5329,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev, u32 status; rmb(); - status = le32_to_cpu(desc->opts1); + status = le32_to_cpu(desc->opts1) & tp->opts1_mask; if (status & DescOwn) break; -- cgit v1.2.3-70-g09d2 From 2544bfc0eb2581e0eedbdfea1468b3866223d47e Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 1 Sep 2011 18:42:09 +0200 Subject: r8169: do not enable the TBI for anything but the original 8169. The TBI bit in PHYStatus is reserved on anything but the oldest 8169. Nobody complained after I disabled it for the 8168 and the 810x (see 66ec5d4fb1ce6f0bd9df4bc4b758f0916d9f37ab). Signed-off-by: Francois Romieu Cc: Hayes Wang --- drivers/net/r8169.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index dff0bf09416..c2366701792 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -3080,6 +3080,14 @@ static void rtl8169_phy_reset(struct net_device *dev, netif_err(tp, link, dev, "PHY reset failed\n"); } +static bool rtl_tbi_enabled(struct rtl8169_private *tp) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return (tp->mac_version == RTL_GIGA_MAC_VER_01) && + (RTL_R8(PHYstatus) & TBI_Enable); +} + static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) { void __iomem *ioaddr = tp->mmio_addr; @@ -3112,7 +3120,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full : 0)); - if (RTL_R8(PHYstatus) & TBI_Enable) + if (rtl_tbi_enabled(tp)) netif_info(tp, link, dev, "TBI auto-negotiating\n"); } @@ -3738,8 +3746,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->features |= rtl_try_msi(pdev, ioaddr, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); - if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) && - (RTL_R8(PHYstatus) & TBI_Enable)) { + if (rtl_tbi_enabled(tp)) { tp->set_speed = rtl8169_set_speed_tbi; tp->get_settings = rtl8169_gset_tbi; tp->phy_reset_enable = rtl8169_tbi_reset_enable; -- cgit v1.2.3-70-g09d2 From 8be964d2364e8fbe302850f60d9d514c3e134510 Mon Sep 17 00:00:00 2001 From: Chen Ganir Date: Tue, 30 Aug 2011 13:58:28 +0300 Subject: Bluetooth: Fixed BT ST Channel reg order Reordered the BT ST channel registration, to make sure that the event channel is registered before all others. This prevents a situation where incoming events may cause kernel panic in the ST driver if the event channel is not yet registered to handle incoming events.In addition, the deregistration of the channels was also modified, to be in the reversed order of the registration, to allow the event channel to be the last one unregistered. Signed-off-by: Chen Ganir Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btwilink.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btwilink.c b/drivers/bluetooth/btwilink.c index 65d27aff553..04d353f58d7 100644 --- a/drivers/bluetooth/btwilink.c +++ b/drivers/bluetooth/btwilink.c @@ -124,6 +124,13 @@ static long st_receive(void *priv_data, struct sk_buff *skb) /* ------- Interfaces to HCI layer ------ */ /* protocol structure registered with shared transport */ static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = { + { + .chnl_id = HCI_EVENT_PKT, /* HCI Events */ + .hdr_len = sizeof(struct hci_event_hdr), + .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen), + .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */ + .reserve = 8, + }, { .chnl_id = HCI_ACLDATA_PKT, /* ACL */ .hdr_len = sizeof(struct hci_acl_hdr), @@ -138,13 +145,6 @@ static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = { .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */ .reserve = 8, }, - { - .chnl_id = HCI_EVENT_PKT, /* HCI Events */ - .hdr_len = sizeof(struct hci_event_hdr), - .offset_len_in_hdr = offsetof(struct hci_event_hdr, plen), - .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */ - .reserve = 8, - }, }; /* Called from HCI core to initialize the device */ @@ -240,7 +240,7 @@ static int ti_st_close(struct hci_dev *hdev) if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; - for (i = 0; i < MAX_BT_CHNL_IDS; i++) { + for (i = MAX_BT_CHNL_IDS-1; i >= 0; i--) { err = st_unregister(&ti_st_proto[i]); if (err) BT_ERR("st_unregister(%d) failed with error %d", -- cgit v1.2.3-70-g09d2 From a63b723d02531f7add0b2b8a0e6a77ee176f1626 Mon Sep 17 00:00:00 2001 From: Pieter-Augustijn Van Malleghem Date: Wed, 7 Sep 2011 02:28:10 -0400 Subject: Bluetooth: Add MacBookAir4,1 support This patch against current git adds the hardware ID for the Apple MacBookAir4,1, released in July 2011. The device features a BCM2046 USB chip. The patch was inspired by the previous modifications adding support for the MacBookAir3,x. Signed-off-by: Pieter-Augustijn Van Malleghem Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3ef476070ba..60c748a32ed 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -72,6 +72,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookAir3,1, MacBookAir3,2 */ { USB_DEVICE(0x05ac, 0x821b) }, + /* Apple MacBookAir4,1 */ + { USB_DEVICE(0x05ac, 0x821f) }, + /* Apple MacBookPro8,2 */ { USB_DEVICE(0x05ac, 0x821a) }, -- cgit v1.2.3-70-g09d2 From f78b68261e80899f81a21dfdf91e2a1456ea8175 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Sun, 4 Sep 2011 18:01:42 +0200 Subject: Bluetooth: add support for 2011 mac mini Today I noticed that the usb bluetooth adapter (BCM2046B1) on my 2011 mac mini was not working. I've created a patch to get it going. Signed-off-by: Jurgen Kramer Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 60c748a32ed..9cbac6b445e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -78,6 +78,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookPro8,2 */ { USB_DEVICE(0x05ac, 0x821a) }, + /* Apple MacMini5,1 */ + { USB_DEVICE(0x05ac, 0x8281) }, + /* AVM BlueFRITZ! USB v2.0 */ { USB_DEVICE(0x057c, 0x3800) }, -- cgit v1.2.3-70-g09d2 From 18b4fada275dd2b6dd9db904ddf70fe39e272222 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Sep 2011 12:04:07 -0400 Subject: drm/radeon/kms: fix typo in r100_blit_copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cur_pages is the number of pages per loop iteration. Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 11e44a3479e..a536505342d 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -773,8 +773,8 @@ int r100_copy_blit(struct radeon_device *rdev, radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); - radeon_ring_write(rdev, num_pages); - radeon_ring_write(rdev, num_pages); + radeon_ring_write(rdev, cur_pages); + radeon_ring_write(rdev, cur_pages); radeon_ring_write(rdev, cur_pages | (stride_pixels << 16)); } radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); -- cgit v1.2.3-70-g09d2 From 003cefe0c238e683a29d2207dba945b508cd45b7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 16 Sep 2011 12:04:08 -0400 Subject: drm/radeon/kms: Make GPU/CPU page size handling consistent in blit code (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BO blit code inconsistenly handled the page size. This wasn't an issue on system with 4k pages since the GPU's page size is 4k as well. Switch the driver blit callbacks to take num pages in GPU page units. Fixes lemote mipsel systems using AMD rs780/rs880 chipsets. v2: incorporate suggestions from Michel. Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 10 ++++++---- drivers/gpu/drm/radeon/r100.c | 12 ++++++------ drivers/gpu/drm/radeon/r200.c | 4 ++-- drivers/gpu/drm/radeon/r600.c | 10 ++++++---- drivers/gpu/drm/radeon/radeon.h | 7 ++++--- drivers/gpu/drm/radeon/radeon_asic.h | 8 ++++---- drivers/gpu/drm/radeon/radeon_ttm.c | 7 ++++++- 7 files changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f10d1c1c255..e8a746712b5 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3171,21 +3171,23 @@ int evergreen_suspend(struct radeon_device *rdev) } int evergreen_copy_blit(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, struct radeon_fence *fence) + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence *fence) { int r; mutex_lock(&rdev->r600_blit.mutex); rdev->r600_blit.vb_ib = NULL; - r = evergreen_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + r = evergreen_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE); if (r) { if (rdev->r600_blit.vb_ib) radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); mutex_unlock(&rdev->r600_blit.mutex); return r; } - evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); + evergreen_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE); evergreen_blit_done_copy(rdev, fence); mutex_unlock(&rdev->r600_blit.mutex); return 0; diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a536505342d..5b1837b4aac 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -721,11 +721,11 @@ void r100_fence_ring_emit(struct radeon_device *rdev, int r100_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence) { uint32_t cur_pages; - uint32_t stride_bytes = PAGE_SIZE; + uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE; uint32_t pitch; uint32_t stride_pixels; unsigned ndw; @@ -737,7 +737,7 @@ int r100_copy_blit(struct radeon_device *rdev, /* radeon pitch is /64 */ pitch = stride_bytes / 64; stride_pixels = stride_bytes / 4; - num_loops = DIV_ROUND_UP(num_pages, 8191); + num_loops = DIV_ROUND_UP(num_gpu_pages, 8191); /* Ask for enough room for blit + flush + fence */ ndw = 64 + (10 * num_loops); @@ -746,12 +746,12 @@ int r100_copy_blit(struct radeon_device *rdev, DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw); return -EINVAL; } - while (num_pages > 0) { - cur_pages = num_pages; + while (num_gpu_pages > 0) { + cur_pages = num_gpu_pages; if (cur_pages > 8191) { cur_pages = 8191; } - num_pages -= cur_pages; + num_gpu_pages -= cur_pages; /* pages are in Y direction - height page width in X direction - width */ diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c index f2405830041..a1f3ba063c2 100644 --- a/drivers/gpu/drm/radeon/r200.c +++ b/drivers/gpu/drm/radeon/r200.c @@ -84,7 +84,7 @@ static int r200_get_vtx_size_0(uint32_t vtx_fmt_0) int r200_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence) { uint32_t size; @@ -93,7 +93,7 @@ int r200_copy_dma(struct radeon_device *rdev, int r = 0; /* radeon pitch is /64 */ - size = num_pages << PAGE_SHIFT; + size = num_gpu_pages << RADEON_GPU_PAGE_SHIFT; num_loops = DIV_ROUND_UP(size, 0x1FFFFF); r = radeon_ring_lock(rdev, num_loops * 4 + 64); if (r) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c68427612e3..720dd99163f 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2353,21 +2353,23 @@ void r600_fence_ring_emit(struct radeon_device *rdev, } int r600_copy_blit(struct radeon_device *rdev, - uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, struct radeon_fence *fence) + uint64_t src_offset, + uint64_t dst_offset, + unsigned num_gpu_pages, + struct radeon_fence *fence) { int r; mutex_lock(&rdev->r600_blit.mutex); rdev->r600_blit.vb_ib = NULL; - r = r600_blit_prepare_copy(rdev, num_pages * RADEON_GPU_PAGE_SIZE); + r = r600_blit_prepare_copy(rdev, num_gpu_pages * RADEON_GPU_PAGE_SIZE); if (r) { if (rdev->r600_blit.vb_ib) radeon_ib_free(rdev, &rdev->r600_blit.vb_ib); mutex_unlock(&rdev->r600_blit.mutex); return r; } - r600_kms_blit_copy(rdev, src_offset, dst_offset, num_pages * RADEON_GPU_PAGE_SIZE); + r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages * RADEON_GPU_PAGE_SIZE); r600_blit_done_copy(rdev, fence); mutex_unlock(&rdev->r600_blit.mutex); return 0; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 32807baf55e..c1e056b35b2 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -322,6 +322,7 @@ union radeon_gart_table { #define RADEON_GPU_PAGE_SIZE 4096 #define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1) +#define RADEON_GPU_PAGE_SHIFT 12 struct radeon_gart { dma_addr_t table_addr; @@ -914,17 +915,17 @@ struct radeon_asic { int (*copy_blit)(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence); int (*copy_dma)(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence); int (*copy)(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence); uint32_t (*get_engine_clock)(struct radeon_device *rdev); void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock); diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3d7a0d7c6a9..3dedaa07aac 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -75,7 +75,7 @@ uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg); int r100_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence); int r100_set_surface_reg(struct radeon_device *rdev, int reg, uint32_t tiling_flags, uint32_t pitch, @@ -143,7 +143,7 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); extern int r200_copy_dma(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, + unsigned num_gpu_pages, struct radeon_fence *fence); void r200_set_safe_registers(struct radeon_device *rdev); @@ -311,7 +311,7 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int r600_ring_test(struct radeon_device *rdev); int r600_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, struct radeon_fence *fence); + unsigned num_gpu_pages, struct radeon_fence *fence); void r600_hpd_init(struct radeon_device *rdev); void r600_hpd_fini(struct radeon_device *rdev); bool r600_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); @@ -403,7 +403,7 @@ void evergreen_bandwidth_update(struct radeon_device *rdev); void evergreen_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int evergreen_copy_blit(struct radeon_device *rdev, uint64_t src_offset, uint64_t dst_offset, - unsigned num_pages, struct radeon_fence *fence); + unsigned num_gpu_pages, struct radeon_fence *fence); void evergreen_hpd_init(struct radeon_device *rdev); void evergreen_hpd_fini(struct radeon_device *rdev); bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 9b86fb0e412..0b5468bfaf5 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -277,7 +277,12 @@ static int radeon_move_blit(struct ttm_buffer_object *bo, DRM_ERROR("Trying to move memory with CP turned off.\n"); return -EINVAL; } - r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence); + + BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0); + + r = radeon_copy(rdev, old_start, new_start, + new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE), /* GPU pages */ + fence); /* FIXME: handle copy error */ r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL, evict, no_wait_reserve, no_wait_gpu, new_mem); -- cgit v1.2.3-70-g09d2 From 8c23516fbb209ccf8f8c36268311c721faff29ee Mon Sep 17 00:00:00 2001 From: Manual Munz Date: Sun, 18 Sep 2011 18:24:03 -0500 Subject: b43: Fix beacon problem in ad-hoc mode In ad-hoc mode, driver b43 does not issue beacons. Signed-off-by: Manual Munz Tested-by: Larry Finger Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 26f1ab840cc..e293a7921bf 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -1632,7 +1632,8 @@ static void handle_irq_beacon(struct b43_wldev *dev) u32 cmd, beacon0_valid, beacon1_valid; if (!b43_is_mode(wl, NL80211_IFTYPE_AP) && - !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) + !b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) && + !b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) return; /* This is the bottom half of the asynchronous beacon update. */ -- cgit v1.2.3-70-g09d2 From c19cc78efe922e86da7ba694dbfc4be066dd7eb4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 19 Sep 2011 16:05:10 -0700 Subject: staging: fix comedi build when ISA_DMA_API is enabled but COMEDI_PCI is not enabled Fix build when CONFIG_ISA_DMA_API is enabled but CONFIG_COMEDI_PCI[_DRIVERS] is not enabled. Fixes these build errors: drivers/staging/comedi/drivers/ni_labpc.c: In function 'labpc_ai_cmd': drivers/staging/comedi/drivers/ni_labpc.c:1351: error: implicit declaration of function 'labpc_suggest_transfer_size' drivers/staging/comedi/drivers/ni_labpc.c: At top level: drivers/staging/comedi/drivers/ni_labpc.c:1802: error: conflicting types for 'labpc_suggest_transfer_size' drivers/staging/comedi/drivers/ni_labpc.c:1351: note: previous implicit declaration of 'labpc_suggest_transfer_size' was here Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/staging/comedi/drivers/ni_labpc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 6859af0778c..7611def97d0 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -241,8 +241,10 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data); static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); -#ifdef CONFIG_COMEDI_PCI +#ifdef CONFIG_ISA_DMA_API static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd); +#endif +#ifdef CONFIG_COMEDI_PCI static int labpc_find_device(struct comedi_device *dev, int bus, int slot); #endif static int labpc_dio_mem_callback(int dir, int port, int data, -- cgit v1.2.3-70-g09d2 From 44f4c3ed60fb21e1d2dd98304390ac121e6c7c6d Mon Sep 17 00:00:00 2001 From: Greg KH Date: Mon, 19 Sep 2011 16:05:11 -0700 Subject: USB: xhci: Set change bit when warm reset change is set. Sometimes, when a USB 3.0 device is disconnected, the Intel Panther Point xHCI host controller will report a link state change with the state set to "SS.Inactive". This causes the xHCI host controller to issue a warm port reset, which doesn't finish before the USB core times out while waiting for it to complete. When the warm port reset does complete, and the xHC gives back a port status change event, the xHCI driver kicks khubd. However, it fails to set the bit indicating there is a change event for that port because the logic in xhci-hub.c doesn't check for the warm port reset bit. After that, the warm port status change bit is never cleared by the USB core, and the xHC stops reporting port status change bits. (The xHCI spec says it shouldn't report more port events until all change bits are cleared.) This means any port changes when a new device is connected will never be reported, and the port will seem "dead" until the xHCI driver is unloaded and reloaded, or the computer is rebooted. Fix this by making the xHCI driver set the port change bit when a warm port reset change bit is set. A better solution would be to make the USB core handle warm port reset in differently, merging the current code with the standard port reset code that does an incremental backoff on the timeout, and tries to complete the port reset two more times before giving up. That more complicated fix will be merged next window, and this fix will be backported to stable. This should be backported to kernels as old as 3.0, since that was the first kernel with commit a11496ebf375 ("xHCI: warm reset support"). Signed-off-by: Sarah Sharp Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 1e96d1f1fe6..723f8231193 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -761,7 +761,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) memset(buf, 0, retval); status = 0; - mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC; + mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ -- cgit v1.2.3-70-g09d2 From c2d7b49f42f50d7fc5cbfd195b785a128723fdf4 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 19 Sep 2011 16:05:12 -0700 Subject: USB: xHCI: prevent infinite loop when processing MSE event When a xHC host is unable to handle isochronous transfer in the interval, it reports a Missed Service Error event and skips some tds. Currently xhci driver handles MSE event in the following ways: 1. When encounter a MSE event, set ep->skip flag, update event ring dequeue pointer and return. 2. When encounter the next event on this ep, the driver will run the do-while loop, fetch td from ep's td_list to find the td corresponding to this event. All tds missed are marked as short transfer(-EXDEV). The do-while loop will end in two ways: 1. If the td pointed by the event trb is found; 2. If the ep ring's td_list is empty. However, if a buggy HW reports some unpredicted event (for example, an overrun event following a MSE event while the ep ring is actually not empty), the driver will never find the td, and it will loop until the td_list is empty. Unfortunately, the spinlock is dropped when give back a urb in the do-while loop. During the spinlock released period, the class driver may still submit urbs and add tds to the td_list. This may cause disaster, since the td_list will never be empty and the loop never ends, and the system hangs. To fix this, count the number of TDs on the ep ring before skipping TDs, and quit the loop when skipped that number of tds. This guarantees the do-while loop will end after certain number of cycles, and driver will not be trapped in an infinite loop. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/xhci-ring.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 54139a2f06c..952e2ded61a 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1934,8 +1934,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, int status = -EINPROGRESS; struct urb_priv *urb_priv; struct xhci_ep_ctx *ep_ctx; + struct list_head *tmp; u32 trb_comp_code; int ret = 0; + int td_num = 0; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; @@ -1957,6 +1959,12 @@ static int handle_tx_event(struct xhci_hcd *xhci, return -ENODEV; } + /* Count current td numbers if ep->skip is set */ + if (ep->skip) { + list_for_each(tmp, &ep_ring->td_list) + td_num++; + } + event_dma = le64_to_cpu(event->buffer); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); /* Look for common error cases */ @@ -2068,7 +2076,18 @@ static int handle_tx_event(struct xhci_hcd *xhci, goto cleanup; } + /* We've skipped all the TDs on the ep ring when ep->skip set */ + if (ep->skip && td_num == 0) { + ep->skip = false; + xhci_dbg(xhci, "All tds on the ep_ring skipped. " + "Clear skip flag.\n"); + ret = 0; + goto cleanup; + } + td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + if (ep->skip) + td_num--; /* Is this a TRB in the currently executing TD? */ event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, -- cgit v1.2.3-70-g09d2 From 7cd015a0a37265e23bbdce7ce8f7e00507abe9ed Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 5 Sep 2011 11:53:21 -0700 Subject: drm/i915: Enable dither whenever display bpc < frame buffer bpc We want to enable dithering on any pipe where the frame buffer has more color resolution than the output device. The previous code was incorrectly clamping the frame buffer bpc to the display bpc, effectively disabling dithering all of the time as the computed frame buffer bpc would never be larger than the display bpc. Signed-off-by: Keith Packard Reported-by: Oliver Hartkopp Tested-by: Oliver Hartkopp --- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 56a8554d903..9fb4a40bd9e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4687,13 +4687,13 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, bpc = 6; /* min is 18bpp */ break; case 24: - bpc = min((unsigned int)8, display_bpc); + bpc = 8; break; case 30: - bpc = min((unsigned int)10, display_bpc); + bpc = 10; break; case 48: - bpc = min((unsigned int)12, display_bpc); + bpc = 12; break; default: DRM_DEBUG("unsupported depth, assuming 24 bits\n"); @@ -4701,10 +4701,12 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, break; } + display_bpc = min(display_bpc, bpc); + DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n", bpc, display_bpc); - *pipe_bpp = bpc * 3; + *pipe_bpp = display_bpc * 3; return display_bpc != bpc; } -- cgit v1.2.3-70-g09d2 From cb7efc02c6dbc3bfe9d5d1509ed790fc757e05a9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 3 Aug 2011 15:38:20 -0700 Subject: watchdog: WatchDog Timer Driver Core - use passed watchdog_device Use the passed watchdog_device instead of the static global variable when testing and setting the status in watchdog_ping, watchdog_start, and watchdog_stop. Note that the callers of these functions are actually passing the static global variable. Signed-off-by: H Hartley Sweeten Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/watchdog_dev.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index d33520d0b4c..1199da0f98c 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -59,7 +59,7 @@ static struct watchdog_device *wdd; static int watchdog_ping(struct watchdog_device *wddev) { - if (test_bit(WDOG_ACTIVE, &wdd->status)) { + if (test_bit(WDOG_ACTIVE, &wddev->status)) { if (wddev->ops->ping) return wddev->ops->ping(wddev); /* ping the watchdog */ else @@ -81,12 +81,12 @@ static int watchdog_start(struct watchdog_device *wddev) { int err; - if (!test_bit(WDOG_ACTIVE, &wdd->status)) { + if (!test_bit(WDOG_ACTIVE, &wddev->status)) { err = wddev->ops->start(wddev); if (err < 0) return err; - set_bit(WDOG_ACTIVE, &wdd->status); + set_bit(WDOG_ACTIVE, &wddev->status); } return 0; } @@ -105,18 +105,18 @@ static int watchdog_stop(struct watchdog_device *wddev) { int err = -EBUSY; - if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) { + if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) { pr_info("%s: nowayout prevents watchdog to be stopped!\n", - wdd->info->identity); + wddev->info->identity); return err; } - if (test_bit(WDOG_ACTIVE, &wdd->status)) { + if (test_bit(WDOG_ACTIVE, &wddev->status)) { err = wddev->ops->stop(wddev); if (err < 0) return err; - clear_bit(WDOG_ACTIVE, &wdd->status); + clear_bit(WDOG_ACTIVE, &wddev->status); } return 0; } -- cgit v1.2.3-70-g09d2 From dbc018eca386b4e2670fc3116feada19f3db664c Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Tue, 9 Aug 2011 22:27:26 +0000 Subject: watchdog: hpwdt: prevent multiple "NMI occurred" messages On platforms with no iCRU support don't print two, (possibly conflicting), "NMI occurred" messages when the firmware is unable to source the NMI. Please note that one of the enhancements to the v1.3.0 hpwdt driver is to panic and allow KDUMP to succeed even on NMIs that are unknown to the platform firmware. Signed-off-by: Naga Chumbalkar Reviewed-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 410fba45378..809cbda03d7 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -494,15 +494,16 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, asminline_call(&cmn_regs, cru_rom_addr); die_nmi_called = 1; spin_unlock_irqrestore(&rom_lock, rom_pl); + + if (allow_kdump) + hpwdt_stop(); + if (!is_icru) { if (cmn_regs.u1.ral == 0) { - printk(KERN_WARNING "hpwdt: An NMI occurred, " + panic("An NMI occurred, " "but unable to determine source.\n"); } } - - if (allow_kdump) - hpwdt_stop(); panic("An NMI occurred, please see the Integrated " "Management Log for details.\n"); -- cgit v1.2.3-70-g09d2 From 9cfce47b146cb492b8d5e7b40d6f7b3ea1963d50 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 24 Aug 2011 10:31:39 +0200 Subject: watchdog: lantiq: fix watchdogs timeout handling The enable function was using the global timeout variable for local operations. This resulted in the value of the global variable being corrupted, thus breaking the code. Signed-off-by: John Crispin Signed-off-by: Thomas Langer Signed-off-by: Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org Cc: linux-mips@linux-mips.org --- drivers/watchdog/lantiq_wdt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 7d82adac1cb..102aed0efbf 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -51,16 +51,16 @@ static int ltq_wdt_ok_to_close; static void ltq_wdt_enable(void) { - ltq_wdt_timeout = ltq_wdt_timeout * + unsigned long int timeout = ltq_wdt_timeout * (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; - if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT) - ltq_wdt_timeout = LTQ_MAX_TIMEOUT; + if (timeout > LTQ_MAX_TIMEOUT) + timeout = LTQ_MAX_TIMEOUT; /* write the first password magic */ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); /* write the second magic plus the configuration and new timeout */ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | - LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR); + LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR); } static void -- cgit v1.2.3-70-g09d2 From 4e8858d5130459c4af80b990c2280115a1d49877 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 15 Sep 2011 13:09:51 -0700 Subject: watchdog: Initconst section fixes for watchdog Signed-off-by: Andi Kleen Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/sbc_epx_c3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c index 3066a5127ca..eaca366b723 100644 --- a/drivers/watchdog/sbc_epx_c3.c +++ b/drivers/watchdog/sbc_epx_c3.c @@ -173,7 +173,7 @@ static struct notifier_block epx_c3_notifier = { .notifier_call = epx_c3_notify_sys, }; -static const char banner[] __initdata = KERN_INFO PFX +static const char banner[] __initconst = KERN_INFO PFX "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n"; static int __init watchdog_init(void) -- cgit v1.2.3-70-g09d2 From 6af29a963cecf426966d56935d60a984bd5594ea Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Thu, 8 Sep 2011 03:14:35 +0000 Subject: GRETH: RX/TX bytes were never increased Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- drivers/net/greth.c | 5 +++++ drivers/net/greth.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 16ce45c1193..58ec74a7315 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -428,6 +428,7 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev) dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE); status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN); + greth->tx_bufs_length[greth->tx_next] = skb->len & GRETH_BD_LEN; /* Wrap around descriptor ring */ if (greth->tx_next == GRETH_TXBD_NUM_MASK) { @@ -641,6 +642,7 @@ static void greth_clean_tx(struct net_device *dev) dev->stats.tx_fifo_errors++; } dev->stats.tx_packets++; + dev->stats.tx_bytes += greth->tx_bufs_length[greth->tx_last]; greth->tx_last = NEXT_TX(greth->tx_last); greth->tx_free++; } @@ -695,6 +697,7 @@ static void greth_clean_tx_gbit(struct net_device *dev) greth->tx_skbuff[greth->tx_last] = NULL; greth_update_tx_stats(dev, stat); + dev->stats.tx_bytes += skb->len; bdp = greth->tx_bd_base + greth->tx_last; @@ -796,6 +799,7 @@ static int greth_rx(struct net_device *dev, int limit) memcpy(skb_put(skb, pkt_len), phys_to_virt(dma_addr), pkt_len); skb->protocol = eth_type_trans(skb, dev); + dev->stats.rx_bytes += pkt_len; dev->stats.rx_packets++; netif_receive_skb(skb); } @@ -910,6 +914,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit) skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; netif_receive_skb(skb); greth->rx_skbuff[greth->rx_cur] = newskb; diff --git a/drivers/net/greth.h b/drivers/net/greth.h index 9a0040dee4d..232a622a85b 100644 --- a/drivers/net/greth.h +++ b/drivers/net/greth.h @@ -103,6 +103,7 @@ struct greth_private { unsigned char *tx_bufs[GRETH_TXBD_NUM]; unsigned char *rx_bufs[GRETH_RXBD_NUM]; + u16 tx_bufs_length[GRETH_TXBD_NUM]; u16 tx_next; u16 tx_last; -- cgit v1.2.3-70-g09d2 From d706f00f65146822c0097b796b3557ea8980c305 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Fri, 9 Sep 2011 05:17:54 +0000 Subject: GRETH: avoid overwrite IP-stack's IP-frags checksum The GRETH GBIT core does not do checksum offloading for IP segmentation. This patch adds a check in the xmit function to determine if the stack has calculated the checksum for us. Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- drivers/net/greth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/greth.c b/drivers/net/greth.c index 58ec74a7315..52a39000c42 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -491,7 +491,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) if (nr_frags != 0) status = GRETH_TXBD_MORE; - status |= GRETH_TXBD_CSALL; + if (skb->ip_summed == CHECKSUM_PARTIAL) + status |= GRETH_TXBD_CSALL; status |= skb_headlen(skb) & GRETH_BD_LEN; if (greth->tx_next == GRETH_TXBD_NUM_MASK) status |= GRETH_BD_WR; @@ -514,7 +515,9 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev) greth->tx_skbuff[curr_tx] = NULL; bdp = greth->tx_bd_base + curr_tx; - status = GRETH_TXBD_CSALL | GRETH_BD_EN; + status = GRETH_BD_EN; + if (skb->ip_summed == CHECKSUM_PARTIAL) + status |= GRETH_TXBD_CSALL; status |= frag->size & GRETH_BD_LEN; /* Wrap around descriptor ring */ -- cgit v1.2.3-70-g09d2 From 22e83a2926998fe132ae4dd26f1e998c70ae2e38 Mon Sep 17 00:00:00 2001 From: Henry Wong Date: Sun, 18 Sep 2011 13:41:49 +0000 Subject: ppp_generic: fix multilink fragment MTU calculation (again) When using MLPPP, the maximum size of a fragment is incorrectly calculated with an offset of -2. This patch reverses the changes in the patch found here: http://marc.info/?l=linux-netdev&m=123541324010539&w=2 The value of hdrlen includes the size of both the 2-byte PPP protocol field and the 2- or 4-byte multilink header (2+4=6 for long sequence numbers, 2+2=4 for short sequence numbers). Section 2 of RFC1661 says that the MRU that is negotiated (i.e., the MTU of the sending system) includes only the PPP payload but not the protocol field, thus the correct MTU should be the link's MTU minus the multilink header (mtu - (hdrlen-2)). The incorrect calculation causes Linux to fragment packets to a size two bytes smaller than the allowed MTU. While not technically illegal, this behaviour confounds MRU-tuning to avoid PPP-layer fragmentation. Signed-off-by: Henry Wong Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 10e5d985afa..edfa15d2e79 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1465,7 +1465,12 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) continue; } - mtu = pch->chan->mtu - hdrlen; + /* + * hdrlen includes the 2-byte PPP protocol field, but the + * MTU counts only the payload excluding the protocol field. + * (RFC1661 Section 2) + */ + mtu = pch->chan->mtu - (hdrlen - 2); if (mtu < 4) mtu = 4; if (flen > mtu) -- cgit v1.2.3-70-g09d2 From 710778ff878a06654175863db133293007d45aee Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 6 Sep 2011 12:44:25 +0000 Subject: gianfar: Fix overflow check and return value for gfar_get_cls_all() This function may currently fill one entry beyond the end of the array it is given. It also doesn't return an error code in case it does detect overflow. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/gianfar_ethtool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index 25a8c2adb00..0caf3c323ec 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -1669,10 +1669,10 @@ static int gfar_get_cls_all(struct gfar_private *priv, u32 i = 0; list_for_each_entry(comp, &priv->rx_list.list, list) { - if (i <= cmd->rule_cnt) { - rule_locs[i] = comp->fs.location; - i++; - } + if (i == cmd->rule_cnt) + return -EMSGSIZE; + rule_locs[i] = comp->fs.location; + i++; } cmd->data = MAX_FILER_IDX; -- cgit v1.2.3-70-g09d2 From 97c7de055713afddf4218f19c896b5185555da15 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Tue, 20 Sep 2011 15:45:07 -0400 Subject: netconsole: switch init_netconsole() to late_initcall Commit 88491d8(drivers/net: Kconfig & Makefile cleanup) causes a regression that netconsole does not work if netconsole and network device driver are build into kernel, because netconsole is linked before network device driver. Andrew Morton suggested to fix this with initcall ordering. Fixes it by switching init_netconsole() to late_initcall. Signed-off-by: Lin Ming Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfc82720065..ed2a3977c6e 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -799,5 +799,11 @@ static void __exit cleanup_netconsole(void) } } -module_init(init_netconsole); +/* + * Use late_initcall to ensure netconsole is + * initialized after network device driver if built-in. + * + * late_initcall() and module_init() are identical if built as module. + */ +late_initcall(init_netconsole); module_exit(cleanup_netconsole); -- cgit v1.2.3-70-g09d2 From b7e43381260e56840fd2fa582565c362d2fba1d9 Mon Sep 17 00:00:00 2001 From: Tanmay Upadhyay Date: Mon, 5 Sep 2011 19:32:04 +0000 Subject: net: pxa168: Fix build errors by including interrupt.h Commit a6b7a407865aab9f849dd99a71072b7cd1175116 removed linux/interrupt.h from netdevice.h. This fixes below build failure drivers/net/pxa168_eth.c: In function 'pxa168_eth_collect_events': drivers/net/pxa168_eth.c:866: error: 'IRQ_NONE' undeclared (first use in this function) drivers/net/pxa168_eth.c:866: error: (Each undeclared identifier is reported only once drivers/net/pxa168_eth.c:866: error: for each function it appears in.) drivers/net/pxa168_eth.c: At top level: drivers/net/pxa168_eth.c:913: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'pxa168_eth_int_handler' drivers/net/pxa168_eth.c: In function 'pxa168_eth_open': drivers/net/pxa168_eth.c:1133: error: implicit declaration of function 'request_irq' drivers/net/pxa168_eth.c:1133: error: 'pxa168_eth_int_handler' undeclared (first use in this function) drivers/net/pxa168_eth.c:1134: error: 'IRQF_DISABLED' undeclared (first use in this function) drivers/net/pxa168_eth.c:1160: error: implicit declaration of function 'free_irq' Signed-off-by: Tanmay Upadhyay Signed-off-by: David S. Miller --- drivers/net/pxa168_eth.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 1a3033d8e7e..d17d0624c5e 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 80976804f501303a34a76e925119393722596dca Mon Sep 17 00:00:00 2001 From: Seth Jennings Date: Tue, 20 Sep 2011 13:09:56 -0700 Subject: staging: zcache: fix cleancache crash After commit c5f5c4db3938 ("staging: zcache: fix crash on high memory swap") cleancache crashes on the first successful get. This was caused by a remaining virt_to_page() call in zcache_pampd_get_data_and_free() that only gets run in the cleancache path. The patch converts the virt_to_page() to struct page casting like was done for other instances in c5f5c4db3938. Signed-off-by: Seth Jennings Tested-By: Valdis Kletnieks Acked-by: Dan Magenheimer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/staging/zcache/zcache-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c index a3f5162bfed..462fbc20561 100644 --- a/drivers/staging/zcache/zcache-main.c +++ b/drivers/staging/zcache/zcache-main.c @@ -1242,7 +1242,7 @@ static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, int ret = 0; BUG_ON(!is_ephemeral(pool)); - zbud_decompress(virt_to_page(data), pampd); + zbud_decompress((struct page *)(data), pampd); zbud_free_and_delist((struct zbud_hdr *)pampd); atomic_dec(&zcache_curr_eph_pampd_count); return ret; -- cgit v1.2.3-70-g09d2 From 5c1e688388f629e8d8e88183b5ebc21e209252aa Mon Sep 17 00:00:00 2001 From: Kasper Pedersen Date: Tue, 20 Sep 2011 12:41:17 +0000 Subject: tg3: fix VLAN tagging regression commit 92cd3a17ce9c719abb4c28dee3438e0c641f8de4 tg3: Simplify tx bd assignments broke VLAN tagging on outbound packets. It ifdef'ed BCM_KERNEL_SUPPORTS_8021Q, but this is not set anywhere. So vlan never gets set, and all packets are sent with vlan=0. v2: We can just remove the test. vlan_tx_tag_present is valid regardless of whether the 802.1q module is built. Tested on BCM5721 rev 11. Signed-off-by: Kasper Pedersen Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index dc3fbf61910..4a1374df608 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6234,12 +6234,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) } } -#ifdef BCM_KERNEL_SUPPORTS_8021Q if (vlan_tx_tag_present(skb)) { base_flags |= TXD_FLAG_VLAN; vlan = vlan_tx_tag_get(skb); } -#endif if (tg3_flag(tp, USE_JUMBO_BDFLAG) && !mss && skb->len > VLAN_ETH_FRAME_LEN) -- cgit v1.2.3-70-g09d2 From b811ce9104a7f7663ddae4f7795a194a103b8f90 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Tue, 20 Sep 2011 15:13:03 +0000 Subject: ixgbe: fix possible null buffer error It seems that at least one PPC machine would occasionally give a (valid) 0 as the return value from dma_map, this caused the ixgbe code to not work correctly. A fix is pending in the PPC tree to not return 0 from dma map, but we can also fix the driver to make sure we don't mess up in other arches as well. This patch is applicable to all current stable kernels. Ref: https://bugzilla.redhat.com/show_bug.cgi?id=683611 Reported-by: Neil Horman Signed-off-by: Jesse Brandeburg CC: Alexander Duyck CC: stable@kernel.org Tested-by: Thadeu Lima de Souza Cascardo Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- drivers/net/ixgbe/ixgbe_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 22790394318..e1fcc958927 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -1321,8 +1321,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, if (ring_is_rsc_enabled(rx_ring)) pkt_is_rsc = ixgbe_get_rsc_state(rx_desc); - /* if this is a skb from previous receive DMA will be 0 */ - if (rx_buffer_info->dma) { + /* linear means we are building an skb from multiple pages */ + if (!skb_is_nonlinear(skb)) { u16 hlen; if (pkt_is_rsc && !(staterr & IXGBE_RXD_STAT_EOP) && -- cgit v1.2.3-70-g09d2 From 6c4867f6469964e34c5f4ee229a2a7f71a34c7ff Mon Sep 17 00:00:00 2001 From: Carsten Emde Date: Wed, 21 Sep 2011 10:22:11 +0200 Subject: floppy: use del_timer_sync() in init cleanup When no floppy is found the module code can be released while a timer function is pending or about to be executed. CPU0 CPU1 floppy_init() timer_softirq() spin_lock_irq(&base->lock); detach_timer(); spin_unlock_irq(&base->lock); -> Interrupt del_timer(); return -ENODEV; module_cleanup(); <- EOI call_timer_fn(); OOPS Use del_timer_sync() to prevent this. Signed-off-by: Carsten Emde Signed-off-by: Thomas Gleixner Cc: Jens Axboe Cc: Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/floppy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 98de8f41867..9955a53733b 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4250,7 +4250,7 @@ static int __init floppy_init(void) use_virtual_dma = can_use_virtual_dma & 1; fdc_state[0].address = FDC1; if (fdc_state[0].address == -1) { - del_timer(&fd_timeout); + del_timer_sync(&fd_timeout); err = -ENODEV; goto out_unreg_region; } @@ -4261,7 +4261,7 @@ static int __init floppy_init(void) fdc = 0; /* reset fdc in case of unexpected interrupt */ err = floppy_grab_irq_and_dma(); if (err) { - del_timer(&fd_timeout); + del_timer_sync(&fd_timeout); err = -EBUSY; goto out_unreg_region; } @@ -4318,7 +4318,7 @@ static int __init floppy_init(void) user_reset_fdc(-1, FD_RESET_ALWAYS, false); } fdc = 0; - del_timer(&fd_timeout); + del_timer_sync(&fd_timeout); current_drive = 0; initialized = true; if (have_no_fdc) { @@ -4368,7 +4368,7 @@ out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: while (dr--) { - del_timer(&motor_off_timer[dr]); + del_timer_sync(&motor_off_timer[dr]); if (disks[dr]->queue) blk_cleanup_queue(disks[dr]->queue); put_disk(disks[dr]); -- cgit v1.2.3-70-g09d2 From 6fcb8a3a3a542ca078dc739fe0ea97191bc59e74 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 19 Sep 2011 16:17:55 +0200 Subject: mfd: Fix generic irq chip ack function name for jz4740-adc In commit 659fb32d1b6("genirq: replace irq_gc_ack() with {set,clr}_bit variants"), irq_gc_ack was renamed to irq_gc_ack_set_bit. The jz4740-adc driver still uses the old name which results in a compile error. Signed-off-by: Lars-Peter Clausen Signed-off-by: Samuel Ortiz --- drivers/mfd/jz4740-adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 21131c7b0f1..563654c9b19 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -273,7 +273,7 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) ct->regs.ack = JZ_REG_ADC_STATUS; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_ack = irq_gc_ack; + ct->chip.irq_ack = irq_gc_ack_set_bit; irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); -- cgit v1.2.3-70-g09d2 From e9f9530bb697f53dd620df290102359a3325bb23 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Tue, 20 Sep 2011 16:23:51 +0530 Subject: ath9k_hw: Fix Rx DMA stuck for AR9003 chips During the endurance testing, rx frames are not getting DMAd from MAC whereas pcu rx frame counters are getting updated properly. As per systems team input updated the initval to fix rx dma stuck issue. Cc: stable@kernel.org Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 2339728a730..3e69c631ebb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = { {0x00008258, 0x00000000}, {0x0000825c, 0x40000000}, {0x00008260, 0x00080922}, - {0x00008264, 0x9bc00010}, + {0x00008264, 0x9d400010}, {0x00008268, 0xffffffff}, {0x0000826c, 0x0000ffff}, {0x00008270, 0x00000000}, -- cgit v1.2.3-70-g09d2 From 2e2a41d6ca07d1b2aa67015c35fd80701c98e867 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 20 Sep 2011 16:46:36 +0200 Subject: iwlegacy: fix command queue timeout iwlegacy version of fix: commit 282cdb325aea4ebbc42ce753b47cc96145eb54bc Author: Johannes Berg Date: Mon Sep 12 12:09:10 2011 -0700 iwlagn: fix command queue timeout If the command queue is constantly busy, which can happen in P2P, the hangcheck timer will frequently find a command in it and will eventually reset the device because nothing sets the timestamp for this queue when commands are processed. Fix this by setting the timestamp when a command completes. iwlegacy does not support P2P, but this patch fix possible unneeded hardware resets, hence is needed. Cc: stable@kernel.org # 2.6.39+ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-tx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index 4fff995c6f3..4b4489f746a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; + txq->time_stamp = jiffies; + pci_unmap_single(priv->pci_dev, dma_unmap_addr(meta, mapping), dma_unmap_len(meta, len), -- cgit v1.2.3-70-g09d2 From 65d0f19e583e80e42b1c67c166bfc4dfdf6ab693 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 20 Sep 2011 16:49:03 +0200 Subject: iwlegacy: do not use interruptible waits iwlegacy version of fix: commit effd4d9aece9184f526e6556786a94d335e38b71 Author: Johannes Berg Date: Thu Sep 15 11:46:52 2011 -0700 iwlagn: do not use interruptible waits Since the dawn of its time, iwlwifi has used interruptible waits to wait for synchronous commands and firmware loading. This leads to "interesting" bugs, because it can't actually handle the interruptions; for example when a command sending is interrupted it will assume the command completed fully, and then leave it pending, which leads to all kinds of trouble when the command finishes later. Since there's no easy way to gracefully deal with interruptions, fix the driver to not use interruptible waits. This at least fixes the error iwlagn 0000:02:00.0: Error: Response NULL in 'REPLY_SCAN_ABORT_CMD' I have seen in P2P testing, but it is likely that there are other errors caused by this. Cc: stable@kernel.org # 2.6.39+ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-core.c | 4 ++-- drivers/net/wireless/iwlegacy/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlegacy/iwl-tx.c | 2 +- drivers/net/wireless/iwlegacy/iwl3945-base.c | 8 ++++---- drivers/net/wireless/iwlegacy/iwl4965-base.c | 10 +++++----- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 35cd2537e7f..e5971fe9d16 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv) &priv->contexts[IWL_RXON_CTX_BSS]); #endif - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); /* Keep the restart process from trying to send host * commands by clearing the INIT status bit */ @@ -1746,7 +1746,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external) /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); /* * Keep the restart process from trying to send host * commands by clearing the INIT status bit diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c index 62b4b09122c..ce1fc9feb61 100644 --- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c +++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c @@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) goto out; } - ret = wait_event_interruptible_timeout(priv->wait_command_queue, + ret = wait_event_timeout(priv->wait_command_queue, !test_bit(STATUS_HCMD_ACTIVE, &priv->status), HOST_COMPLETE_TIMEOUT); if (!ret) { diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index 4b4489f746a..ef9e268bf8a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -647,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", iwl_legacy_get_cmd_string(cmd->hdr.cmd)); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } /* Mark as unmapped */ diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 795826a014e..66ee15629a7 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -841,7 +841,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); else - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } /** @@ -2269,7 +2269,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv) iwl3945_reg_txpower_periodic(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); return; @@ -2300,7 +2300,7 @@ static void __iwl3945_down(struct iwl_priv *priv) iwl_legacy_clear_driver_stations(priv); /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); + wake_up_all(&priv->wait_command_queue); /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ @@ -2853,7 +2853,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw) /* Wait for START_ALIVE from ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, + ret = wait_event_timeout(priv->wait_command_queue, test_bit(STATUS_READY, &priv->status), UCODE_READY_TIMEOUT); if (!ret) { diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 14334668034..aa0c2539761 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -576,7 +576,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); else - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } /** @@ -926,7 +926,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_FH_TX; /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } if (inta & ~handled) { @@ -1795,7 +1795,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv) iwl4965_rf_kill_ct_config(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); iwl_legacy_power_update_mode(priv, true); IWL_DEBUG_INFO(priv, "Updated power mode\n"); @@ -1828,7 +1828,7 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl_legacy_clear_driver_stations(priv); /* Unblock any waiting calls */ - wake_up_interruptible_all(&priv->wait_command_queue); + wake_up_all(&priv->wait_command_queue); /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ @@ -2266,7 +2266,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw) /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, + ret = wait_event_timeout(priv->wait_command_queue, test_bit(STATUS_READY, &priv->status), UCODE_READY_TIMEOUT); if (!ret) { -- cgit v1.2.3-70-g09d2 From cc68c81aed7d892deaf12d720d5455208e94cd0a Mon Sep 17 00:00:00 2001 From: Simon Farnsworth Date: Wed, 21 Sep 2011 17:13:30 +0100 Subject: drm/i915: Enable SDVO hotplug interrupts for HDMI and DVI I was seeing a nasty 5 frame glitch every 10 seconds, caused by the poll for connection on DVI attached by SDVO. As my SDVO DVI supports hotplug detect interrupts, the fix is to enable them, and hook them in to the various bits of driver infrastructure so that they work reliably. Note that this is only tested on single-function DVI-D SDVOs, on two platforms (965GME and 945GSE), and has not been checked against a specification document. With lots of help from Adam Jackson on IRC. Signed-off-by: Simon Farnsworth Reviewed-by: Keith Packard Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_drv.h | 3 -- drivers/gpu/drm/i915/intel_sdvo.c | 88 +++++++++++++-------------------------- 2 files changed, 29 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0b2ee9d3998..fe1099d8817 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -337,9 +337,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, struct drm_connector *connector, struct intel_load_detect_pipe *old); -extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); -extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); -extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); extern void intelfb_restore(void); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 30fe554d893..6348c499616 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -92,6 +92,11 @@ struct intel_sdvo { */ uint16_t attached_output; + /* + * Hotplug activation bits for this device + */ + uint8_t hotplug_active[2]; + /** * This is used to select the color range of RBG outputs in HDMI mode. * It is only valid when using TMDS encoding and 8 bit per color mode. @@ -1208,74 +1213,20 @@ static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct in return true; } -/* No use! */ -#if 0 -struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB) -{ - struct drm_connector *connector = NULL; - struct intel_sdvo *iout = NULL; - struct intel_sdvo *sdvo; - - /* find the sdvo connector */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - iout = to_intel_sdvo(connector); - - if (iout->type != INTEL_OUTPUT_SDVO) - continue; - - sdvo = iout->dev_priv; - - if (sdvo->sdvo_reg == SDVOB && sdvoB) - return connector; - - if (sdvo->sdvo_reg == SDVOC && !sdvoB) - return connector; - - } - - return NULL; -} - -int intel_sdvo_supports_hotplug(struct drm_connector *connector) +static int intel_sdvo_supports_hotplug(struct intel_sdvo *intel_sdvo) { u8 response[2]; - u8 status; - struct intel_sdvo *intel_sdvo; - DRM_DEBUG_KMS("\n"); - - if (!connector) - return 0; - - intel_sdvo = to_intel_sdvo(connector); return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, &response, 2) && response[0]; } -void intel_sdvo_set_hotplug(struct drm_connector *connector, int on) +static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) { - u8 response[2]; - u8 status; - struct intel_sdvo *intel_sdvo = to_intel_sdvo(connector); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_sdvo, &response, 2); - - if (on) { - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); - status = intel_sdvo_read_response(intel_sdvo, &response, 2); - - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); - } else { - response[0] = 0; - response[1] = 0; - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); - } + struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); - intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); - intel_sdvo_read_response(intel_sdvo, &response, 2); + intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &intel_sdvo->hotplug_active, 2); } -#endif static bool intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) @@ -2045,6 +1996,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) { struct drm_encoder *encoder = &intel_sdvo->base.base; struct drm_connector *connector; + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); struct intel_connector *intel_connector; struct intel_sdvo_connector *intel_sdvo_connector; @@ -2062,7 +2014,17 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) { + connector->polled = DRM_CONNECTOR_POLL_HPD; + intel_sdvo->hotplug_active[0] |= 1 << device; + /* Some SDVO devices have one-shot hotplug interrupts. + * Ensure that they get re-enabled when an interrupt happens. + */ + intel_encoder->hot_plug = intel_sdvo_enable_hotplug; + intel_sdvo_enable_hotplug(intel_encoder); + } + else + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; encoder->encoder_type = DRM_MODE_ENCODER_TMDS; connector->connector_type = DRM_MODE_CONNECTOR_DVID; @@ -2569,6 +2531,14 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg) if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps)) goto err; + /* Set up hotplug command - note paranoia about contents of reply. + * We assume that the hardware is in a sane state, and only touch + * the bits we think we understand. + */ + intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ACTIVE_HOT_PLUG, + &intel_sdvo->hotplug_active, 2); + intel_sdvo->hotplug_active[0] &= ~0x3; + if (intel_sdvo_output_setup(intel_sdvo, intel_sdvo->caps.output_flags) != true) { DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n", -- cgit v1.2.3-70-g09d2 From cd0de039bff32ee314046c0e4c047c38aa696f84 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 19 Sep 2011 21:34:19 -0700 Subject: drm/i915: FBC off for ironlake and older, otherwise on by default Make the default FBC behaviour chipset specific, allowing us to turn it on by default for Ironlake and older where it has been seen to cause trouble with screen updates. Signed-off-by: Keith Packard Tested-by: Francis Moreau --- drivers/gpu/drm/i915/i915_drv.c | 4 ++-- drivers/gpu/drm/i915/intel_display.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ce045a8cf82..f07e4252b70 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -67,11 +67,11 @@ module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); MODULE_PARM_DESC(i915_enable_rc6, "Enable power-saving render C-state 6 (default: true)"); -unsigned int i915_enable_fbc __read_mostly = 1; +unsigned int i915_enable_fbc __read_mostly = -1; module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); MODULE_PARM_DESC(i915_enable_fbc, "Enable frame buffer compression for power savings " - "(default: false)"); + "(default: -1 (use per-chip default))"); unsigned int i915_lvds_downclock __read_mostly = 0; module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9fb4a40bd9e..04411ad2e77 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1799,6 +1799,7 @@ static void intel_update_fbc(struct drm_device *dev) struct drm_framebuffer *fb; struct intel_framebuffer *intel_fb; struct drm_i915_gem_object *obj; + int enable_fbc; DRM_DEBUG_KMS("\n"); @@ -1839,8 +1840,15 @@ static void intel_update_fbc(struct drm_device *dev) intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; - if (!i915_enable_fbc) { - DRM_DEBUG_KMS("fbc disabled per module param (default off)\n"); + enable_fbc = i915_enable_fbc; + if (enable_fbc < 0) { + DRM_DEBUG_KMS("fbc set to per-chip default\n"); + enable_fbc = 1; + if (INTEL_INFO(dev)->gen <= 5) + enable_fbc = 0; + } + if (!enable_fbc) { + DRM_DEBUG_KMS("fbc disabled per module param\n"); dev_priv->no_fbc_reason = FBC_MODULE_PARAM; goto out_disable; } -- cgit v1.2.3-70-g09d2 From 6bf9e9b09c3abb5447bbbf16c2d0cbe721e44f3f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 16 Sep 2011 21:21:43 +0200 Subject: hwmon: (coretemp) Drop duplicate function get_pkg_tjmax Function get_pkg_tjmax is a simplified copy of get_tjmax. Drop it and always use get_tjmax, result is the same and this avoids code duplication. Also make get_tjmax less verbose: don't warn about MSR read failure when failure was expected, and don't report TjMax in the logs unless debugging is enabled. Signed-off-by: Jean Delvare Cc: Fenghua Yu Cc: Guenter Roeck Cc: Durgadoss R Acked-by: Fenghua Yu Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 41125767613..256f70803eb 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -374,7 +374,6 @@ static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) { - /* The 100C is default for both mobile and non mobile CPUs */ int err; u32 eax, edx; u32 val; @@ -385,7 +384,8 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) */ err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); if (err) { - dev_warn(dev, "Unable to read TjMax from CPU.\n"); + if (c->x86_model > 0xe && c->x86_model != 0x1c) + dev_warn(dev, "Unable to read TjMax from CPU %u\n", id); } else { val = (eax >> 16) & 0xff; /* @@ -393,7 +393,7 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) * will be used */ if (val) { - dev_info(dev, "TjMax is %d C.\n", val); + dev_dbg(dev, "TjMax is %d degrees C\n", val); return val * 1000; } } @@ -414,21 +414,6 @@ static void __devinit get_ucode_rev_on_cpu(void *edx) rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx); } -static int get_pkg_tjmax(unsigned int cpu, struct device *dev) -{ - int err; - u32 eax, edx, val; - - err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); - if (!err) { - val = (eax >> 16) & 0xff; - if (val) - return val * 1000; - } - dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu); - return 100000; /* Default TjMax: 100 degree celsius */ -} - static int create_name_attr(struct platform_data *pdata, struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); @@ -588,10 +573,7 @@ static int create_core_data(struct platform_data *pdata, goto exit_free; /* We can access status register. Get Critical Temperature */ - if (pkg_flag) - tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev); - else - tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); + tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); /* * Test if we can access the intrpt register. If so, increase the -- cgit v1.2.3-70-g09d2 From a45a8c8571c0be6a6bd72ae5a14255c26b14b504 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 16 Sep 2011 21:24:02 +0200 Subject: hwmon: (coretemp) Let the user force TjMax On old CPUs (and even some recent Atom CPUs) TjMax can't be read from the CPU registers, so it is guessed by the driver using a complex heuristic which isn't reliable. So let users who know their CPU's TjMax pass it as a module parameter. Signed-off-by: Jean Delvare Cc: Fenghua Yu Cc: "R, Durgadoss" Cc: Guenter Roeck Cc: Alexander Stein Acked-by: Fenghua Yu Signed-off-by: Guenter Roeck --- Documentation/hwmon/coretemp | 7 ++++--- drivers/hwmon/coretemp.c | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index fa8776ab9b1..49c0d42dde8 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -49,9 +49,10 @@ tempX_label - Contains string "Core X", where X is processor number. For Package temp, this will be "Physical id Y", where Y is the package number. -The TjMax temperature is set to 85 degrees C if undocumented model specific -register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as -(sometimes) documented in processor datasheet. +On CPU models which support it, TjMax is read from a model-specific register. +On other models, it is set to an arbitrary value based on weak heuristics. +If these heuristics don't work for you, you can pass the correct TjMax value +as a module parameter (tjmax). Appendix A. Known TjMax lists (TBD): Some information comes from ark.intel.com diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 256f70803eb..5a41e9dda90 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -36,11 +36,20 @@ #include #include #include +#include #include #include #define DRVNAME "coretemp" +/* + * force_tjmax only matters when TjMax can't be read from the CPU itself. + * When set, it replaces the driver's suboptimal heuristic. + */ +static int force_tjmax; +module_param_named(tjmax, force_tjmax, int, 0444); +MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); + #define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */ #define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ #define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ @@ -398,6 +407,12 @@ static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) } } + if (force_tjmax) { + dev_notice(dev, "TjMax forced to %d degrees C by user\n", + force_tjmax); + return force_tjmax * 1000; + } + /* * An assumption is made for early CPUs and unreadable MSR. * NOTE: the calculated value may not be correct. -- cgit v1.2.3-70-g09d2 From f4af6fd6e21792ca4deca3d29c113a575594078e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 19 Sep 2011 21:41:16 -0700 Subject: hwmon: (coretemp) Don't use threshold registers for tempX_max With commit c814a4c7c4aad795835583344353963a0a673eb0, the meaning of tempX_max was changed. It no longer returns the value of bits 8:15 of MSR_IA32_TEMPERATURE_TARGET, but instead returns the value of CPU threshold register T1. tempX_max_hyst was added to reflect the value of temperature threshold register T0. As it turns out, T0 and T1 are used on some systems, presumably by the BIOS. Also, T0 and T1 don't have a well defined meaning. The thresholds may be used as upper or lower limits, and it is not guaranteed that T0 <= T1. Thus, the new attribute mapping does not reflect the actual usage of the threshold registers. Also, register contents are changed during runtime by an entity other than the hwmon driver, meaning the values cached by the driver do not reflect actual register contents. Revert most of c814a4c7c4aad795835583344353963a0a673eb0 to address the problem. Support for T0 and T1 will be added back in with a separate commit, using new attribute names. Signed-off-by: Guenter Roeck Cc: Fenghua Yu Cc: Durgadoss R Acked-by: Jean Delvare --- Documentation/hwmon/coretemp | 7 --- drivers/hwmon/coretemp.c | 135 +++++-------------------------------------- 2 files changed, 14 insertions(+), 128 deletions(-) (limited to 'drivers') diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index 49c0d42dde8..84d46c0c71a 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -35,13 +35,6 @@ the Out-Of-Spec bit. Following table summarizes the exported sysfs files: All Sysfs entries are named with their core_id (represented here by 'X'). tempX_input - Core temperature (in millidegrees Celsius). tempX_max - All cooling devices should be turned on (on Core2). - Initialized with IA32_THERM_INTERRUPT. When the CPU - temperature reaches this temperature, an interrupt is - generated and tempX_max_alarm is set. -tempX_max_hyst - If the CPU temperature falls below than temperature, - an interrupt is generated and tempX_max_alarm is reset. -tempX_max_alarm - Set if the temperature reaches or exceeds tempX_max. - Reset if the temperature drops to or below tempX_max_hyst. tempX_crit - Maximum junction temperature (in millidegrees Celsius). tempX_crit_alarm - Set when Out-of-spec bit is set, never clears. Correct CPU operation is no longer guaranteed. diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 5a41e9dda90..47364151e67 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -54,8 +54,7 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); #define NUM_REAL_CORES 16 /* Number of Real cores per cpu */ #define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */ #define MAX_CORE_ATTRS 4 /* Maximum no of basic attrs */ -#define MAX_THRESH_ATTRS 3 /* Maximum no of Threshold attrs */ -#define TOTAL_ATTRS (MAX_CORE_ATTRS + MAX_THRESH_ATTRS) +#define TOTAL_ATTRS (MAX_CORE_ATTRS + 1) #define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO) #ifdef CONFIG_SMP @@ -78,8 +77,6 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); * This value is passed as "id" field to rdmsr/wrmsr functions. * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS, * from where the temperature values should be read. - * @intrpt_reg: One of IA32_THERM_INTERRUPT or IA32_PACKAGE_THERM_INTERRUPT, - * from where the thresholds are read. * @attr_size: Total number of pre-core attrs displayed in the sysfs. * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data. * Otherwise, temp_data holds coretemp data. @@ -88,13 +85,11 @@ MODULE_PARM_DESC(tjmax, "TjMax value in degrees Celsius"); struct temp_data { int temp; int ttarget; - int tmin; int tjmax; unsigned long last_updated; unsigned int cpu; u32 cpu_core_id; u32 status_reg; - u32 intrpt_reg; int attr_size; bool is_pkg_data; bool valid; @@ -152,19 +147,6 @@ static ssize_t show_crit_alarm(struct device *dev, return sprintf(buf, "%d\n", (eax >> 5) & 1); } -static ssize_t show_max_alarm(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - u32 eax, edx; - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - struct temp_data *tdata = pdata->core_data[attr->index]; - - rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx); - - return sprintf(buf, "%d\n", !!(eax & THERM_STATUS_THRESHOLD1)); -} - static ssize_t show_tjmax(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -183,83 +165,6 @@ static ssize_t show_ttarget(struct device *dev, return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget); } -static ssize_t store_ttarget(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct platform_data *pdata = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct temp_data *tdata = pdata->core_data[attr->index]; - u32 eax, edx; - unsigned long val; - int diff; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - - /* - * THERM_MASK_THRESHOLD1 is 7 bits wide. Values are entered in terms - * of milli degree celsius. Hence don't accept val > (127 * 1000) - */ - if (val > tdata->tjmax || val > 127000) - return -EINVAL; - - diff = (tdata->tjmax - val) / 1000; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); - eax = (eax & ~THERM_MASK_THRESHOLD1) | - (diff << THERM_SHIFT_THRESHOLD1); - wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); - tdata->ttarget = val; - mutex_unlock(&tdata->update_lock); - - return count; -} - -static ssize_t show_tmin(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct platform_data *pdata = dev_get_drvdata(dev); - - return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tmin); -} - -static ssize_t store_tmin(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct platform_data *pdata = dev_get_drvdata(dev); - struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct temp_data *tdata = pdata->core_data[attr->index]; - u32 eax, edx; - unsigned long val; - int diff; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - - /* - * THERM_MASK_THRESHOLD0 is 7 bits wide. Values are entered in terms - * of milli degree celsius. Hence don't accept val > (127 * 1000) - */ - if (val > tdata->tjmax || val > 127000) - return -EINVAL; - - diff = (tdata->tjmax - val) / 1000; - - mutex_lock(&tdata->update_lock); - rdmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, &eax, &edx); - eax = (eax & ~THERM_MASK_THRESHOLD0) | - (diff << THERM_SHIFT_THRESHOLD0); - wrmsr_on_cpu(tdata->cpu, tdata->intrpt_reg, eax, edx); - tdata->tmin = val; - mutex_unlock(&tdata->update_lock); - - return count; -} - static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -445,16 +350,11 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_temp, show_tjmax, - show_max_alarm, show_ttarget, show_tmin }; - static ssize_t (*rw_ptr[TOTAL_ATTRS]) (struct device *dev, - struct device_attribute *devattr, const char *buf, - size_t count) = { NULL, NULL, NULL, NULL, NULL, - store_ttarget, store_tmin }; + show_ttarget }; static const char *names[TOTAL_ATTRS] = { "temp%d_label", "temp%d_crit_alarm", "temp%d_input", "temp%d_crit", - "temp%d_max_alarm", "temp%d_max", - "temp%d_max_hyst" }; + "temp%d_max" }; for (i = 0; i < tdata->attr_size; i++) { snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i], @@ -462,10 +362,6 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr); tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i]; tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO; - if (rw_ptr[i]) { - tdata->sd_attrs[i].dev_attr.attr.mode |= S_IWUSR; - tdata->sd_attrs[i].dev_attr.store = rw_ptr[i]; - } tdata->sd_attrs[i].dev_attr.show = rd_ptr[i]; tdata->sd_attrs[i].index = attr_no; err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr); @@ -538,8 +434,6 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS : MSR_IA32_THERM_STATUS; - tdata->intrpt_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_INTERRUPT : - MSR_IA32_THERM_INTERRUPT; tdata->is_pkg_data = pkg_flag; tdata->cpu = cpu; tdata->cpu_core_id = TO_CORE_ID(cpu); @@ -591,19 +485,18 @@ static int create_core_data(struct platform_data *pdata, tdata->tjmax = get_tjmax(c, cpu, &pdev->dev); /* - * Test if we can access the intrpt register. If so, increase the - * 'size' enough to have ttarget/tmin/max_alarm interfaces. - * Initialize ttarget with bits 16:22 of MSR_IA32_THERM_INTERRUPT + * Read the still undocumented bits 8:15 of IA32_TEMPERATURE_TARGET. + * The target temperature is available on older CPUs but not in this + * register. Atoms don't have the register at all. */ - err = rdmsr_safe_on_cpu(cpu, tdata->intrpt_reg, &eax, &edx); - if (!err) { - tdata->attr_size += MAX_THRESH_ATTRS; - tdata->tmin = tdata->tjmax - - ((eax & THERM_MASK_THRESHOLD0) >> - THERM_SHIFT_THRESHOLD0) * 1000; - tdata->ttarget = tdata->tjmax - - ((eax & THERM_MASK_THRESHOLD1) >> - THERM_SHIFT_THRESHOLD1) * 1000; + if (c->x86_model > 0xe && c->x86_model != 0x1c) { + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, + &eax, &edx); + if (!err) { + tdata->ttarget + = tdata->tjmax - ((eax >> 8) & 0xff) * 1000; + tdata->attr_size++; + } } pdata->core_data[attr_no] = tdata; -- cgit v1.2.3-70-g09d2 From 7cbe1ceeb6ab2e4bc334b3dab3254d4414b72a23 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Wed, 21 Sep 2011 06:52:09 -0700 Subject: hwmon: (w83791d) rename prototype parameter from 'register' to 'reg' gcc -Wextra warns "register is not at beginning of declaration" because the compiler thinks the parameter has been marked as a 'register' variable, but the function prototype intended to name the parameter "register" (which is a reserved keyword). Signed-off-by: Chris Peterson Acked-by: Marc Hulsman Signed-off-by: Guenter Roeck --- drivers/hwmon/w83791d.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 17cf1ab9552..8c2844e5691 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -329,8 +329,8 @@ static int w83791d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83791d_remove(struct i2c_client *client); -static int w83791d_read(struct i2c_client *client, u8 register); -static int w83791d_write(struct i2c_client *client, u8 register, u8 value); +static int w83791d_read(struct i2c_client *client, u8 reg); +static int w83791d_write(struct i2c_client *client, u8 reg, u8 value); static struct w83791d_data *w83791d_update_device(struct device *dev); #ifdef DEBUG -- cgit v1.2.3-70-g09d2 From cc41d586e8b4d76164fe7731c1c49be6cc5fc7e6 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 21 Sep 2011 13:06:11 -0400 Subject: hwmon: (ds620) Fix handling of negative temperatures Signed (negative) temperatures were not handled correctly. Signed-off-by: Roland Stigge Signed-off-by: Guenter Roeck Cc: stable@kernel.org # v2.6.38+ --- drivers/hwmon/ds620.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 257957c69d9..4f7c3fc40a8 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -72,7 +72,7 @@ struct ds620_data { char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u16 temp[3]; /* Register values, word */ + s16 temp[3]; /* Register values, word */ }; /* -- cgit v1.2.3-70-g09d2 From 5ebbf72dc51bd3b481aa91fea37a7157da5fc548 Mon Sep 17 00:00:00 2001 From: archit taneja Date: Fri, 5 Aug 2011 04:19:21 -0300 Subject: [media] OMAP_VOUT: Fix build break caused by update_mode removal in DSS2 The DSS2 driver does not support the configuration of the update_mode of a panel anymore. Remove the setting of update_mode done in omap_vout_probe(). Ignore configuration of TE since omap_vout driver doesn't support manual update displays anyway. Signed-off-by: Archit Taneja Tested-by: Koen Kooi Signed-off-by: Vaibhav Hiremath Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap/omap_vout.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index b5ef3622244..b3a5ecdb33a 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -2194,19 +2194,6 @@ static int __init omap_vout_probe(struct platform_device *pdev) "'%s' Display already enabled\n", def_display->name); } - /* set the update mode */ - if (def_display->caps & - OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { - if (dssdrv->enable_te) - dssdrv->enable_te(def_display, 0); - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_MANUAL); - } else { - if (dssdrv->set_update_mode) - dssdrv->set_update_mode(def_display, - OMAP_DSS_UPDATE_AUTO); - } } } -- cgit v1.2.3-70-g09d2 From dd182e5416e872e30d90cf071758eec1cf6340d5 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 16 Jul 2011 00:51:00 -0300 Subject: [media] uvcvideo: Set alternate setting 0 on resume if the bus has been reset If the bus has been reset on resume, set the alternate setting to 0. This should be the default value, but some devices crash or otherwise misbehave if they don't receive a SET_INTERFACE request before any other video control request. Microdia's 0c45:6437 camera has been found to require this change or it will stop sending video data after resume. uvc_video.c] Signed-off-by: Ming Lei Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_driver.c | 2 +- drivers/media/video/uvc/uvc_video.c | 10 +++++++++- drivers/media/video/uvc/uvcvideo.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index d29f9c2d085..e4100b1f68d 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) - return uvc_video_resume(stream); + return uvc_video_resume(stream, reset); } uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 8244167c891..ffd1158628b 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream) * buffers, making sure userspace applications are notified of the problem * instead of waiting forever. */ -int uvc_video_resume(struct uvc_streaming *stream) +int uvc_video_resume(struct uvc_streaming *stream, int reset) { int ret; + /* If the bus has been reset on resume, set the alternate setting to 0. + * This should be the default value, but some devices crash or otherwise + * misbehave if they don't receive a SET_INTERFACE request before any + * other video control request. + */ + if (reset) + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + stream->frozen = 0; ret = uvc_commit_video(stream, &stream->ctrl); diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index df32a43ca86..cbdd49bf8b6 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ extern int uvc_video_init(struct uvc_streaming *stream); extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream); +extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -- cgit v1.2.3-70-g09d2 From 8280b662df96f4172c4972b14a4aec0daf272b8f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 6 Sep 2011 10:23:18 -0300 Subject: [media] v4l: Fix use-after-free case in v4l2_device_release Drivers that have no v4l2_device release callback might free the v4l2_device instance in the video_device release callback. Make sure we don't access the v4l2_device instance after it gets freed. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 06f14008b34..d7215651772 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -173,6 +173,17 @@ static void v4l2_device_release(struct device *cd) media_device_unregister_entity(&vdev->entity); #endif + /* Do not call v4l2_device_put if there is no release callback set. + * Drivers that have no v4l2_device release callback might free the + * v4l2_dev instance in the video_device release callback below, so we + * must perform this check here. + * + * TODO: In the long run all drivers that use v4l2_device should use the + * v4l2_device release callback. This check will then be unnecessary. + */ + if (v4l2_dev->release == NULL) + v4l2_dev = NULL; + /* Release video_device and perform other cleanups as needed. */ vdev->release(vdev); -- cgit v1.2.3-70-g09d2 From 236c5441d70312242b5b32d229259930046a80e5 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Tue, 6 Sep 2011 09:08:08 -0300 Subject: [media] v4l: Make sure we hold a reference to the v4l2_device before using it v4l2_device_disconnect() calls dev_get_drvdata() and dev_set_drvdata() on the device it received in v4l2_device_register(). Get a reference to the device in v4l2_device_register() to make sure it won't disappear as long as we need it. Reported-by: Sitsofe Wheeler Signed-off-by: Dave Young Tested-by: Sitsofe Wheeler Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index c72856c4143..e6a2c3b302d 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -38,6 +38,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); kref_init(&v4l2_dev->ref); + get_device(dev); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ @@ -93,6 +94,7 @@ void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev) dev_set_drvdata(v4l2_dev->dev, NULL); + put_device(v4l2_dev->dev); v4l2_dev->dev = NULL; } EXPORT_SYMBOL_GPL(v4l2_device_disconnect); -- cgit v1.2.3-70-g09d2 From 4d9b2ebd335d83044b9e6656d0e604e8e1300334 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 6 Sep 2011 19:16:18 -0300 Subject: [media] uvcvideo: Fix crash when linking entities The uvc_mc_register_entity() function wrongfully selects the media_entity associated with a UVC entity when creating links. This results in access to uninitialized media_entity structures and can hit a BUG_ON statement in media_entity_create_link(). Fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_entity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c index 48fea373c25..29e239911d0 100644 --- a/drivers/media/video/uvc/uvc_entity.c +++ b/drivers/media/video/uvc/uvc_entity.c @@ -49,7 +49,7 @@ static int uvc_mc_register_entity(struct uvc_video_chain *chain, if (remote == NULL) return -EINVAL; - source = (UVC_ENTITY_TYPE(remote) != UVC_TT_STREAMING) + source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) ? (remote->vdev ? &remote->vdev->entity : NULL) : &remote->subdev.entity; if (source == NULL) -- cgit v1.2.3-70-g09d2 From e74d83aad3709a17d68f01481f2b5f240250b1c3 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 6 Sep 2011 11:02:15 -0300 Subject: [media] omap3isp: Fix build error in ispccdc.c The following build error occurs with 3.1-rc5: CC drivers/media/video/omap3isp/ispccdc.o This patch adds the missing 'linux/slab.h' include to fix the problem. Signed-off-by: Joerg Roedel Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 9d3459de04b..80796eb0c53 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "isp.h" -- cgit v1.2.3-70-g09d2 From d0efab26f89506387a1bde898556660e06d7eb15 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Fri, 2 Sep 2011 19:31:46 +0400 Subject: [SCSI] aacraid: reset should disable MSI interrupt scsi reset on hardware with enabled MSI interrupts generates WARNING message [11027.798722] aacraid: Host adapter abort request (0,0,0,0) [11027.798814] aacraid: Host adapter reset request. SCSI hang ? [11087.762237] aacraid: SCSI bus appears hung [11135.082543] ------------[ cut here ]------------ [11135.082646] WARNING: at drivers/pci/msi.c:658 pci_enable_msi_block+0x251/0x290() Signed-off-by: Vasily Averin Acked-by: Mark Salyzyn Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/aacraid/commsup.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index e7d0d47b918..e5f2d7d9002 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1283,6 +1283,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) kfree(aac->queues); aac->queues = NULL; free_irq(aac->pdev->irq, aac); + if (aac->msi) + pci_disable_msi(aac->pdev); kfree(aac->fsa_dev); aac->fsa_dev = NULL; quirks = aac_get_driver_ident(index)->quirks; -- cgit v1.2.3-70-g09d2 From 24926dadc41cc566e974022b0e66231b82c6375f Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 1 Sep 2011 06:11:17 -0700 Subject: [SCSI] libsas: fix failure to revalidate domain for anything but the first expander child. In an enclosure model where there are chaining expanders to a large body of storage, it was discovered that libsas, responding to a broadcast event change, would only revalidate the domain of first child expander in the list. The issue is that the pointer value to the discovered source device was used to break out of the loop, rather than the content of the pointer. This still remains non-compliant as the revalidate domain code is supposed to loop through all child expanders, and not stop at the first one it finds that reports a change count. However, the design of this routine does not allow multiple device discoveries and that would be a more complicated set of patches reserved for another day. We are fixing the glaring bug rather than refactoring the code. Signed-off-by: Mark Salyzyn Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/libsas/sas_expander.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index f84084bba2f..c9e3dc024bc 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1721,7 +1721,7 @@ static int sas_find_bcast_dev(struct domain_device *dev, list_for_each_entry(ch, &ex->children, siblings) { if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) { res = sas_find_bcast_dev(ch, src_dev); - if (src_dev) + if (*src_dev) return res; } } -- cgit v1.2.3-70-g09d2 From 3538a001ea7db13fa1be2966b71f69d808acff01 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 31 Aug 2011 15:02:00 -0700 Subject: [SCSI] scsi: qla4xxx needs libiscsi.o qla4xxx driver needs to be linked with libiscsi.o to fix build errors. This happens when no other drivers that use libiscsi.o are enabled. ERROR: "iscsi_conn_stop" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_get_addr_param" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_session_teardown" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_host_alloc" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_start" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_send_pdu" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_session_get_param" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_get_param" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_set_param" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_session_failure" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_complete_pdu" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_session_setup" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_bind" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_conn_setup" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! ERROR: "iscsi_itt_to_task" [drivers/scsi/qla4xxx/qla4xxx.ko] undefined! Signed-off-by: Randy Dunlap Reviewed-by: Mike Christie Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 3c08f5352b2..6153a66a8a3 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -88,7 +88,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ -obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/ +obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_BFA_FC) += bfa/ obj-$(CONFIG_SCSI_PAS16) += pas16.o -- cgit v1.2.3-70-g09d2 From a7f4d00a82feb5b311f765bf9522bc55bee0684f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 22 Sep 2011 21:47:38 +0200 Subject: zorro: Defer device_register() until all devices have been identified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As the Amiga Zorro II address space is limited to 8.5 MiB and Zorro devices can contain only one BAR, several Amiga Zorro II expansion boards (mainly graphics cards) contain multiple Zorro devices: a small one for the control registers and one (or more) for the graphics memory. The conversion of cirrusfb to the new driver framework introduced a regression: the driver contains a zorro_driver for the first Zorro device, and uses the (old) zorro_find_device() call to find the second Zorro device. However, as the Zorro core calls device_register() as soon as a Zorro device is identified, it may not have identified the second Zorro device belonging to the same physical Zorro expansion card. Hence cirrusfb could no longer find the second part of the Picasso II graphics card, causing a NULL pointer dereference. Defer the registration of Zorro devices with the driver framework until all Zorro devices have been identified to fix this. Note that the alternative solution (modifying cirrusfb to register a zorro_driver for all Zorro devices belonging to a graphics card, instead of only for the first one, and adding a synchronization mechanism to defer initialization until all have been found), is not an option, as on some cards one device may be optional (e.g. the second bank of 2 MiB of graphics memory on the Picasso IV in Zorro II mode). Reported-by: Ingo Jürgensmann Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: Linus Torvalds --- drivers/zorro/zorro.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index e0c2807b097..181fa8158a8 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -148,10 +148,10 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, bus); - /* Register all devices */ pr_info("Zorro: Probing AutoConfig expansion devices: %u device%s\n", zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + /* First identify all devices ... */ for (i = 0; i < zorro_num_autocon; i++) { z = &zorro_autocon[i]; z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8); @@ -172,6 +172,11 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) dev_set_name(&z->dev, "%02x", i); z->dev.parent = &bus->dev; z->dev.bus = &zorro_bus_type; + } + + /* ... then register them */ + for (i = 0; i < zorro_num_autocon; i++) { + z = &zorro_autocon[i]; error = device_register(&z->dev); if (error) { dev_err(&bus->dev, "Error registering device %s\n", -- cgit v1.2.3-70-g09d2 From 5ce5ed35939ece8a9c7e0f10c7f3d5bc000c6b64 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 8 Aug 2011 13:08:19 +0200 Subject: TPM: TCG_ATMEL should depend on HAS_IOPORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On m68k, I get: drivers/char/tpm/tpm_atmel.h: In function ‘atmel_get_base_addr’: drivers/char/tpm/tpm_atmel.h:129: error: implicit declaration of function ‘ioport_map’ drivers/char/tpm/tpm_atmel.h:129: warning: return makes pointer from integer without a cast The code in tpm_atmel.h supports PPC64 (using the device tree and ioremap()) and "anything else" (using ioport_map()). However, ioportmap() is only available on platforms that set HAS_IOPORT. Although PC64 seems to have HAS_IOPORT, a "depends on HAS_IOPORT" should work, but I think it's better to expose the special PPC64 handling explicit using "depends on PPC64 || HAS_IOPORT". Signed-off-by: Geert Uytterhoeven Signed-off-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index f6595aba4f0..fa567f1158c 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -43,6 +43,7 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" + depends on PPC64 || HAS_IOPORT ---help--- If you have a TPM security chip from Atmel say Yes and it will be accessible from within Linux. To compile this driver -- cgit v1.2.3-70-g09d2 From de69113ec1896443c732e8b812e8005fb44eeeeb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 4 Aug 2011 07:58:07 +0800 Subject: TPM: tpm_nsc: Fix a double free of pdev in cleanup_nsc platform_device_unregister() will release all resources and remove it from the subsystem, then drop reference count by calling platform_device_put(). We should not call kfree(pdev) after platform_device_unregister(pdev). Signed-off-by: Axel Lin Signed-off-by: Rajiv Andrade Signed-off-by: James Morris --- drivers/char/tpm/tpm_nsc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 82facc9104c..4d2464871ad 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -396,8 +396,6 @@ static void __exit cleanup_nsc(void) if (pdev) { tpm_nsc_remove(&pdev->dev); platform_device_unregister(pdev); - kfree(pdev); - pdev = NULL; } platform_driver_unregister(&nsc_drv); -- cgit v1.2.3-70-g09d2 From 6b07d30aca7e52f2881b8c8c20c8a2cd28e8b3d3 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 15 Sep 2011 14:37:43 -0300 Subject: TPM: Call tpm_transmit with correct size This patch changes the call of tpm_transmit by supplying the size of the userspace buffer instead of TPM_BUFSIZE. This got assigned CVE-2011-1161. [The first hunk didn't make sense given one could expect way less data than TPM_BUFSIZE, so added tpm_transmit boundary check over bufsiz instead The last parameter of tpm_transmit() reflects the amount of data expected from the device, and not the buffer size being supplied to it. It isn't ideal to parse it directly, so we just set it to the maximum the input buffer can handle and let the userspace API to do such job.] Signed-off-by: Rajiv Andrade Cc: Stable Kernel Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index caf8012ef47..1fe97933583 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -383,6 +383,9 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, u32 count, ordinal; unsigned long stop; + if (bufsiz > TPM_BUFSIZE) + bufsiz = TPM_BUFSIZE; + count = be32_to_cpu(*((__be32 *) (buf + 2))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) -- cgit v1.2.3-70-g09d2 From 3321c07ae5068568cd61ac9f4ba749006a7185c9 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Thu, 15 Sep 2011 14:47:42 -0300 Subject: TPM: Zero buffer after copying to userspace Since the buffer might contain security related data it might be a good idea to zero the buffer after we have copied it to userspace. This got assigned CVE-2011-1162. Signed-off-by: Rajiv Andrade Cc: Stable Kernel Signed-off-by: James Morris --- drivers/char/tpm/tpm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 1fe97933583..9ca5c021d0b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1105,6 +1105,7 @@ ssize_t tpm_read(struct file *file, char __user *buf, { struct tpm_chip *chip = file->private_data; ssize_t ret_size; + int rc; del_singleshot_timer_sync(&chip->user_read_timer); flush_work_sync(&chip->work); @@ -1115,8 +1116,11 @@ ssize_t tpm_read(struct file *file, char __user *buf, ret_size = size; mutex_lock(&chip->buffer_mutex); - if (copy_to_user(buf, chip->data_buffer, ret_size)) + rc = copy_to_user(buf, chip->data_buffer, ret_size); + memset(chip->data_buffer, 0, ret_size); + if (rc) ret_size = -EFAULT; + mutex_unlock(&chip->buffer_mutex); } -- cgit v1.2.3-70-g09d2 From d9ad77ebfd3a304306f9f18ff3f9e522da075e27 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 23 Sep 2011 14:00:54 +0100 Subject: Revert "drm/radeon/kms: fix typo in r100_blit_copy" This reverts commit 18b4fada275dd2b6dd9db904ddf70fe39e272222. This code was correct, apologies to anyone who noticed things broke. revert contents are different due to another commit in between. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 5b1837b4aac..7fcdbbbf297 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -773,8 +773,8 @@ int r100_copy_blit(struct radeon_device *rdev, radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16)); - radeon_ring_write(rdev, cur_pages); - radeon_ring_write(rdev, cur_pages); + radeon_ring_write(rdev, num_gpu_pages); + radeon_ring_write(rdev, num_gpu_pages); radeon_ring_write(rdev, cur_pages | (stride_pixels << 16)); } radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0)); -- cgit v1.2.3-70-g09d2 From fdfc61594e6de21c23f955818ef78bcab9bafe40 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 22 Sep 2011 10:47:23 -0400 Subject: drm/radeon/kms: fix DDIA enable on some rs690 systems DVOOutputControl checks the value of of bios scratch reg 3 on some tables and assumes the encoder is already enabled if the DFP2_ACTIVE bit is set. Clear that bit so the table sets the DDIA enable bit properly. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_encoders.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 319d85d7e75..13690f3eb4a 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -1507,7 +1507,14 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) switch (mode) { case DRM_MODE_DPMS_ON: args.ucAction = ATOM_ENABLE; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + /* workaround for DVOOutputControl on some RS690 systems */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { + u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); + WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + WREG32(RADEON_BIOS_3_SCRATCH, reg); + } else + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { args.ucAction = ATOM_LCD_BLON; atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -- cgit v1.2.3-70-g09d2 From b3a242a6e4b8c09dbb466ab7a9d2c724e75faa67 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:35:00 -0400 Subject: hwmon: (coretemp) don't use kernel assigned CPU number as platform device ID ... as that has the potential to conflict with (particularly soft) CPU hot removal and re-adding. Signed-off-by: Jan Beulich [guenter.roeck@ericsson.com: use platform device ID as physical CPU id] Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 47364151e67..6420c3be07b 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -561,7 +561,7 @@ static int __devinit coretemp_probe(struct platform_device *pdev) if (err) goto exit_free; - pdata->phys_proc_id = TO_PHYS_ID(pdev->id); + pdata->phys_proc_id = pdev->id; platform_set_drvdata(pdev, pdata); pdata->hwmon_dev = hwmon_device_register(&pdev->dev); @@ -613,7 +613,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) mutex_lock(&pdev_list_mutex); - pdev = platform_device_alloc(DRVNAME, cpu); + pdev = platform_device_alloc(DRVNAME, TO_PHYS_ID(cpu)); if (!pdev) { err = -ENOMEM; pr_err("Device allocation failed\n"); -- cgit v1.2.3-70-g09d2 From e3204ed3a4a78ca4d10eee8b661b94429bd38da8 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:36:53 -0400 Subject: hwmon: (coretemp) constify static data These arrays won't ever be written to, so protect them from unintentional modification. Signed-off-by: Jan Beulich Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 6420c3be07b..ac1c81f1d59 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -347,11 +347,11 @@ static int create_core_attrs(struct temp_data *tdata, struct device *dev, int attr_no) { int err, i; - static ssize_t (*rd_ptr[TOTAL_ATTRS]) (struct device *dev, + static ssize_t (*const rd_ptr[TOTAL_ATTRS]) (struct device *dev, struct device_attribute *devattr, char *buf) = { show_label, show_crit_alarm, show_temp, show_tjmax, show_ttarget }; - static const char *names[TOTAL_ATTRS] = { + static const char *const names[TOTAL_ATTRS] = { "temp%d_label", "temp%d_crit_alarm", "temp%d_input", "temp%d_crit", "temp%d_max" }; -- cgit v1.2.3-70-g09d2 From 2f1c3db0a6adcfd12d556afa3605d4923658b307 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Fri, 23 Sep 2011 06:40:08 -0400 Subject: hwmon: (coretemp) remove struct platform_data * parameter from create_core_data() The only caller of the function obtained the pointer solely for the purpose of passing it to this function, while it can be easily determined from the struct platform_device * parameter also passed. Signed-off-by: Jan Beulich Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index ac1c81f1d59..44b23917d4c 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -442,11 +442,11 @@ static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag) return tdata; } -static int create_core_data(struct platform_data *pdata, - struct platform_device *pdev, +static int create_core_data(struct platform_device *pdev, unsigned int cpu, int pkg_flag) { struct temp_data *tdata; + struct platform_data *pdata = platform_get_drvdata(pdev); struct cpuinfo_x86 *c = &cpu_data(cpu); u32 eax, edx; int err, attr_no; @@ -514,16 +514,13 @@ exit_free: static void coretemp_add_core(unsigned int cpu, int pkg_flag) { - struct platform_data *pdata; struct platform_device *pdev = coretemp_get_pdev(cpu); int err; if (!pdev) return; - pdata = platform_get_drvdata(pdev); - - err = create_core_data(pdata, pdev, cpu, pkg_flag); + err = create_core_data(pdev, cpu, pkg_flag); if (err) dev_err(&pdev->dev, "Adding Core %u failed\n", cpu); } -- cgit v1.2.3-70-g09d2 From 2b7fe39babcbd67458a0c4fbed5704089e0c8c1f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 23 Sep 2011 15:43:54 -0700 Subject: scsi: SCSI_ISCI needs to select SCSI_SAS_HOST_SMP, fixes build error SCSI_ISCI needs to select SCSI_SAS_HOST_SMP to ensure that all needed symbols are available to it. Fixes this build error: ERROR: "try_test_sas_gpio_gp_bit" [drivers/scsi/isci/isci.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/scsi/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8d9dae89f06..3878b739508 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -837,6 +837,7 @@ config SCSI_ISCI # (temporary): known alpha quality driver depends on EXPERIMENTAL select SCSI_SAS_LIBSAS + select SCSI_SAS_HOST_SMP ---help--- This driver supports the 6Gb/s SAS capabilities of the storage control unit found in the Intel(R) C600 series chipset. -- cgit v1.2.3-70-g09d2 From 8ec9c7fb15fd8edf6b34555f5b498033121b2173 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 23 Sep 2011 15:40:50 -0700 Subject: scsi: fix qla2xxx printk format warning sector_t can be different types, so cast it to its largest possible type. drivers/scsi/qla2xxx/qla_isr.c:1509:5: warning: format '%lx' expects type 'long unsigned int', but argument 5 has type 'sector_t' Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/scsi/qla2xxx/qla_isr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 646fc5263d5..8a7591f035e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1507,8 +1507,8 @@ qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) if (k != blocks_done) { qla_printk(KERN_WARNING, sp->fcport->vha->hw, - "unexpected tag values tag:lba=%x:%lx)\n", - e_ref_tag, lba_s); + "unexpected tag values tag:lba=%x:%llx)\n", + e_ref_tag, (unsigned long long)lba_s); return 1; } -- cgit v1.2.3-70-g09d2 From 387719c2ec995019e0af0dc537ca17c9ebd5b64f Mon Sep 17 00:00:00 2001 From: Jeff Harris Date: Fri, 23 Sep 2011 11:49:36 -0400 Subject: spi: Fix WARN when removing spi-fsl-spi module If CPM mode is not used, the fsl_dummy_rx variable is never allocated. When the cleanup attempts to free it, the reference count is zero and a WARN is generated. The same CPM mode check used in the initialize is applied to the free as well. Tested on 2.6.33 with the previous spi_mpc8xxx driver. The renamed spi-fsl-spi driver looks to have the same problem. Signed-off-by: Jeff Harris Signed-off-by: Grant Likely --- drivers/spi/spi-fsl-spi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index d2407558773..24cacff5778 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -825,6 +825,9 @@ static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi) { struct device *dev = mspi->dev; + if (!(mspi->flags & SPI_CPM_MODE)) + return; + dma_unmap_single(dev, mspi->dma_dummy_rx, SPI_MRBLR, DMA_FROM_DEVICE); dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE); cpm_muram_free(cpm_muram_offset(mspi->tx_bd)); -- cgit v1.2.3-70-g09d2 From e48f129c2f200dde8899f6ea5c6e7173674fc482 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 6 Sep 2011 13:59:13 -0400 Subject: [SCSI] cxgb3i: convert cdev->l2opt to use rcu to prevent NULL dereference This oops was reported recently: d:mon> e cpu 0xd: Vector: 300 (Data Access) at [c0000000fd4c7120] pc: d00000000076f194: .t3_l2t_get+0x44/0x524 [cxgb3] lr: d000000000b02108: .init_act_open+0x150/0x3d4 [cxgb3i] sp: c0000000fd4c73a0 msr: 8000000000009032 dar: 0 dsisr: 40000000 current = 0xc0000000fd640d40 paca = 0xc00000000054ff80 pid = 5085, comm = iscsid d:mon> t [c0000000fd4c7450] d000000000b02108 .init_act_open+0x150/0x3d4 [cxgb3i] [c0000000fd4c7500] d000000000e45378 .cxgbi_ep_connect+0x784/0x8e8 [libcxgbi] [c0000000fd4c7650] d000000000db33f0 .iscsi_if_rx+0x71c/0xb18 [scsi_transport_iscsi2] [c0000000fd4c7740] c000000000370c9c .netlink_data_ready+0x40/0xa4 [c0000000fd4c77c0] c00000000036f010 .netlink_sendskb+0x4c/0x9c [c0000000fd4c7850] c000000000370c18 .netlink_sendmsg+0x358/0x39c [c0000000fd4c7950] c00000000033be24 .sock_sendmsg+0x114/0x1b8 [c0000000fd4c7b50] c00000000033d208 .sys_sendmsg+0x218/0x2ac [c0000000fd4c7d70] c00000000033f55c .sys_socketcall+0x228/0x27c [c0000000fd4c7e30] c0000000000086a4 syscall_exit+0x0/0x40 --- Exception: c01 (System Call) at 00000080da560cfc The root cause was an EEH error, which sent us down the offload_close path in the cxgb3 driver, which in turn sets cdev->l2opt to NULL, without regard for upper layer driver (like the cxgbi drivers) which might have execution contexts in the middle of its use. The result is the oops above, when t3_l2t_get attempts to dereference L2DATA(cdev)->nentries in arp_hash right after the EEH error handler sets it to NULL. The fix is to prevent the setting of the NULL pointer until after there are no further users of it. The t3cdev->l2opt pointer is now converted to be an rcu pointer and the L2DATA macro is now called under the protection of the rcu_read_lock(). When the EEH error path: t3_adapter_error->offload_close->cxgb3_offload_deactivate Is exectured, setting of that l2opt pointer to NULL, is now gated on an rcu quiescence point, preventing, allowing L2DATA callers to safely check for a NULL pointer without concern that the underlying data will be freeded before the pointer is dereferenced. This has been tested by the reporter and shown to fix the reproted oops [nhorman: fix up unitinialised variable reported by Dan Carpenter] Signed-off-by: Neil Horman Reviewed-by: Karen Xie Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/infiniband/hw/cxgb3/iwch_cm.c | 10 +++++----- drivers/net/cxgb3/cxgb3_offload.c | 23 ++++++++++++++++++----- drivers/net/cxgb3/l2t.c | 15 ++++++++++++--- drivers/net/cxgb3/l2t.h | 16 ++++++++++++---- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2 +- 5 files changed, 48 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 17bf9d95463..6cd642aaa4d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -287,7 +287,7 @@ void __free_ep(struct kref *kref) if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid); dst_release(ep->dst); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); + l2t_release(ep->com.tdev, ep->l2t); } kfree(ep); } @@ -1178,7 +1178,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) release_tid(ep->com.tdev, GET_TID(rpl), NULL); cxgb3_free_atid(ep->com.tdev, ep->atid); dst_release(ep->dst); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); + l2t_release(ep->com.tdev, ep->l2t); put_ep(&ep->com); return CPL_RET_BUF_DONE; } @@ -1377,7 +1377,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) if (!child_ep) { printk(KERN_ERR MOD "%s - failed to allocate ep entry!\n", __func__); - l2t_release(L2DATA(tdev), l2t); + l2t_release(tdev, l2t); dst_release(dst); goto reject; } @@ -1956,7 +1956,7 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (!err) goto out; - l2t_release(L2DATA(h->rdev.t3cdev_p), ep->l2t); + l2t_release(h->rdev.t3cdev_p, ep->l2t); fail4: dst_release(ep->dst); fail3: @@ -2127,7 +2127,7 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, PDBG("%s ep %p redirect to dst %p l2t %p\n", __func__, ep, new, l2t); dst_hold(new); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); + l2t_release(ep->com.tdev, ep->l2t); ep->l2t = l2t; dst_release(old); ep->dst = new; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 805076c54f1..da5a5d9b8af 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -1146,12 +1146,14 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) if (te && te->ctx && te->client && te->client->redirect) { update_tcb = te->client->redirect(te->ctx, old, new, e); if (update_tcb) { + rcu_read_lock(); l2t_hold(L2DATA(tdev), e); + rcu_read_unlock(); set_l2t_ix(tdev, tid, e); } } } - l2t_release(L2DATA(tdev), e); + l2t_release(tdev, e); } /* @@ -1264,7 +1266,7 @@ int cxgb3_offload_activate(struct adapter *adapter) goto out_free; err = -ENOMEM; - L2DATA(dev) = t3_init_l2t(l2t_capacity); + RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity)); if (!L2DATA(dev)) goto out_free; @@ -1298,16 +1300,24 @@ int cxgb3_offload_activate(struct adapter *adapter) out_free_l2t: t3_free_l2t(L2DATA(dev)); - L2DATA(dev) = NULL; + rcu_assign_pointer(dev->l2opt, NULL); out_free: kfree(t); return err; } +static void clean_l2_data(struct rcu_head *head) +{ + struct l2t_data *d = container_of(head, struct l2t_data, rcu_head); + t3_free_l2t(d); +} + + void cxgb3_offload_deactivate(struct adapter *adapter) { struct t3cdev *tdev = &adapter->tdev; struct t3c_data *t = T3C_DATA(tdev); + struct l2t_data *d; remove_adapter(adapter); if (list_empty(&adapter_list)) @@ -1315,8 +1325,11 @@ void cxgb3_offload_deactivate(struct adapter *adapter) free_tid_maps(&t->tid_maps); T3C_DATA(tdev) = NULL; - t3_free_l2t(L2DATA(tdev)); - L2DATA(tdev) = NULL; + rcu_read_lock(); + d = L2DATA(tdev); + rcu_read_unlock(); + rcu_assign_pointer(tdev->l2opt, NULL); + call_rcu(&d->rcu_head, clean_l2_data); if (t->nofail_skb) kfree_skb(t->nofail_skb); kfree(t); diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index f452c400325..41540978a17 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -300,14 +300,21 @@ static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh) struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, struct net_device *dev) { - struct l2t_entry *e; - struct l2t_data *d = L2DATA(cdev); + struct l2t_entry *e = NULL; + struct l2t_data *d; + int hash; u32 addr = *(u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; - int hash = arp_hash(addr, ifidx, d); struct port_info *p = netdev_priv(dev); int smt_idx = p->port_id; + rcu_read_lock(); + d = L2DATA(cdev); + if (!d) + goto done_rcu; + + hash = arp_hash(addr, ifidx, d); + write_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) if (e->addr == addr && e->ifindex == ifidx && @@ -338,6 +345,8 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, } done: write_unlock_bh(&d->lock); +done_rcu: + rcu_read_unlock(); return e; } diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h index 7a12d52ed4f..c5f54796e2c 100644 --- a/drivers/net/cxgb3/l2t.h +++ b/drivers/net/cxgb3/l2t.h @@ -76,6 +76,7 @@ struct l2t_data { atomic_t nfree; /* number of free entries */ rwlock_t lock; struct l2t_entry l2tab[0]; + struct rcu_head rcu_head; /* to handle rcu cleanup */ }; typedef void (*arp_failure_handler_func)(struct t3cdev * dev, @@ -99,7 +100,7 @@ static inline void set_arp_failure_handler(struct sk_buff *skb, /* * Getting to the L2 data from an offload device. */ -#define L2DATA(dev) ((dev)->l2opt) +#define L2DATA(cdev) (rcu_dereference((cdev)->l2opt)) #define W_TCB_L2T_IX 0 #define S_TCB_L2T_IX 7 @@ -126,15 +127,22 @@ static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb, return t3_l2t_send_slow(dev, skb, e); } -static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e) +static inline void l2t_release(struct t3cdev *t, struct l2t_entry *e) { - if (atomic_dec_and_test(&e->refcnt)) + struct l2t_data *d; + + rcu_read_lock(); + d = L2DATA(t); + + if (atomic_dec_and_test(&e->refcnt) && d) t3_l2e_free(d, e); + + rcu_read_unlock(); } static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) { - if (atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ + if (d && atomic_add_return(1, &e->refcnt) == 1) /* 0 -> 1 transition */ atomic_dec(&d->nfree); } diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index bd22041e278..f5864485033 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -913,7 +913,7 @@ static void l2t_put(struct cxgbi_sock *csk) struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev; if (csk->l2t) { - l2t_release(L2DATA(t3dev), csk->l2t); + l2t_release(t3dev, csk->l2t); csk->l2t = NULL; cxgbi_sock_put(csk); } -- cgit v1.2.3-70-g09d2 From 96067723e46b0dd24ae7b934085ab4eff4d26a1b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 18 Sep 2011 18:56:20 +0400 Subject: [SCSI] 3w-9xxx: fix iommu_iova leak Following reports on the list, it looks like the 3e-9xxx driver will leak dma mappings every time we get a transient queueing error back from the card. This is because it maps the sg list in the routine that sends the command, but doesn't unmap again in the transient failure path (even though the command is sent back to the block layer). Fix by unmapping before returning the status. Reported-by: Chris Boot Tested-by: Chris Boot Acked-by: Adam Radford Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/3w-9xxx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index b7bd5b0cc7a..3868ab2397c 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1800,10 +1800,12 @@ static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_ switch (retval) { case SCSI_MLQUEUE_HOST_BUSY: twa_free_request_id(tw_dev, request_id); + twa_unmap_scsi_data(tw_dev, request_id); break; case 1: tw_dev->state[request_id] = TW_S_COMPLETED; twa_free_request_id(tw_dev, request_id); + twa_unmap_scsi_data(tw_dev, request_id); SCpnt->result = (DID_ERROR << 16); done(SCpnt); retval = 0; -- cgit v1.2.3-70-g09d2 From a681887f7b0f8b7698e4b22f1191015424fa96e4 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 26 Sep 2011 16:40:35 +0200 Subject: [S390] cio: fix cio_tpi ignoring adapter interrupts Ensure that adapter interrupts are correctly processed when they are retrieved using TEST PENDING INTERRUPTION. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index cbde448f994..eb3140ee821 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -654,8 +654,8 @@ static struct io_subchannel_private console_priv; static int console_subchannel_in_use; /* - * Use tpi to get a pending interrupt, call the interrupt handler and - * return a pointer to the subchannel structure. + * Use cio_tpi to get a pending interrupt and call the interrupt handler. + * Return non-zero if an interrupt was processed, zero otherwise. */ static int cio_tpi(void) { @@ -667,6 +667,10 @@ static int cio_tpi(void) tpi_info = (struct tpi_info *)&S390_lowcore.subchannel_id; if (tpi(NULL) != 1) return 0; + if (tpi_info->adapter_IO) { + do_adapter_IO(tpi_info->isc); + return 1; + } irb = (struct irb *)&S390_lowcore.irb; /* Store interrupt response block to lowcore. */ if (tsch(tpi_info->schid, irb) != 0) -- cgit v1.2.3-70-g09d2 From e8b364b88cc4001b21c28c1ecf1e1e3ffbe162e6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 26 Sep 2011 19:40:23 +0200 Subject: PM / Clocks: Do not acquire a mutex under a spinlock Commit b7ab83e (PM: Use spinlock instead of mutex in clock management functions) introduced a regression causing clocks_mutex to be acquired under a spinlock. This happens because pm_clk_suspend() and pm_clk_resume() call pm_clk_acquire() under pcd->lock, but pm_clk_acquire() executes clk_get() which causes clocks_mutex to be acquired. Similarly, __pm_clk_remove(), executed under pcd->lock, calls clk_put(), which also causes clocks_mutex to be acquired. To fix those problems make pm_clk_add() call pm_clk_acquire(), so that pm_clk_suspend() and pm_clk_resume() don't have to do that. Change pm_clk_remove() and pm_clk_destroy() to separate modifications of the pcd->clock_list list from the actual removal of PM clock entry objects done by __pm_clk_remove(). Reported-and-tested-by: Guennadi Liakhovetski Signed-off-by: Rafael J. Wysocki Acked-by: Russell King --- drivers/base/power/clock_ops.c | 75 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 2c18d584066..b97294e2d95 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -41,6 +41,22 @@ static struct pm_clk_data *__to_pcd(struct device *dev) return dev ? dev->power.subsys_data : NULL; } +/** + * pm_clk_acquire - Acquire a device clock. + * @dev: Device whose clock is to be acquired. + * @ce: PM clock entry corresponding to the clock. + */ +static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) +{ + ce->clk = clk_get(dev, ce->con_id); + if (IS_ERR(ce->clk)) { + ce->status = PCE_STATUS_ERROR; + } else { + ce->status = PCE_STATUS_ACQUIRED; + dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); + } +} + /** * pm_clk_add - Start using a device clock for power management. * @dev: Device whose clock is going to be used for power management. @@ -73,6 +89,8 @@ int pm_clk_add(struct device *dev, const char *con_id) } } + pm_clk_acquire(dev, ce); + spin_lock_irq(&pcd->lock); list_add_tail(&ce->node, &pcd->clock_list); spin_unlock_irq(&pcd->lock); @@ -82,17 +100,12 @@ int pm_clk_add(struct device *dev, const char *con_id) /** * __pm_clk_remove - Destroy PM clock entry. * @ce: PM clock entry to destroy. - * - * This routine must be called under the spinlock protecting the PM list of - * clocks corresponding the the @ce's device. */ static void __pm_clk_remove(struct pm_clock_entry *ce) { if (!ce) return; - list_del(&ce->node); - if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) clk_disable(ce->clk); @@ -126,18 +139,22 @@ void pm_clk_remove(struct device *dev, const char *con_id) spin_lock_irq(&pcd->lock); list_for_each_entry(ce, &pcd->clock_list, node) { - if (!con_id && !ce->con_id) { - __pm_clk_remove(ce); - break; - } else if (!con_id || !ce->con_id) { + if (!con_id && !ce->con_id) + goto remove; + else if (!con_id || !ce->con_id) continue; - } else if (!strcmp(con_id, ce->con_id)) { - __pm_clk_remove(ce); - break; - } + else if (!strcmp(con_id, ce->con_id)) + goto remove; } spin_unlock_irq(&pcd->lock); + return; + + remove: + list_del(&ce->node); + spin_unlock_irq(&pcd->lock); + + __pm_clk_remove(ce); } /** @@ -175,43 +192,33 @@ void pm_clk_destroy(struct device *dev) { struct pm_clk_data *pcd = __to_pcd(dev); struct pm_clock_entry *ce, *c; + struct list_head list; if (!pcd) return; dev->power.subsys_data = NULL; + INIT_LIST_HEAD(&list); spin_lock_irq(&pcd->lock); list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) - __pm_clk_remove(ce); + list_move(&ce->node, &list); spin_unlock_irq(&pcd->lock); kfree(pcd); + + list_for_each_entry_safe_reverse(ce, c, &list, node) { + list_del(&ce->node); + __pm_clk_remove(ce); + } } #endif /* CONFIG_PM */ #ifdef CONFIG_PM_RUNTIME -/** - * pm_clk_acquire - Acquire a device clock. - * @dev: Device whose clock is to be acquired. - * @con_id: Connection ID of the clock. - */ -static void pm_clk_acquire(struct device *dev, - struct pm_clock_entry *ce) -{ - ce->clk = clk_get(dev, ce->con_id); - if (IS_ERR(ce->clk)) { - ce->status = PCE_STATUS_ERROR; - } else { - ce->status = PCE_STATUS_ACQUIRED; - dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); - } -} - /** * pm_clk_suspend - Disable clocks in a device's PM clock list. * @dev: Device to disable the clocks for. @@ -230,9 +237,6 @@ int pm_clk_suspend(struct device *dev) spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry_reverse(ce, &pcd->clock_list, node) { - if (ce->status == PCE_STATUS_NONE) - pm_clk_acquire(dev, ce); - if (ce->status < PCE_STATUS_ERROR) { clk_disable(ce->clk); ce->status = PCE_STATUS_ACQUIRED; @@ -262,9 +266,6 @@ int pm_clk_resume(struct device *dev) spin_lock_irqsave(&pcd->lock, flags); list_for_each_entry(ce, &pcd->clock_list, node) { - if (ce->status == PCE_STATUS_NONE) - pm_clk_acquire(dev, ce); - if (ce->status < PCE_STATUS_ERROR) { clk_enable(ce->clk); ce->status = PCE_STATUS_ENABLED; -- cgit v1.2.3-70-g09d2 From 6c80c39d9a6986a566c30d797aae37bfb697eea3 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 22 Sep 2011 14:59:04 -0700 Subject: iwlagn: fix dangling scan request If iwl_scan_initiate() fails for any reason, priv->scan_request and priv->scan_vif are left dangling. This can lead to a crash later when iwl_bg_scan_completed() tries to run a pending scan request. In practice, this seems to be very rare due to the STATUS_SCANNING check earlier. That check, however, is wrong -- it should allow a scan to be queued when a reset/roc scan is going on. When a normal scan is already going on, a new one can't be issued by mac80211, so that code can be removed completely. I introduced this bug when adding off-channel support in commit 266af4c745952e9bebf687dd68af58df553cb59d. Cc: stable@kernel.org [3.0] Reported-by: Peng Yan Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-scan.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index dd6937e9705..77e528f5db8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -405,31 +405,33 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - if (test_bit(STATUS_SCANNING, &priv->status) && - priv->scan_type != IWL_SCAN_NORMAL) { - IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); - ret = -EAGAIN; - goto out_unlock; - } - - /* mac80211 will only ask for one band at a time */ - priv->scan_request = req; - priv->scan_vif = vif; - /* * If an internal scan is in progress, just set * up the scan_request as per above. */ if (priv->scan_type != IWL_SCAN_NORMAL) { - IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n"); + IWL_DEBUG_SCAN(priv, + "SCAN request during internal scan - defer\n"); + priv->scan_request = req; + priv->scan_vif = vif; ret = 0; - } else + } else { + priv->scan_request = req; + priv->scan_vif = vif; + /* + * mac80211 will only ask for one band at a time + * so using channels[0] here is ok + */ ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL, req->channels[0]->band); + if (ret) { + priv->scan_request = NULL; + priv->scan_vif = NULL; + } + } IWL_DEBUG_MAC80211(priv, "leave\n"); -out_unlock: mutex_unlock(&priv->mutex); return ret; -- cgit v1.2.3-70-g09d2 From 831d85471e761e190c3c8979b37540d699ae5812 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 22 Sep 2011 22:59:02 -0500 Subject: rtlwifi: rtl8192cu: Fix unitialized struct Driver rtl8192cu assigns a new struct rtl_tcb_desc object, but fails to clear it. Signed-off-by: Larry Finger Cc: Stable [2.6.39+] Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 8b1cef0ffde..4bf3cf457ef 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -863,6 +863,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, u8 tid = 0; u16 seq_number = 0; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); if (ieee80211_is_auth(fc)) { RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); rtl_ips_nic_on(hw); -- cgit v1.2.3-70-g09d2 From ba54238552625aad2d75f455a4d3db18ea7dec68 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 23 Sep 2011 14:33:14 +0530 Subject: ath9k: Fix a dma warning/memory leak proper dma_unmapping and freeing of skb's has to be done in the rx cleanup for EDMA chipsets when the device is unloaded and this also seems to address the following warning which shows up occasionally when the device is unloaded Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? dma_debug_device_change+0x19c/0x200 [] ? dma_debug_device_change+0x19c/0x200 [] warn_slowpath_fmt+0x33/0x40 [] dma_debug_device_change+0x19c/0x200 [] notifier_call_chain+0x82/0xb0 [] __blocking_notifier_call_chain+0x60/0x90 [] blocking_notifier_call_chain+0x1f/0x30 [] __device_release_driver+0xa4/0xc0 [] driver_detach+0x97/0xa0 [] bus_remove_driver+0x6c/0xe0 [] ? sysfs_addrm_finish+0x4b/0x60 [] driver_unregister+0x49/0x80 [] ? sysfs_remove_file+0x14/0x20 [] pci_unregister_driver+0x32/0x80 [] ath_pci_exit+0x12/0x20 [ath9k] [] ath9k_exit+0x17/0x36 [ath9k] [] ? mutex_unlock+0xd/0x10 [] sys_delete_module+0x13f/0x200 [] ? sys_munmap+0x4b/0x60 [] ? restore_all+0xf/0xf [] ? spurious_fault+0xe0/0xe0 [] ? trace_hardirqs_on_caller+0xf4/0x180 [] sysenter_do_call+0x12/0x38 ---[ end trace 16e1c1521c06bcf9 ]--- Mapped at: [] debug_dma_map_page+0x48/0x120 [] ath_rx_init+0x3f8/0x4b0 [ath9k] [] ath9k_init_device+0x4c4/0x7b0 [ath9k] [] ath_pci_probe+0x263/0x330 [ath9k] Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 9a4850154fb..4c21f8cbdeb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc, static void ath_rx_edma_cleanup(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf; ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); list_for_each_entry(bf, &sc->rx.rxbuf, list) { - if (bf->bf_mpdu) + if (bf->bf_mpdu) { + dma_unmap_single(sc->dev, bf->bf_buf_addr, + common->rx_bufsize, + DMA_BIDIRECTIONAL); dev_kfree_skb_any(bf->bf_mpdu); + bf->bf_buf_addr = 0; + bf->bf_mpdu = NULL; + } } INIT_LIST_HEAD(&sc->rx.rxbuf); -- cgit v1.2.3-70-g09d2 From f2eaeb58bf6995a979c413ea0cc73289533feacb Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 22 Sep 2011 02:33:31 +0000 Subject: bnx2x: fix hw attention handling Use register name to initialize attention mask Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 6 ++++-- drivers/net/bnx2x/bnx2x_reg.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index c027e9341a1..6b469177e52 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -4943,7 +4943,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp) int igu_seg_id; int port = BP_PORT(bp); int func = BP_FUNC(bp); - int reg_offset; + int reg_offset, reg_offset_en5; u64 section; int index; struct hc_sp_status_block_data sp_sb_data; @@ -4966,6 +4966,8 @@ static void bnx2x_init_def_sb(struct bnx2x *bp) reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + reg_offset_en5 = (port ? MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0); for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { int sindex; /* take care of sig[0]..sig[4] */ @@ -4980,7 +4982,7 @@ static void bnx2x_init_def_sb(struct bnx2x *bp) * and not 16 between the different groups */ bp->attn_group[index].sig[4] = REG_RD(bp, - reg_offset + 0x10 + 0x4*index); + reg_offset_en5 + 0x4*index); else bp->attn_group[index].sig[4] = 0; } diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 750e8445dac..fc7bd0f23c0 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -1384,6 +1384,18 @@ Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ #define MISC_REG_AEU_ENABLE4_PXP_0 0xa108 #define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8 +/* [RW 32] fifth 32b for enabling the output for function 0 output0. Mapped + * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC + * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6] + * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1 + * parity; [31-10] Reserved; */ +#define MISC_REG_AEU_ENABLE5_FUNC_0_OUT_0 0xa688 +/* [RW 32] Fifth 32b for enabling the output for function 1 output0. Mapped + * as follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC + * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6] + * mstat0 attention; [7] mstat0 parity; [8] mstat1 attention; [9] mstat1 + * parity; [31-10] Reserved; */ +#define MISC_REG_AEU_ENABLE5_FUNC_1_OUT_0 0xa6b0 /* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu 128 bit vector */ #define MISC_REG_AEU_GENERAL_ATTN_0 0xa000 -- cgit v1.2.3-70-g09d2 From f99779035730f8c3be8aeadd386cc9e77e086446 Mon Sep 17 00:00:00 2001 From: Dmitry Kravkov Date: Thu, 22 Sep 2011 02:33:32 +0000 Subject: bnx2x: fix WOL by enablement PME in config space Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 6b469177e52..15f800085bb 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -7627,8 +7627,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode) u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; u8 *mac_addr = bp->dev->dev_addr; u32 val; + u16 pmc; + /* The mac address is written to entries 1-4 to - preserve entry 0 which is used by the PMF */ + * preserve entry 0 which is used by the PMF + */ u8 entry = (BP_VN(bp) + 1)*8; val = (mac_addr[0] << 8) | mac_addr[1]; @@ -7638,6 +7641,11 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode) (mac_addr[4] << 8) | mac_addr[5]; EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val); + /* Enable the PME and clear the status */ + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmc); + pmc |= PCI_PM_CTRL_PME_ENABLE | PCI_PM_CTRL_PME_STATUS; + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, pmc); + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; } else -- cgit v1.2.3-70-g09d2 From a0babc80eb375aad69dab4687c3b44c47d42f241 Mon Sep 17 00:00:00 2001 From: Shmulik Ravid Date: Thu, 22 Sep 2011 02:33:33 +0000 Subject: bnx2x: add missing break in bnx2x_dcbnl_get_cap Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_dcb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c index a1e004a82f7..0b4acf67e0c 100644 --- a/drivers/net/bnx2x/bnx2x_dcb.c +++ b/drivers/net/bnx2x/bnx2x_dcb.c @@ -2120,6 +2120,7 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) break; case DCB_CAP_ATTR_DCBX: *cap = BNX2X_DCBX_CAPS; + break; default: rval = -EINVAL; break; -- cgit v1.2.3-70-g09d2 From 0eb9782ad9b1bd496ba61cd5ea27ccb8db21e885 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 28 Sep 2011 08:11:00 -0700 Subject: hwmon: (coretemp) Fixup platform device ID change With recent change "hwmon: (coretemp) don't use kernel assigned CPU number as platform device ID", the microcode check is now running on random CPU. Fix that by checking the microcode before creating the platform device rather than at probe time. Also avoid calling TO_PHYS_ID(cpu) twice in the same function, it's expensive. Signed-off-by: Jean Delvare Cc: Jan Beulich Cc: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/hwmon/coretemp.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 44b23917d4c..cf5b1de32c0 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -377,9 +377,9 @@ exit_free: } -static int __devinit chk_ucode_version(struct platform_device *pdev) +static int __cpuinit chk_ucode_version(unsigned int cpu) { - struct cpuinfo_x86 *c = &cpu_data(pdev->id); + struct cpuinfo_x86 *c = &cpu_data(cpu); int err; u32 edx; @@ -390,17 +390,15 @@ static int __devinit chk_ucode_version(struct platform_device *pdev) */ if (c->x86_model == 0xe && c->x86_mask < 0xc) { /* check for microcode update */ - err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu, + err = smp_call_function_single(cpu, get_ucode_rev_on_cpu, &edx, 1); if (err) { - dev_err(&pdev->dev, - "Cannot determine microcode revision of " - "CPU#%u (%d)!\n", pdev->id, err); + pr_err("Cannot determine microcode revision of " + "CPU#%u (%d)!\n", cpu, err); return -ENODEV; } else if (edx < 0x39) { - dev_err(&pdev->dev, - "Errata AE18 not fixed, update BIOS or " - "microcode of the CPU!\n"); + pr_err("Errata AE18 not fixed, update BIOS or " + "microcode of the CPU!\n"); return -ENODEV; } } @@ -544,11 +542,6 @@ static int __devinit coretemp_probe(struct platform_device *pdev) struct platform_data *pdata; int err; - /* Check the microcode version of the CPU */ - err = chk_ucode_version(pdev); - if (err) - return err; - /* Initialize the per-package data structures */ pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL); if (!pdata) @@ -630,7 +623,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu) } pdev_entry->pdev = pdev; - pdev_entry->phys_proc_id = TO_PHYS_ID(cpu); + pdev_entry->phys_proc_id = pdev->id; list_add_tail(&pdev_entry->list, &pdev_list); mutex_unlock(&pdev_list_mutex); @@ -691,6 +684,10 @@ static void __cpuinit get_core_online(unsigned int cpu) return; if (!pdev) { + /* Check the microcode version of the CPU */ + if (chk_ucode_version(cpu)) + return; + /* * Alright, we have DTS support. * We are bringing the _first_ core in this pkg -- cgit v1.2.3-70-g09d2 From 20ecb499f64a7e8e7fe03f6098ab25c71b7a6481 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 24 Sep 2011 15:27:04 -0700 Subject: hwmon: (coretemp) Avoid leaving around dangling pointer Storing the struct temp_data pointer allocated from create_core_data() when returning an error has the potential of leaving around a pointer to freed memory. Reset it to NULL for error returns. Reported-by: Jan Beulich Signed-off-by: Guenter Roeck Acked-by: Jean Delvare --- drivers/hwmon/coretemp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index cf5b1de32c0..93238378664 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -506,6 +506,7 @@ static int create_core_data(struct platform_device *pdev, return 0; exit_free: + pdata->core_data[attr_no] = NULL; kfree(tdata); return err; } -- cgit v1.2.3-70-g09d2 From 02715ed2e7b71569ed6e61f0b23b0736a509913d Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Tue, 20 Sep 2011 01:25:42 +0000 Subject: dp83640: reduce driver noise The driver has two warning messages that might be triggered by normal use cases. When they appear, the messages give the impression of a never ending series of errors. This commit changes them to debug messages instead. Signed-off-by: Richard Cochran Signed-off-by: David S. Miller --- drivers/net/phy/dp83640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index cb6e0b486b1..edd7304773e 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -589,7 +589,7 @@ static void decode_rxts(struct dp83640_private *dp83640, prune_rx_ts(dp83640); if (list_empty(&dp83640->rxpool)) { - pr_warning("dp83640: rx timestamp pool is empty\n"); + pr_debug("dp83640: rx timestamp pool is empty\n"); goto out; } rxts = list_first_entry(&dp83640->rxpool, struct rxts, list); @@ -612,7 +612,7 @@ static void decode_txts(struct dp83640_private *dp83640, skb = skb_dequeue(&dp83640->tx_queue); if (!skb) { - pr_warning("dp83640: have timestamp but tx_queue empty\n"); + pr_debug("dp83640: have timestamp but tx_queue empty\n"); return; } ns = phy2txts(phy_txts); -- cgit v1.2.3-70-g09d2 From 6482aa7c120447858da1869197b48eff66435a31 Mon Sep 17 00:00:00 2001 From: Divy Le Ray Date: Sat, 24 Sep 2011 06:11:31 +0000 Subject: cxgb4: Fix EEH on IBM P7IOC Fix EEH recovery on new P Series platform by requesting fundamental reset. Signed-off-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb4/cxgb4_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index c9957b7f17b..b4efa292fd6 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -3712,6 +3712,9 @@ static int __devinit init_one(struct pci_dev *pdev, setup_debugfs(adapter); } + /* PCIe EEH recovery on powerpc platforms needs fundamental reset */ + pdev->needs_freset = 1; + if (is_offload(adapter)) attach_ulds(adapter); -- cgit v1.2.3-70-g09d2 From 95de86cf5162f78bc5aea80d1a9e5a248196ffaf Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 28 Sep 2011 05:33:43 +0000 Subject: ibmveth: Fix oops on request_irq failure If request_irq fails, the ibmveth driver will overwrite the rc and end up returning a successful rc on its open function, resulting in an oops later when a packet gets sent and buffers are not allocated due to the failed open. Signed-off-by: Brian King Signed-off-by: David S. Miller --- drivers/net/ibmveth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 8dd5fccef72..d393f1e764e 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -636,8 +636,8 @@ static int ibmveth_open(struct net_device *netdev) netdev_err(netdev, "unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { - rc = h_free_logical_lan(adapter->vdev->unit_address); - } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); + lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); + } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY)); goto err_out; } -- cgit v1.2.3-70-g09d2 From 109bc10d30f33e84f1d7289f0039e0c858ade82f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 Oct 2011 09:13:45 -0400 Subject: drm/radeon/kms: fix regression in DP aux defer handling An incorrect ordering in the error checking code lead to DP aux defer being skipped in the aux native write path. Move the bytes transferred check (ret == 0) below the defer check. Tracked down by: Brad Campbell Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=41121 Signed-off-by: Alex Deucher Cc: Brad Campbell Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 7ad43c6b1db..f526fa77e32 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -158,14 +158,14 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, while (1) { ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_bytes, recv, recv_bytes, delay, &ack); - if (ret == 0) - return -EPROTO; if (ret < 0) return ret; if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) return ret; else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) udelay(400); + else if (ret == 0) + return -EPROTO; else return -EIO; } -- cgit v1.2.3-70-g09d2 From 6375bda073724ead7df08746866b724b1799a295 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 Oct 2011 09:13:46 -0400 Subject: drm/radeon/kms: add retry limits for native DP aux defer The previous code could potentially loop forever. Limit the number of DP aux defer retries to 4 for native aux transactions, same as i2c over aux transactions. Noticed by: Brad Campbell Signed-off-by: Alex Deucher Cc: Brad Campbell Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_dp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index f526fa77e32..4da23889fea 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -115,6 +115,7 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, u8 msg[20]; int msg_bytes = send_bytes + 4; u8 ack; + unsigned retry; if (send_bytes > 16) return -1; @@ -125,20 +126,20 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, msg[3] = (msg_bytes << 4) | (send_bytes - 1); memcpy(&msg[4], send, send_bytes); - while (1) { + for (retry = 0; retry < 4; retry++) { ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_bytes, NULL, 0, delay, &ack); if (ret < 0) return ret; if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) - break; + return send_bytes; else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) udelay(400); else return -EIO; } - return send_bytes; + return -EIO; } static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, @@ -149,13 +150,14 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, int msg_bytes = 4; u8 ack; int ret; + unsigned retry; msg[0] = address; msg[1] = address >> 8; msg[2] = AUX_NATIVE_READ << 4; msg[3] = (msg_bytes << 4) | (recv_bytes - 1); - while (1) { + for (retry = 0; retry < 4; retry++) { ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_bytes, recv, recv_bytes, delay, &ack); if (ret < 0) @@ -169,6 +171,8 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, else return -EIO; } + + return -EIO; } static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector, -- cgit v1.2.3-70-g09d2 From 5ba7ddf81634bfdf32d09261d2959e3f5b7c4263 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 3 Oct 2011 08:37:33 -0400 Subject: drm/radeon/kms: Fix logic error in DP HPD handler Only disable the pipe if the monitor is physically disconnected. The previous logic also disabled the pipe if the link was trained. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=41248 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c4b8741dbf5..bce63fd329d 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -68,11 +68,11 @@ void radeon_connector_hotplug(struct drm_connector *connector) if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { int saved_dpms = connector->dpms; - if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) && - radeon_dp_needs_link_train(radeon_connector)) - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - else + /* Only turn off the display it it's physically disconnected */ + if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + else if (radeon_dp_needs_link_train(radeon_connector)) + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); connector->dpms = saved_dpms; } } -- cgit v1.2.3-70-g09d2 From b356fe0afe9aa2cfdc7be0bae22ea1c93afc2451 Mon Sep 17 00:00:00 2001 From: Nicholas Miell Date: Thu, 29 Sep 2011 19:07:14 -0700 Subject: drm/radeon/kms: fix cursor image off-by-one error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mouse cursor hotspot calculation when the cursor is partially off the top or left side of the screen was off by one. Fixes https://bugs.freedesktop.org/show_bug.cgi?id=41158 Signed-off-by: Nicholas Miell Reviewed-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 3189a7efb2e..c495575b2e1 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -209,9 +209,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, int w = radeon_crtc->cursor_width; if (x < 0) - xorigin = -x + 1; + xorigin = -x; if (y < 0) - yorigin = -y + 1; + yorigin = -y; if (xorigin >= CURSOR_WIDTH) xorigin = CURSOR_WIDTH - 1; if (yorigin >= CURSOR_HEIGHT) -- cgit v1.2.3-70-g09d2 From 7d309529b4c1a6281549bf86681cdfb4fbed49ed Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Fri, 30 Sep 2011 17:16:51 +0200 Subject: drm/radeon: Simplify cursor x/yorigin calculation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index c495575b2e1..bac8ee7990a 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -209,13 +209,9 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, int w = radeon_crtc->cursor_width; if (x < 0) - xorigin = -x; + xorigin = min(-x, CURSOR_WIDTH - 1); if (y < 0) - yorigin = -y; - if (xorigin >= CURSOR_WIDTH) - xorigin = CURSOR_WIDTH - 1; - if (yorigin >= CURSOR_HEIGHT) - yorigin = CURSOR_HEIGHT - 1; + yorigin = min(-y, CURSOR_HEIGHT - 1); if (ASIC_IS_AVIVO(rdev)) { int i = 0; -- cgit v1.2.3-70-g09d2 From b8aee294d89502469f2d80ae6afb93398d8227e0 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Fri, 30 Sep 2011 17:16:52 +0200 Subject: drm/radeon: Update AVIVO cursor coordinate origin before x/yorigin calculation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes cursor disappearing prematurely when moving off a top/left edge which is not located at the desktop top/left edge. Signed-off-by: Michel Dänzer Cc: stable@kernel.org Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index bac8ee7990a..f1d871db039 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -208,6 +208,13 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, int xorigin = 0, yorigin = 0; int w = radeon_crtc->cursor_width; + if (ASIC_IS_AVIVO(rdev)) { + /* avivo cursor are offset into the total surface */ + x += crtc->x; + y += crtc->y; + } + DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); + if (x < 0) xorigin = min(-x, CURSOR_WIDTH - 1); if (y < 0) @@ -217,11 +224,6 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, int i = 0; struct drm_crtc *crtc_p; - /* avivo cursor are offset into the total surface */ - x += crtc->x; - y += crtc->y; - DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); - /* avivo cursor image can't end on 128 pixel boundary or * go past the end of the frame if both crtcs are enabled */ -- cgit v1.2.3-70-g09d2 From 02e6859eae4a8e511fa1a2c9a689ea25cdc6166a Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Fri, 30 Sep 2011 17:16:53 +0200 Subject: drm/radeon: Set cursor x/y to 0 when x/yorigin > 0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apart from the obvious cleanup, this should make the line cursor_end = x - xorigin + w; correct now. Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index f1d871db039..fde25c0d65a 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -215,10 +215,14 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, } DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); - if (x < 0) + if (x < 0) { xorigin = min(-x, CURSOR_WIDTH - 1); - if (y < 0) + x = 0; + } + if (y < 0) { yorigin = min(-y, CURSOR_HEIGHT - 1); + y = 0; + } if (ASIC_IS_AVIVO(rdev)) { int i = 0; @@ -251,16 +255,12 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, radeon_lock_cursor(crtc, true); if (ASIC_IS_DCE4(rdev)) { - WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, - ((xorigin ? 0 : x) << 16) | - (yorigin ? 0 : y)); + WREG32(EVERGREEN_CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(EVERGREEN_CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(EVERGREEN_CUR_SIZE + radeon_crtc->crtc_offset, ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); } else if (ASIC_IS_AVIVO(rdev)) { - WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, - ((xorigin ? 0 : x) << 16) | - (yorigin ? 0 : y)); + WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset, (x << 16) | y); WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin); WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset, ((w - 1) << 16) | (radeon_crtc->cursor_height - 1)); @@ -274,8 +274,8 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, | yorigin)); WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset, (RADEON_CUR_LOCK - | ((xorigin ? 0 : x) << 16) - | (yorigin ? 0 : y))); + | (x << 16) + | y)); /* offset is from DISP(2)_BASE_ADDRESS */ WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, (radeon_crtc->legacy_cursor_offset + (yorigin * 256))); -- cgit v1.2.3-70-g09d2 From a0db2dad0935e798973bb79676e722b82f177206 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Fri, 23 Sep 2011 10:53:34 +0000 Subject: bonding: properly stop queuing work when requested During a test where a pair of bonding interfaces using ARP monitoring were both brought up and torn down (with an rmmod) repeatedly, a panic in the timer code was noticed. I tracked this down and determined that any of the bonding functions that ran as workqueue handlers and requeued more work might not properly exit when the module was removed. There was a flag protected by the bond lock called kill_timers that is set when the interface goes down or the module is removed, but many of the functions that monitor link status now unlock the bond lock to take rtnl first. There is a chance that another CPU running the rmmod could get the lock and set kill_timers after the first check has passed. This patch does not allow any function to queue work that will make itself run unless kill_timers is not set. I also noticed while doing this work that bond_resend_igmp_join_requests did not have a check for kill_timers, so I added the needed call there as well. Signed-off-by: Andy Gospodarek Reported-by: Liang Zheng Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 3 ++- drivers/net/bonding/bond_alb.c | 3 ++- drivers/net/bonding/bond_main.c | 13 ++++++++----- 3 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index a047eb973e3..47b928ed08f 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2168,7 +2168,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) } re_arm: - queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); + if (!bond->kill_timers) + queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); out: read_unlock(&bond->lock); } diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 7f8b20a34ee..d4fbd2e6261 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1440,7 +1440,8 @@ void bond_alb_monitor(struct work_struct *work) } re_arm: - queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); + if (!bond->kill_timers) + queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks); out: read_unlock(&bond->lock); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 43f2ea54108..6d79b78cfc7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -777,6 +777,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) read_lock(&bond->lock); + if (bond->kill_timers) + goto out; + /* rejoin all groups on bond device */ __bond_resend_igmp_join_requests(bond->dev); @@ -790,9 +793,9 @@ static void bond_resend_igmp_join_requests(struct bonding *bond) __bond_resend_igmp_join_requests(vlan_dev); } - if (--bond->igmp_retrans > 0) + if ((--bond->igmp_retrans > 0) && !bond->kill_timers) queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); - +out: read_unlock(&bond->lock); } @@ -2538,7 +2541,7 @@ void bond_mii_monitor(struct work_struct *work) } re_arm: - if (bond->params.miimon) + if (bond->params.miimon && !bond->kill_timers) queue_delayed_work(bond->wq, &bond->mii_work, msecs_to_jiffies(bond->params.miimon)); out: @@ -2886,7 +2889,7 @@ void bond_loadbalance_arp_mon(struct work_struct *work) } re_arm: - if (bond->params.arp_interval) + if (bond->params.arp_interval && !bond->kill_timers) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); out: read_unlock(&bond->lock); @@ -3154,7 +3157,7 @@ void bond_activebackup_arp_mon(struct work_struct *work) bond_ab_arp_probe(bond); re_arm: - if (bond->params.arp_interval) + if (bond->params.arp_interval && !bond->kill_timers) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); out: read_unlock(&bond->lock); -- cgit v1.2.3-70-g09d2 From d0e5d83284dac15c015bb48115b6780f5a6413cd Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 30 Sep 2011 06:37:51 +0000 Subject: net: xen-netback: correctly restart Tx after a VM restore/migrate If a VM is saved and restored (or migrated) the netback driver will no longer process any Tx packets from the frontend. xenvif_up() does not schedule the processing of any pending Tx requests from the front end because the carrier is off. Without this initial kick the frontend just adds Tx requests to the ring without raising an event (until the ring is full). This was caused by 47103041e91794acdbc6165da0ae288d844c820b (net: xen-netback: convert to hw_features) which reordered the calls to xenvif_up() and netif_carrier_on() in xenvif_connect(). Signed-off-by: David Vrabel Cc: Ian Campbell Acked-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 0ca86f9ec4e..182562952c7 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -327,12 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, xenvif_get(vif); rtnl_lock(); - if (netif_running(vif->dev)) - xenvif_up(vif); if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) dev_set_mtu(vif->dev, ETH_DATA_LEN); netdev_update_features(vif->dev); netif_carrier_on(vif->dev); + if (netif_running(vif->dev)) + xenvif_up(vif); rtnl_unlock(); return 0; -- cgit v1.2.3-70-g09d2 From 5f3a11419099d5cc010cfbfc524ca10d8fb81f89 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Sun, 25 Sep 2011 21:27:42 +0000 Subject: pch_gbe: Fixed the issue on which PC was frozen when link was downed. When a link was downed during network use, there is an issue on which PC freezes. This patch fixed this issue. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 567ff10889b..5474189d320 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -2195,7 +2195,7 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) /* If no Tx and not enough Rx work done, * exit the polling mode */ - if ((work_done < budget) || !netif_running(netdev)) + if (work_done < budget) poll_end_flag = true; } -- cgit v1.2.3-70-g09d2 From 805e969f6151eda7bc1a57e9c737054230acc3cc Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Sun, 25 Sep 2011 21:27:43 +0000 Subject: pch_gbe: Fixed the issue on which a network freezes The pch_gbe driver has an issue which a network stops, when receiving traffic is high. In the case, The link down and up are necessary to return a network. This patch fixed this issue. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 56 ++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 5474189d320..b8b4ba27b0e 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -1199,6 +1199,8 @@ static irqreturn_t pch_gbe_intr(int irq, void *data) iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR), &hw->reg->INT_EN); pch_gbe_stop_receive(adapter); + int_st |= ioread32(&hw->reg->INT_ST); + int_st = int_st & ioread32(&hw->reg->INT_EN); } if (int_st & PCH_GBE_INT_RX_DMA_ERR) adapter->stats.intr_rx_dma_err_count++; @@ -1218,14 +1220,11 @@ static irqreturn_t pch_gbe_intr(int irq, void *data) /* Set Pause packet */ pch_gbe_mac_set_pause_packet(hw); } - if ((int_en & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) - == 0) { - return IRQ_HANDLED; - } } /* When request status is Receive interruption */ - if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))) { + if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) || + (adapter->rx_stop_flag == true)) { if (likely(napi_schedule_prep(&adapter->napi))) { /* Enable only Rx Descriptor empty */ atomic_inc(&adapter->irq_sem); @@ -1385,7 +1384,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, struct sk_buff *skb; unsigned int i; unsigned int cleaned_count = 0; - bool cleaned = false; + bool cleaned = true; pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean); @@ -1396,7 +1395,6 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) { pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status); - cleaned = true; buffer_info = &tx_ring->buffer_info[i]; skb = buffer_info->skb; @@ -1439,8 +1437,10 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter, tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); /* weight of a sort for tx, to avoid endless transmit cleanup */ - if (cleaned_count++ == PCH_GBE_TX_WEIGHT) + if (cleaned_count++ == PCH_GBE_TX_WEIGHT) { + cleaned = false; break; + } } pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n", cleaned_count); @@ -2168,7 +2168,6 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) { struct pch_gbe_adapter *adapter = container_of(napi, struct pch_gbe_adapter, napi); - struct net_device *netdev = adapter->netdev; int work_done = 0; bool poll_end_flag = false; bool cleaned = false; @@ -2176,33 +2175,32 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget) pr_debug("budget : %d\n", budget); - /* Keep link state information with original netdev */ - if (!netif_carrier_ok(netdev)) { + pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget); + cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); + + if (!cleaned) + work_done = budget; + /* If no Tx and not enough Rx work done, + * exit the polling mode + */ + if (work_done < budget) poll_end_flag = true; - } else { - pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget); + + if (poll_end_flag) { + napi_complete(napi); + if (adapter->rx_stop_flag) { + adapter->rx_stop_flag = false; + pch_gbe_start_receive(&adapter->hw); + } + pch_gbe_irq_enable(adapter); + } else if (adapter->rx_stop_flag) { adapter->rx_stop_flag = false; pch_gbe_start_receive(&adapter->hw); int_en = ioread32(&adapter->hw.reg->INT_EN); iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR), - &adapter->hw.reg->INT_EN); + &adapter->hw.reg->INT_EN); } - cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring); - - if (cleaned) - work_done = budget; - /* If no Tx and not enough Rx work done, - * exit the polling mode - */ - if (work_done < budget) - poll_end_flag = true; - } - - if (poll_end_flag) { - napi_complete(napi); - pch_gbe_irq_enable(adapter); - } pr_debug("poll_end_flag : %d work_done : %d budget : %d\n", poll_end_flag, work_done, budget); -- cgit v1.2.3-70-g09d2 From 2c8fc867602e385fd2abe76da0b6bda8ed907547 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 3 Oct 2011 14:28:18 -0400 Subject: ide-disk: Fix request requeuing Simon Kirby reported that on his RAID setup with idedisk underneath the box OOMs after a couple of days of runtime. Running with CONFIG_DEBUG_KMEMLEAK pointed to idedisk_prep_fn() which unconditionally allocates an ide_cmd struct. However, ide_requeue_and_plug() can be called more than once per request, either from the request issue or the IRQ handler path and do blk_peek_request() ends up in idedisk_prep_fn() repeatedly, allocating a struct ide_cmd everytime and "forgetting" the previous pointer. Make sure the code reuses the old allocated chunk. Reported-and-tested-by: Simon Kirby Cc: [ 39.x, 3.0.x ] Link: http://marc.info/?l=linux-kernel&m=131667641517919 Link: http://lkml.kernel.org/r/20110922072643.GA27232@hostway.ca Signed-off-by: Borislav Petkov Signed-off-by: David S. Miller --- drivers/ide/ide-disk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 274798068a5..16f69be820c 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -435,7 +435,12 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq) if (!(rq->cmd_flags & REQ_FLUSH)) return BLKPREP_OK; - cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + if (rq->special) { + cmd = rq->special; + memset(cmd, 0, sizeof(*cmd)); + } else { + cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC); + } /* FIXME: map struct ide_taskfile on rq->cmd[] */ BUG_ON(cmd == NULL); -- cgit v1.2.3-70-g09d2 From 05faadcf59507e8eea57ffbeea9cbb14c9a2ab3d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 3 Oct 2011 18:09:14 -0700 Subject: lis3: fix regression of HP DriveGuard with 8bit chip Commit 2a7fade7e03 ("hwmon: lis3: Power on corrections") caused a regression on HP laptops with 8bit chip. Writing CTRL2_BOOT_8B bit seems clearing the BIOS setup, and no proper interrupt for DriveGuard will be triggered any more. Since the init code there is basically only for embedded devices, put a pdata check so that the problematic initialization will be skipped for hp_accel stuff. Signed-off-by: Takashi Iwai Cc: Eric Piel Cc: Samu Onkalo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/lis3lv02d/lis3lv02d.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index b928bc14e97..8b51cd62d06 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -375,12 +375,14 @@ void lis3lv02d_poweron(struct lis3lv02d *lis3) * both have been read. So the value read will always be correct. * Set BOOT bit to refresh factory tuning values. */ - lis3->read(lis3, CTRL_REG2, ®); - if (lis3->whoami == WAI_12B) - reg |= CTRL2_BDU | CTRL2_BOOT; - else - reg |= CTRL2_BOOT_8B; - lis3->write(lis3, CTRL_REG2, reg); + if (lis3->pdata) { + lis3->read(lis3, CTRL_REG2, ®); + if (lis3->whoami == WAI_12B) + reg |= CTRL2_BDU | CTRL2_BOOT; + else + reg |= CTRL2_BOOT_8B; + lis3->write(lis3, CTRL_REG2, reg); + } /* LIS3 power on delay is quite long */ msleep(lis3->pwron_delay / lis3lv02d_get_odr()); -- cgit v1.2.3-70-g09d2 From 27504be5c10bdc61761ec0126b3645428598ad91 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:34 +0900 Subject: spi-topcliff-pch: add tx-memory clear after complete transmitting Currently, in case of reading date from SPI flash, command is sent twice. The cause is that tx-memory clear processing is missing . This patch adds the tx-momory clear processing. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 1d23f383186..7a98caa3aed 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -837,6 +837,11 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, DMA_FROM_DEVICE); + + dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent, + DMA_FROM_DEVICE); + memset(data->dma.tx_buf_virt, 0, PAGE_SIZE); + async_tx_ack(dma->desc_rx); async_tx_ack(dma->desc_tx); kfree(dma->sg_tx_p); -- cgit v1.2.3-70-g09d2 From 8b7aa961a815dad389525dcd1c36a44c249b1760 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:35 +0900 Subject: spi-topcliff-pch: Fix SSN Control issue During processing 1 command/data series, SSN should keep LOW. However, currently, SSN becomes HIGH. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 7a98caa3aed..c36d5165706 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -58,6 +58,7 @@ #define PCH_SLEEP_TIME 10 #define SSN_LOW 0x02U +#define SSN_HIGH 0x03U #define SSN_NO_CONTROL 0x00U #define PCH_MAX_CS 0xFF #define PCI_DEVICE_ID_GE_SPI 0x8816 @@ -756,10 +757,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data) wait_event_interruptible(data->wait, data->transfer_complete); - pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); - dev_dbg(&data->master->dev, - "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); - /* clear all interrupts */ pch_spi_writereg(data->master, PCH_SPSR, pch_spi_readreg(data->master, PCH_SPSR)); @@ -848,9 +845,6 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) kfree(dma->sg_rx_p); spin_lock_irqsave(&data->lock, flags); - pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); - dev_dbg(&data->master->dev, - "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); /* clear fifo threshold, disable interrupts, disable SPI transfer */ pch_spi_setclr_reg(data->master, PCH_SPCR, 0, @@ -1167,6 +1161,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) if (data->use_dma) pch_spi_request_dma(data, data->current_msg->spi->bits_per_word); + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); do { /* If we are already processing a message get the next transfer structure from the message otherwise retrieve @@ -1227,6 +1222,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) } while (data->cur_trans != NULL); + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); if (data->use_dma) pch_spi_release_dma(data); } -- cgit v1.2.3-70-g09d2 From 373b0eb64b9c97a14720896dcfdebfa3268b1991 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:36 +0900 Subject: spi-topcliff-pch: Fix CPU read complete condition issue We found Rx data sometimes drops.(with non-DMA transfer mode) The cause is read complete condition is not true. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index c36d5165706..6cb2fdbe5db 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -317,16 +317,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, /* if transfer complete interrupt */ if (reg_spsr_val & SPSR_FI_BIT) { - if (tx_index < bpw_len) + if ((tx_index == bpw_len) && (rx_index == tx_index)) { + /* disable interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); + + /* transfer is completed; + inform pch_spi_process_messages */ + data->transfer_complete = true; + data->transfer_active = false; + wake_up(&data->wait); + } else { dev_err(&data->master->dev, "%s : Transfer is not completed", __func__); - /* disable interrupts */ - pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); - - /* transfer is completed;inform pch_spi_process_messages */ - data->transfer_complete = true; - data->transfer_active = false; - wake_up(&data->wait); + } } } -- cgit v1.2.3-70-g09d2 From 25e803f9c339a070cd7361e853aebde11b1f9217 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:37 +0900 Subject: spi-topcliff-pch: Add recovery processing in case FIFO overrun error occurs Add recovery processing in case FIFO overrun error occurs with DMA transfer mode. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 6cb2fdbe5db..c8efa757fda 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -352,16 +352,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) "%s returning due to suspend\n", __func__); return IRQ_NONE; } - if (data->use_dma) - return IRQ_NONE; io_remap_addr = data->io_remap_addr; spsr = io_remap_addr + PCH_SPSR; reg_spsr_val = ioread32(spsr); - if (reg_spsr_val & SPSR_ORF_BIT) - dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); + if (reg_spsr_val & SPSR_ORF_BIT) { + dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__); + if (data->current_msg->complete != 0) { + data->transfer_complete = true; + data->current_msg->status = -EIO; + data->current_msg->complete(data->current_msg->context); + data->bcurrent_msg_processing = false; + data->current_msg = NULL; + data->cur_trans = NULL; + } + } + + if (data->use_dma) + return IRQ_NONE; /* Check if the interrupt is for SPI device */ if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { @@ -815,10 +825,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) } } -static void pch_spi_start_transfer(struct pch_spi_data *data) +static int pch_spi_start_transfer(struct pch_spi_data *data) { struct pch_spi_dma_ctrl *dma; unsigned long flags; + int rtn; dma = &data->dma; @@ -833,7 +844,9 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) initiating the transfer. */ dev_dbg(&data->master->dev, "%s:waiting for transfer to get over\n", __func__); - wait_event_interruptible(data->wait, data->transfer_complete); + rtn = wait_event_interruptible_timeout(data->wait, + data->transfer_complete, + msecs_to_jiffies(2 * HZ)); dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, DMA_FROM_DEVICE); @@ -860,6 +873,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) pch_spi_clear_fifo(data->master); spin_unlock_irqrestore(&data->lock, flags); + + return rtn; } static void pch_dma_rx_complete(void *arg) @@ -1187,7 +1202,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) if (data->use_dma) { pch_spi_handle_dma(data, &bpw); - pch_spi_start_transfer(data); + if (!pch_spi_start_transfer(data)) + goto out; pch_spi_copy_rx_data_for_dma(data, bpw); } else { pch_spi_set_tx(data, &bpw); @@ -1225,6 +1241,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) } while (data->cur_trans != NULL); +out: pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); if (data->use_dma) pch_spi_release_dma(data); -- cgit v1.2.3-70-g09d2 From f3e03e2eb0bcd9266720695b82a523e6bc526ff7 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:38 +0900 Subject: spi-topcliff-pch: Fix overrun issue We found that adding load, Rx data sometimes drops.(with DMA transfer mode) The cause is that before starting Rx-DMA processing, Tx-DMA processing starts. This causes FIFO overrun occurs. This patch fixes the issue by modifying FIFO tx-threshold and DMA descriptor size like below. Current this patch Rx-descriptor 4Byte+12Byte*341 --> 12Byte*340-4Byte-12Byte Rx-threshold (Not modified) Tx-descriptor 4Byte+12Byte*341 --> 16Byte-12Byte*340 Rx-threshold 12Byte --> 2Byte Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index c8efa757fda..6a80749391d 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -50,6 +50,8 @@ #define PCH_RX_THOLD 7 #define PCH_RX_THOLD_MAX 15 +#define PCH_TX_THOLD 2 + #define PCH_MAX_BAUDRATE 5000000 #define PCH_MAX_FIFO_DEPTH 16 @@ -1040,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* set receive fifo threshold and transmit fifo threshold */ pch_spi_setclr_reg(data->master, PCH_SPCR, ((size - 1) << SPCR_RFIC_FIELD) | - ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) << - SPCR_TFIC_FIELD), + (PCH_TX_THOLD << SPCR_TFIC_FIELD), MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); spin_unlock_irqrestore(&data->lock, flags); @@ -1052,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* offset, length setting */ sg = dma->sg_rx_p; for (i = 0; i < num; i++, sg++) { - if (i == 0) { - sg->offset = 0; + if (i == (num - 2)) { + sg->offset = size * i; + sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, sg->offset); sg_dma_len(sg) = rem; + } else if (i == (num - 1)) { + sg->offset = size * (i - 1) + rem; + sg->offset = sg->offset * (*bpw / 8); + sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, + sg->offset); + sg_dma_len(sg) = size; } else { - sg->offset = rem + size * (i - 1); + sg->offset = size * i; sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, sg->offset); @@ -1082,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) dma->desc_rx = desc_rx; /* TX */ + if (data->bpw_len > PCH_DMA_TRANS_SIZE) { + num = data->bpw_len / PCH_DMA_TRANS_SIZE; + size = PCH_DMA_TRANS_SIZE; + rem = 16; + } else { + num = 1; + size = data->bpw_len; + rem = data->bpw_len; + } + dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */ -- cgit v1.2.3-70-g09d2 From 12d5180bd7e683a4ae80830b82ba67e7b7fac7b2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 4 Oct 2011 10:46:34 -0400 Subject: drm/radeon/kms: fix channel_remap setup (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most asics just use the hw default value which requires no explicit programming. For those that need a different value, the vbios will program it properly. As such, there's no need to program these registers explicitly in the driver. Changing MC_SHARED_CHREMAP requires a reload of all data in vram otherwise its contents will be scambled. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=40103 v2: drop now unused channel_remap functions. Signed-off-by: Alex Deucher Reviewed-by: Michel Dänzer Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 44 -------------------------------- drivers/gpu/drm/radeon/ni.c | 32 ------------------------ drivers/gpu/drm/radeon/rv770.c | 51 -------------------------------------- 3 files changed, 127 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e8a746712b5..c4ffa14fb2f 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1590,48 +1590,6 @@ static u32 evergreen_get_tile_pipe_to_backend_map(struct radeon_device *rdev, return backend_map; } -static void evergreen_program_channel_remap(struct radeon_device *rdev) -{ - u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp; - - tmp = RREG32(MC_SHARED_CHMAP); - switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { - case 0: - case 1: - case 2: - case 3: - default: - /* default mapping */ - mc_shared_chremap = 0x00fac688; - break; - } - - switch (rdev->family) { - case CHIP_HEMLOCK: - case CHIP_CYPRESS: - case CHIP_BARTS: - tcp_chan_steer_lo = 0x54763210; - tcp_chan_steer_hi = 0x0000ba98; - break; - case CHIP_JUNIPER: - case CHIP_REDWOOD: - case CHIP_CEDAR: - case CHIP_PALM: - case CHIP_SUMO: - case CHIP_SUMO2: - case CHIP_TURKS: - case CHIP_CAICOS: - default: - tcp_chan_steer_lo = 0x76543210; - tcp_chan_steer_hi = 0x0000ba98; - break; - } - - WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo); - WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi); - WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); -} - static void evergreen_gpu_init(struct radeon_device *rdev) { u32 cc_rb_backend_disable = 0; @@ -2078,8 +2036,6 @@ static void evergreen_gpu_init(struct radeon_device *rdev) WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); - evergreen_program_channel_remap(rdev); - num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; grbm_gfx_index = INSTANCE_BROADCAST_WRITES; diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 99fbd793c08..8c79ca97753 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -569,36 +569,6 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev, return backend_map; } -static void cayman_program_channel_remap(struct radeon_device *rdev) -{ - u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp; - - tmp = RREG32(MC_SHARED_CHMAP); - switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { - case 0: - case 1: - case 2: - case 3: - default: - /* default mapping */ - mc_shared_chremap = 0x00fac688; - break; - } - - switch (rdev->family) { - case CHIP_CAYMAN: - default: - //tcp_chan_steer_lo = 0x54763210 - tcp_chan_steer_lo = 0x76543210; - tcp_chan_steer_hi = 0x0000ba98; - break; - } - - WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo); - WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi); - WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); -} - static u32 cayman_get_disable_mask_per_asic(struct radeon_device *rdev, u32 disable_mask_per_se, u32 max_disable_mask_per_se, @@ -842,8 +812,6 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(DMIF_ADDR_CONFIG, gb_addr_config); WREG32(HDP_ADDR_CONFIG, gb_addr_config); - cayman_program_channel_remap(rdev); - /* primary versions */ WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CC_SYS_RB_BACKEND_DISABLE, cc_rb_backend_disable); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4720d000d44..b13c2eedc32 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -536,55 +536,6 @@ static u32 r700_get_tile_pipe_to_backend_map(struct radeon_device *rdev, return backend_map; } -static void rv770_program_channel_remap(struct radeon_device *rdev) -{ - u32 tcp_chan_steer, mc_shared_chremap, tmp; - bool force_no_swizzle; - - switch (rdev->family) { - case CHIP_RV770: - case CHIP_RV730: - force_no_swizzle = false; - break; - case CHIP_RV710: - case CHIP_RV740: - default: - force_no_swizzle = true; - break; - } - - tmp = RREG32(MC_SHARED_CHMAP); - switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { - case 0: - case 1: - default: - /* default mapping */ - mc_shared_chremap = 0x00fac688; - break; - case 2: - case 3: - if (force_no_swizzle) - mc_shared_chremap = 0x00fac688; - else - mc_shared_chremap = 0x00bbc298; - break; - } - - if (rdev->family == CHIP_RV740) - tcp_chan_steer = 0x00ef2a60; - else - tcp_chan_steer = 0x00fac688; - - /* RV770 CE has special chremap setup */ - if (rdev->pdev->device == 0x944e) { - tcp_chan_steer = 0x00b08b08; - mc_shared_chremap = 0x00b08b08; - } - - WREG32(TCP_CHAN_STEER, tcp_chan_steer); - WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); -} - static void rv770_gpu_init(struct radeon_device *rdev) { int i, j, num_qd_pipes; @@ -785,8 +736,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); - rv770_program_channel_remap(rdev); - WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); -- cgit v1.2.3-70-g09d2 From 5f39e6705faade2e89d119958a8c51b9b6e2c53c Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Mon, 3 Oct 2011 09:50:20 -0500 Subject: PCI: Disable MPS configuration by default Add the ability to disable PCI-E MPS turning and using the BIOS configured MPS defaults. Due to the number of issues recently discovered on some x86 chipsets, make this the default behavior. Also, add the option for peer to peer DMA MPS configuration. Peer to peer DMA is outside the scope of this patch, but MPS configuration could prevent it from working by having the MPS on one root port different than the MPS on another. To work around this, simply make the system wide MPS the smallest possible value (128B). Signed-off-by: Jon Mason Acked-by: Benjamin Herrenschmidt Signed-off-by: Linus Torvalds --- drivers/pci/pci.c | 6 +++++- drivers/pci/probe.c | 14 +++++++++++++- include/linux/pci.h | 3 ++- 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4e84fd4a431..e9651f0a881 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -77,7 +77,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; -enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; /* * The default CLS is used if arch didn't set CLS explicitly and not @@ -3568,10 +3568,14 @@ static int __init pci_setup(char *str) pci_hotplug_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "hpmemsize=", 10)) { pci_hotplug_mem_size = memparse(str + 10, &str); + } else if (!strncmp(str, "pcie_bus_tune_off", 17)) { + pcie_bus_config = PCIE_BUS_TUNE_OFF; } else if (!strncmp(str, "pcie_bus_safe", 13)) { pcie_bus_config = PCIE_BUS_SAFE; } else if (!strncmp(str, "pcie_bus_perf", 13)) { pcie_bus_config = PCIE_BUS_PERFORMANCE; + } else if (!strncmp(str, "pcie_bus_peer2peer", 18)) { + pcie_bus_config = PCIE_BUS_PEER2PEER; } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f3f94a5c068..6ab6bd3df4b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1458,12 +1458,24 @@ static int pcie_bus_configure_set(struct pci_dev *dev, void *data) */ void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss) { - u8 smpss = mpss; + u8 smpss; if (!pci_is_pcie(bus->self)) return; + if (pcie_bus_config == PCIE_BUS_TUNE_OFF) + return; + + /* FIXME - Peer to peer DMA is possible, though the endpoint would need + * to be aware to the MPS of the destination. To work around this, + * simply force the MPS of the entire system to the smallest possible. + */ + if (pcie_bus_config == PCIE_BUS_PEER2PEER) + smpss = 0; + if (pcie_bus_config == PCIE_BUS_SAFE) { + smpss = mpss; + pcie_find_smpss(bus->self, &smpss); pci_walk_bus(bus, pcie_find_smpss, &smpss); } diff --git a/include/linux/pci.h b/include/linux/pci.h index 8c230cbcbb4..9fc01226055 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -621,8 +621,9 @@ struct pci_driver { extern void pcie_bus_configure_settings(struct pci_bus *bus, u8 smpss); enum pcie_bus_config_types { - PCIE_BUS_PERFORMANCE, + PCIE_BUS_TUNE_OFF, PCIE_BUS_SAFE, + PCIE_BUS_PERFORMANCE, PCIE_BUS_PEER2PEER, }; -- cgit v1.2.3-70-g09d2