From 4f14faaab4ee46a046b6baff85644be199de718c Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 28 Nov 2011 11:49:03 -0500 Subject: xen/blkback: use grant-table.c hypercall wrappers Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 0088bf6..3174353 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -321,6 +321,7 @@ struct seg_buf { static void xen_blkbk_unmap(struct pending_req *req) { struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; unsigned int i, invcount = 0; grant_handle_t handle; int ret; @@ -332,25 +333,12 @@ static void xen_blkbk_unmap(struct pending_req *req) gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i), GNTMAP_host_map, handle); pending_handle(req, i) = BLKBACK_INVALID_HANDLE; + pages[invcount] = virt_to_page(vaddr(req, i)); invcount++; } - ret = HYPERVISOR_grant_table_op( - GNTTABOP_unmap_grant_ref, unmap, invcount); + ret = gnttab_unmap_refs(unmap, pages, invcount, false); BUG_ON(ret); - /* - * Note, we use invcount, so nr->pages, so we can't index - * using vaddr(req, i). - */ - for (i = 0; i < invcount; i++) { - ret = m2p_remove_override( - virt_to_page(unmap[i].host_addr), false); - if (ret) { - pr_alert(DRV_PFX "Failed to remove M2P override for %lx\n", - (unsigned long)unmap[i].host_addr); - continue; - } - } } static int xen_blkbk_map(struct blkif_request *req, @@ -378,7 +366,7 @@ static int xen_blkbk_map(struct blkif_request *req, pending_req->blkif->domid); } - ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg); + ret = gnttab_map_refs(map, NULL, &blkbk->pending_page(pending_req, 0), nseg); BUG_ON(ret); /* @@ -398,15 +386,6 @@ static int xen_blkbk_map(struct blkif_request *req, if (ret) continue; - ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), - blkbk->pending_page(pending_req, i), NULL); - if (ret) { - pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n", - (unsigned long)map[i].dev_bus_addr, ret); - /* We could switch over to GNTTABOP_copy */ - continue; - } - seg[i].buf = map[i].dev_bus_addr | (req->u.rw.seg[i].first_sect << 9); } -- cgit v0.10.2 From b2167ba6dd89d55ced26a867fad8f0fe388fd595 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Mon, 28 Nov 2011 11:49:05 -0500 Subject: xen/blkback: Enable blkback on HVM guests Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 3174353..70caa89 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -809,7 +809,7 @@ static int __init xen_blkif_init(void) int i, mmap_pages; int rc = 0; - if (!xen_pv_domain()) + if (!xen_domain()) return -ENODEV; blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL); -- cgit v0.10.2 From 34ae2e47d97216d8c66a1c5dff5b530c29b746b8 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 21 Jan 2012 00:15:26 +0900 Subject: xen-blkfront: use bitmap_set() and bitmap_clear() Use bitmap_set and bitmap_clear rather than modifying individual bits in a memory region. Signed-off-by: Akinobu Mita Cc: Jeremy Fitzhardinge Cc: Konrad Rzeszutek Wilk Cc: xen-devel@lists.xensource.com Cc: virtualization@lists.linux-foundation.org Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 2f22874..619868d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -177,8 +178,7 @@ static int xlbd_reserve_minors(unsigned int minor, unsigned int nr) spin_lock(&minor_lock); if (find_next_bit(minors, end, minor) >= end) { - for (; minor < end; ++minor) - __set_bit(minor, minors); + bitmap_set(minors, minor, nr); rc = 0; } else rc = -EBUSY; @@ -193,8 +193,7 @@ static void xlbd_release_minors(unsigned int minor, unsigned int nr) BUG_ON(end > nr_minors); spin_lock(&minor_lock); - for (; minor < end; ++minor) - __clear_bit(minor, minors); + bitmap_clear(minors, minor, nr); spin_unlock(&minor_lock); } -- cgit v0.10.2 From dad5cf659b202b5070c8616b5c515f6ca4db0c42 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 16 Feb 2012 13:16:25 +0100 Subject: xen/blkfront: don't put bdev right after getting it We should hang onto bdev until we're done with it. Signed-off-by: Andrew Jones [v1: Fixed up git commit description] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 619868d..537cb72 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1409,7 +1409,6 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) mutex_lock(&blkfront_mutex); bdev = bdget_disk(disk, 0); - bdput(bdev); if (bdev->bd_openers) goto out; @@ -1440,6 +1439,7 @@ static int blkif_release(struct gendisk *disk, fmode_t mode) } out: + bdput(bdev); mutex_unlock(&blkfront_mutex); return 0; } -- cgit v0.10.2 From 3467811e26660eb46bc655234573d22d6876d5f9 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Fri, 17 Feb 2012 12:04:44 -0800 Subject: xen-blkfront: make blkif_io_lock spinlock per-device This patch moves the global blkif_io_lock to the per-device structure. The spinlock seems to exists for two reasons: to disable IRQs when in the interrupt handlers for blkfront, and to protect the blkfront VBDs when a detachment is requested. Having a global blkif_io_lock doesn't make sense given the use case, and it drastically hinders performance due to contention. All VBDs with pending IOs have to take the lock in order to get work done, which serializes everything pretty badly. Signed-off-by: Steven Noonan Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 537cb72..5d9c559 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -82,6 +82,7 @@ static const struct block_device_operations xlvbd_block_fops; */ struct blkfront_info { + spinlock_t io_lock; struct mutex mutex; struct xenbus_device *xbdev; struct gendisk *gd; @@ -106,8 +107,6 @@ struct blkfront_info int is_ready; }; -static DEFINE_SPINLOCK(blkif_io_lock); - static unsigned int nr_minors; static unsigned long *minors; static DEFINE_SPINLOCK(minor_lock); @@ -418,7 +417,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) struct request_queue *rq; struct blkfront_info *info = gd->private_data; - rq = blk_init_queue(do_blkif_request, &blkif_io_lock); + rq = blk_init_queue(do_blkif_request, &info->io_lock); if (rq == NULL) return -1; @@ -635,14 +634,14 @@ static void xlvbd_release_gendisk(struct blkfront_info *info) if (info->rq == NULL) return; - spin_lock_irqsave(&blkif_io_lock, flags); + spin_lock_irqsave(&info->io_lock, flags); /* No more blkif_request(). */ blk_stop_queue(info->rq); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); /* Flush gnttab callback work. Must be done with no locks held. */ flush_work_sync(&info->work); @@ -674,16 +673,16 @@ static void blkif_restart_queue(struct work_struct *work) { struct blkfront_info *info = container_of(work, struct blkfront_info, work); - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); if (info->connected == BLKIF_STATE_CONNECTED) kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); } static void blkif_free(struct blkfront_info *info, int suspend) { /* Prevent new requests being issued until we fix things up. */ - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); info->connected = suspend ? BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED; /* No more blkif_request(). */ @@ -691,7 +690,7 @@ static void blkif_free(struct blkfront_info *info, int suspend) blk_stop_queue(info->rq); /* No more gnttab callback work. */ gnttab_cancel_free_callback(&info->callback); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); /* Flush gnttab callback work. Must be done with no locks held. */ flush_work_sync(&info->work); @@ -727,10 +726,10 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) struct blkfront_info *info = (struct blkfront_info *)dev_id; int error; - spin_lock_irqsave(&blkif_io_lock, flags); + spin_lock_irqsave(&info->io_lock, flags); if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) { - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); return IRQ_HANDLED; } @@ -815,7 +814,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) kick_pending_request_queues(info); - spin_unlock_irqrestore(&blkif_io_lock, flags); + spin_unlock_irqrestore(&info->io_lock, flags); return IRQ_HANDLED; } @@ -990,6 +989,7 @@ static int blkfront_probe(struct xenbus_device *dev, } mutex_init(&info->mutex); + spin_lock_init(&info->io_lock); info->xbdev = dev; info->vdevice = vdevice; info->connected = BLKIF_STATE_DISCONNECTED; @@ -1067,7 +1067,7 @@ static int blkif_recover(struct blkfront_info *info) xenbus_switch_state(info->xbdev, XenbusStateConnected); - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); /* Now safe for us to use the shared ring */ info->connected = BLKIF_STATE_CONNECTED; @@ -1078,7 +1078,7 @@ static int blkif_recover(struct blkfront_info *info) /* Kick any other new requests queued since we resumed */ kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); return 0; } @@ -1276,10 +1276,10 @@ static void blkfront_connect(struct blkfront_info *info) xenbus_switch_state(info->xbdev, XenbusStateConnected); /* Kick pending requests. */ - spin_lock_irq(&blkif_io_lock); + spin_lock_irq(&info->io_lock); info->connected = BLKIF_STATE_CONNECTED; kick_pending_request_queues(info); - spin_unlock_irq(&blkif_io_lock); + spin_unlock_irq(&info->io_lock); add_disk(info->gd); -- cgit v0.10.2 From 395d287526bb60411ff37b19ad9dd38b58ba8732 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 22 Mar 2012 21:40:08 +0100 Subject: cciss: Initialize scsi host max_sectors for tape drive support The default is too small (1024 blocks), use h->cciss_max_sectors (8192 blocks) Without this change, if you try to set the block size of a tape drive above 512*1024, via "mt -f /dev/st0 setblk nnn" where nnn is greater than 524288, it won't work right. Signed-off-by: Stephen M. Cameron Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index e820b68..f510a9c 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -866,6 +866,7 @@ cciss_scsi_detect(ctlr_info_t *h) sh->can_queue = cciss_tape_cmds; sh->sg_tablesize = h->maxsgentries; sh->max_cmd_len = MAX_COMMAND_SIZE; + sh->max_sectors = h->cciss_max_sectors; ((struct cciss_scsi_adapter_data_t *) h->scsi_ctlr)->scsi_host = sh; -- cgit v0.10.2 From bc67f63650fad6b3478d9ddfd5406d45a95987c9 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 22 Mar 2012 21:40:09 +0100 Subject: cciss: Fix scsi tape io with more than 255 scatter gather elements The total number of scatter gather elements in the CISS command used by the scsi tape code was being cast to a u8, which can hold at most 255 scatter gather elements. It should have been cast to a u16. Without this patch the command gets rejected by the controller since the total scatter gather count did not add up to the right value resulting in an i/o error. Signed-off-by: Stephen M. Cameron Cc: stable@vger.kernel.org Signed-off-by: Jens Axboe diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index f510a9c..acda773 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1411,7 +1411,7 @@ static void cciss_scatter_gather(ctlr_info_t *h, CommandList_struct *c, /* track how many SG entries we are using */ if (request_nsgs > h->maxSG) h->maxSG = request_nsgs; - c->Header.SGTotal = (__u8) request_nsgs + chained; + c->Header.SGTotal = (u16) request_nsgs + chained; if (request_nsgs > h->max_cmd_sgentries) c->Header.SGList = h->max_cmd_sgentries; else -- cgit v0.10.2 From 00380a404fc4235e9b8b39598138bd3223a27b8a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 23 Mar 2012 09:58:54 +0100 Subject: block: blk_alloc_queue_node(): use caller's GFP flags instead of GFP_KERNEL We should use the GFP flags that the caller specified instead of picking our own. All the callers specify GFP_KERNEL so this doesn't make a difference to how the kernel runs, it's just a cleanup. Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 3a78b00..414e822 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -483,7 +483,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) if (!q) return NULL; - q->id = ida_simple_get(&blk_queue_ida, 0, 0, GFP_KERNEL); + q->id = ida_simple_get(&blk_queue_ida, 0, 0, gfp_mask); if (q->id < 0) goto fail_q; -- cgit v0.10.2 From 22be2e6e13ac09b20000582ac34d47fb0029a6da Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Fri, 23 Mar 2012 12:33:03 +0100 Subject: mtip32xx: fix incorrect value set for drv_cleanup_done, and re-initialize and start port in mtip_restart_port() This patch includes two changes: * fix incorrect value set for drv_cleanup_done * re-initialize and start port in mtip_restart_port() Signed-off-by: Asai Thambi S P Signed-off-by: Sam Bradshaw Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 8eb81c9..04f69e6da 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -422,6 +422,10 @@ static void mtip_init_port(struct mtip_port *port) /* Clear any pending interrupts for this port */ writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + /* Clear any pending interrupts on the HBA. */ + writel(readl(port->dd->mmio + HOST_IRQ_STAT), + port->dd->mmio + HOST_IRQ_STAT); + /* Enable port interrupts */ writel(DEF_PORT_IRQ, port->mmio + PORT_IRQ_MASK); } @@ -490,11 +494,9 @@ static void mtip_restart_port(struct mtip_port *port) dev_warn(&port->dd->pdev->dev, "COM reset failed\n"); - /* Clear SError, the PxSERR.DIAG.x should be set so clear it */ - writel(readl(port->mmio + PORT_SCR_ERR), port->mmio + PORT_SCR_ERR); + mtip_init_port(port); + mtip_start_port(port); - /* Enable the DMA engine */ - mtip_enable_engine(port, 1); } /* @@ -3359,9 +3361,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - /* Set the atomic variable as 1 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); - atomic_set(&dd->resumeflag, false); /* Attach the private data to this PCI device. */ @@ -3434,8 +3433,8 @@ iomap_err: pci_set_drvdata(pdev, NULL); return rv; done: - /* Set the atomic variable as 0 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); + /* Set the atomic variable as 0 */ + atomic_set(&dd->drv_cleanup_done, false); return rv; } @@ -3463,8 +3462,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) } } } - /* Set the atomic variable as 1 in case of SRSI */ - atomic_set(&dd->drv_cleanup_done, true); /* Clean up the block layer. */ mtip_block_remove(dd); -- cgit v0.10.2 From 275029353953c2117941ade84f02a2303912fad1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Mar 2012 13:36:42 -0700 Subject: ioat: fix size of 'completion' for Xen Starting with v3.2 Jonathan reports that Xen crashes loading the ioatdma driver. A debug run shows: ioatdma 0000:00:16.4: desc[0]: (0x300cc7000->0x300cc7040) cookie: 0 flags: 0x2 ctl: 0x29 (op: 0 int_en: 1 compl: 1) ... ioatdma 0000:00:16.4: ioat_get_current_completion: phys_complete: 0xcc7000 ...which shows that in this environment GFP_KERNEL memory may be backed by a 64-bit dma address. This breaks the driver's assumption that an unsigned long should be able to contain the physical address for descriptor memory. Switch to dma_addr_t which beyond being the right size, is the true type for the data i.e. an io-virtual address inidicating the engine's last processed descriptor. [stable: 3.2+] Cc: Reported-by: Jonathan Nieder Reported-by: William Dauchy Tested-by: William Dauchy Tested-by: Dave Jiang Signed-off-by: Dan Williams diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index a4d6cb0..6595180 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -548,9 +548,9 @@ void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags, PCI_DMA_TODEVICE, flags, 0); } -unsigned long ioat_get_current_completion(struct ioat_chan_common *chan) +dma_addr_t ioat_get_current_completion(struct ioat_chan_common *chan) { - unsigned long phys_complete; + dma_addr_t phys_complete; u64 completion; completion = *chan->completion; @@ -571,7 +571,7 @@ unsigned long ioat_get_current_completion(struct ioat_chan_common *chan) } bool ioat_cleanup_preamble(struct ioat_chan_common *chan, - unsigned long *phys_complete) + dma_addr_t *phys_complete) { *phys_complete = ioat_get_current_completion(chan); if (*phys_complete == chan->last_completion) @@ -582,14 +582,14 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan, return true; } -static void __cleanup(struct ioat_dma_chan *ioat, unsigned long phys_complete) +static void __cleanup(struct ioat_dma_chan *ioat, dma_addr_t phys_complete) { struct ioat_chan_common *chan = &ioat->base; struct list_head *_desc, *n; struct dma_async_tx_descriptor *tx; - dev_dbg(to_dev(chan), "%s: phys_complete: %lx\n", - __func__, phys_complete); + dev_dbg(to_dev(chan), "%s: phys_complete: %llx\n", + __func__, (unsigned long long) phys_complete); list_for_each_safe(_desc, n, &ioat->used_desc) { struct ioat_desc_sw *desc; @@ -655,7 +655,7 @@ static void __cleanup(struct ioat_dma_chan *ioat, unsigned long phys_complete) static void ioat1_cleanup(struct ioat_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - unsigned long phys_complete; + dma_addr_t phys_complete; prefetch(chan->completion); @@ -701,7 +701,7 @@ static void ioat1_timer_event(unsigned long data) mod_timer(&chan->timer, jiffies + COMPLETION_TIMEOUT); spin_unlock_bh(&ioat->desc_lock); } else if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) { - unsigned long phys_complete; + dma_addr_t phys_complete; spin_lock_bh(&ioat->desc_lock); /* if we haven't made progress and we have already diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index 5216c8a..8bebddd 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -88,7 +88,7 @@ struct ioatdma_device { struct ioat_chan_common { struct dma_chan common; void __iomem *reg_base; - unsigned long last_completion; + dma_addr_t last_completion; spinlock_t cleanup_lock; dma_cookie_t completed_cookie; unsigned long state; @@ -333,7 +333,7 @@ int __devinit ioat_dma_self_test(struct ioatdma_device *device); void __devexit ioat_dma_remove(struct ioatdma_device *device); struct dca_provider * __devinit ioat_dca_init(struct pci_dev *pdev, void __iomem *iobase); -unsigned long ioat_get_current_completion(struct ioat_chan_common *chan); +dma_addr_t ioat_get_current_completion(struct ioat_chan_common *chan); void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *chan, int idx); enum dma_status ioat_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie, @@ -341,7 +341,7 @@ enum dma_status ioat_dma_tx_status(struct dma_chan *c, dma_cookie_t cookie, void ioat_dma_unmap(struct ioat_chan_common *chan, enum dma_ctrl_flags flags, size_t len, struct ioat_dma_descriptor *hw); bool ioat_cleanup_preamble(struct ioat_chan_common *chan, - unsigned long *phys_complete); + dma_addr_t *phys_complete); void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type); void ioat_kobject_del(struct ioatdma_device *device); extern const struct sysfs_ops ioat_sysfs_ops; diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 5d65f83..cb8864d 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -126,7 +126,7 @@ static void ioat2_start_null_desc(struct ioat2_dma_chan *ioat) spin_unlock_bh(&ioat->prep_lock); } -static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete) +static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) { struct ioat_chan_common *chan = &ioat->base; struct dma_async_tx_descriptor *tx; @@ -178,7 +178,7 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete) static void ioat2_cleanup(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - unsigned long phys_complete; + dma_addr_t phys_complete; spin_lock_bh(&chan->cleanup_lock); if (ioat_cleanup_preamble(chan, &phys_complete)) @@ -259,7 +259,7 @@ int ioat2_reset_sync(struct ioat_chan_common *chan, unsigned long tmo) static void ioat2_restart_channel(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - unsigned long phys_complete; + dma_addr_t phys_complete; ioat2_quiesce(chan, 0); if (ioat_cleanup_preamble(chan, &phys_complete)) @@ -274,7 +274,7 @@ void ioat2_timer_event(unsigned long data) struct ioat_chan_common *chan = &ioat->base; if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) { - unsigned long phys_complete; + dma_addr_t phys_complete; u64 status; status = ioat_chansts(chan); diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index f519c93..2dbf32b 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -256,7 +256,7 @@ static bool desc_has_ext(struct ioat_ring_ent *desc) * The difference from the dma_v2.c __cleanup() is that this routine * handles extended descriptors and dma-unmapping raid operations. */ -static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete) +static void __cleanup(struct ioat2_dma_chan *ioat, dma_addr_t phys_complete) { struct ioat_chan_common *chan = &ioat->base; struct ioat_ring_ent *desc; @@ -314,7 +314,7 @@ static void __cleanup(struct ioat2_dma_chan *ioat, unsigned long phys_complete) static void ioat3_cleanup(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - unsigned long phys_complete; + dma_addr_t phys_complete; spin_lock_bh(&chan->cleanup_lock); if (ioat_cleanup_preamble(chan, &phys_complete)) @@ -333,7 +333,7 @@ static void ioat3_cleanup_event(unsigned long data) static void ioat3_restart_channel(struct ioat2_dma_chan *ioat) { struct ioat_chan_common *chan = &ioat->base; - unsigned long phys_complete; + dma_addr_t phys_complete; ioat2_quiesce(chan, 0); if (ioat_cleanup_preamble(chan, &phys_complete)) @@ -348,7 +348,7 @@ static void ioat3_timer_event(unsigned long data) struct ioat_chan_common *chan = &ioat->base; if (test_bit(IOAT_COMPLETION_PENDING, &chan->state)) { - unsigned long phys_complete; + dma_addr_t phys_complete; u64 status; status = ioat_chansts(chan); -- cgit v0.10.2 From 4dae76705fc8f9854bb732f9944e7ff9ba7a8e9f Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 13 Mar 2012 18:43:23 -0400 Subject: xen/blkback: Squash the discard support for 'file' and 'phy' type. The only reason for the distinction was for the special case of 'file' (which is assumed to be loopback device), was to reach inside the loopback device, find the underlaying file, and call fallocate on it. Fortunately "xen-blkback: convert hole punching to discard request on loop devices" removes that use-case and we now based the discard support based on blk_queue_discard(q) and extract all appropriate parameters from the 'struct request_queue'. CC: Li Dongyang Acked-by: Jan Beulich [v1: Dropping pointless initializer and keeping blank line] [v2: Remove the kfree as it is not used anymore] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 70caa89..73f196c 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -398,21 +398,18 @@ static int dispatch_discard_io(struct xen_blkif *blkif, int err = 0; int status = BLKIF_RSP_OKAY; struct block_device *bdev = blkif->vbd.bdev; + unsigned long secure; blkif->st_ds_req++; xen_blkif_get(blkif); - if (blkif->blk_backend_type == BLKIF_BACKEND_PHY || - blkif->blk_backend_type == BLKIF_BACKEND_FILE) { - unsigned long secure = (blkif->vbd.discard_secure && - (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? - BLKDEV_DISCARD_SECURE : 0; - err = blkdev_issue_discard(bdev, - req->u.discard.sector_number, - req->u.discard.nr_sectors, - GFP_KERNEL, secure); - } else - err = -EOPNOTSUPP; + secure = (blkif->vbd.discard_secure && + (req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? + BLKDEV_DISCARD_SECURE : 0; + + err = blkdev_issue_discard(bdev, req->u.discard.sector_number, + req->u.discard.nr_sectors, + GFP_KERNEL, secure); if (err == -EOPNOTSUPP) { pr_debug(DRV_PFX "discard op failed, not supported\n"); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index d0ee7ed..773cf27 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -146,11 +146,6 @@ enum blkif_protocol { BLKIF_PROTOCOL_X86_64 = 3, }; -enum blkif_backend_type { - BLKIF_BACKEND_PHY = 1, - BLKIF_BACKEND_FILE = 2, -}; - struct xen_vbd { /* What the domain refers to this vbd as. */ blkif_vdev_t handle; @@ -177,7 +172,6 @@ struct xen_blkif { unsigned int irq; /* Comms information. */ enum blkif_protocol blk_protocol; - enum blkif_backend_type blk_backend_type; union blkif_back_rings blk_rings; void *blk_ring; /* The VBD attached to this interface. */ diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 24a2fb5..d417c13 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -390,61 +390,43 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) { struct xenbus_device *dev = be->dev; struct xen_blkif *blkif = be->blkif; - char *type; int err; int state = 0; + struct block_device *bdev = be->blkif->vbd.bdev; + struct request_queue *q = bdev_get_queue(bdev); - type = xenbus_read(XBT_NIL, dev->nodename, "type", NULL); - if (!IS_ERR(type)) { - if (strncmp(type, "file", 4) == 0) { - state = 1; - blkif->blk_backend_type = BLKIF_BACKEND_FILE; + if (blk_queue_discard(q)) { + err = xenbus_printf(xbt, dev->nodename, + "discard-granularity", "%u", + q->limits.discard_granularity); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-granularity"); + goto out; + } + err = xenbus_printf(xbt, dev->nodename, + "discard-alignment", "%u", + q->limits.discard_alignment); + if (err) { + xenbus_dev_fatal(dev, err, + "writing discard-alignment"); + goto out; } - if (strncmp(type, "phy", 3) == 0) { - struct block_device *bdev = be->blkif->vbd.bdev; - struct request_queue *q = bdev_get_queue(bdev); - if (blk_queue_discard(q)) { - err = xenbus_printf(xbt, dev->nodename, - "discard-granularity", "%u", - q->limits.discard_granularity); - if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-granularity"); - goto kfree; - } - err = xenbus_printf(xbt, dev->nodename, - "discard-alignment", "%u", - q->limits.discard_alignment); - if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-alignment"); - goto kfree; - } - state = 1; - blkif->blk_backend_type = BLKIF_BACKEND_PHY; - } - /* Optional. */ - err = xenbus_printf(xbt, dev->nodename, - "discard-secure", "%d", - blkif->vbd.discard_secure); - if (err) { - xenbus_dev_fatal(dev, err, + state = 1; + /* Optional. */ + err = xenbus_printf(xbt, dev->nodename, + "discard-secure", "%d", + blkif->vbd.discard_secure); + if (err) { + xenbus_dev_fatal(dev, err, "writting discard-secure"); - goto kfree; - } + goto out; } - } else { - err = PTR_ERR(type); - xenbus_dev_fatal(dev, err, "reading type"); - goto out; } - err = xenbus_printf(xbt, dev->nodename, "feature-discard", "%d", state); if (err) xenbus_dev_fatal(dev, err, "writing feature-discard"); -kfree: - kfree(type); out: return err; } -- cgit v0.10.2 From 3389bb8bf76180eecaffdfa7dd5b35fa4a2ce9b5 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Wed, 14 Mar 2012 13:04:00 -0400 Subject: xen/blkback: Make optional features be really optional. They were using the xenbus_dev_fatal() function which would change the state of the connection immediately. Which is not what we want when we advertise optional features. So make 'feature-discard','feature-barrier','feature-flush-cache' optional. Suggested-by: Jan Beulich [v1: Made the discard function void and static] Signed-off-by: Konrad Rzeszutek Wilk diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index d417c13..89860f3 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -381,12 +381,12 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, err = xenbus_printf(xbt, dev->nodename, "feature-flush-cache", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-flush-cache"); + dev_warn(&dev->dev, "writing feature-flush-cache (%d)", err); return err; } -int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) +static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) { struct xenbus_device *dev = be->dev; struct xen_blkif *blkif = be->blkif; @@ -400,17 +400,15 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) "discard-granularity", "%u", q->limits.discard_granularity); if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-granularity"); - goto out; + dev_warn(&dev->dev, "writing discard-granularity (%d)", err); + return; } err = xenbus_printf(xbt, dev->nodename, "discard-alignment", "%u", q->limits.discard_alignment); if (err) { - xenbus_dev_fatal(dev, err, - "writing discard-alignment"); - goto out; + dev_warn(&dev->dev, "writing discard-alignment (%d)", err); + return; } state = 1; /* Optional. */ @@ -418,17 +416,14 @@ int xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info *be) "discard-secure", "%d", blkif->vbd.discard_secure); if (err) { - xenbus_dev_fatal(dev, err, - "writting discard-secure"); - goto out; + dev_warn(dev-dev, "writing discard-secure (%d)", err); + return; } } err = xenbus_printf(xbt, dev->nodename, "feature-discard", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-discard"); -out: - return err; + dev_warn(&dev->dev, "writing feature-discard (%d)", err); } int xen_blkbk_barrier(struct xenbus_transaction xbt, struct backend_info *be, int state) @@ -439,7 +434,7 @@ int xen_blkbk_barrier(struct xenbus_transaction xbt, err = xenbus_printf(xbt, dev->nodename, "feature-barrier", "%d", state); if (err) - xenbus_dev_fatal(dev, err, "writing feature-barrier"); + dev_warn(&dev->dev, "writing feature-barrier (%d)", err); return err; } @@ -671,14 +666,12 @@ again: return; } - err = xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support); - if (err) - goto abort; + /* If we can't advertise it is OK. */ + xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support); - err = xen_blkbk_discard(xbt, be); + xen_blkbk_discard(xbt, be); - /* If we can't advertise it is OK. */ - err = xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); + xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", (unsigned long long)vbd_sz(&be->blkif->vbd)); -- cgit v0.10.2 From c1ac539ed43f273cd4d92bf7350ffd783b920184 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 22 Mar 2012 08:58:30 -0400 Subject: GFS2: put glock reference in error patch of read_rindex_entry This patch fixes the error path of function read_rindex_entry so that it correctly gives up its glock reference in cases where there is a race to re-read the rindex after gfs2_grow. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 19bde40..19354a2 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -640,6 +640,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, return 0; error = 0; /* someone else read in the rgrp; free it and ignore it */ + gfs2_glock_put(rgd->rd_gl); fail: kfree(rgd->rd_bits); -- cgit v0.10.2 From 97cc008aaa8c1f02699b478ca890e81810244131 Mon Sep 17 00:00:00 2001 From: Benjamin Poirier Date: Fri, 23 Mar 2012 18:06:18 -0400 Subject: GFS2: use depends instead of select in kconfig Avoids having to duplicate the dependencies of what is 'select'ed (and on down...) Those dependencies are currently incomplete, leading to broken builds with GFS2_FS_LOCKING_DLM=y and IP_SCTP=n. Signed-off-by: Benjamin Poirier Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index c465ae0..eb08c9e 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig @@ -1,10 +1,6 @@ config GFS2_FS tristate "GFS2 file system support" depends on (64BIT || LBDAF) - select DLM if GFS2_FS_LOCKING_DLM - select CONFIGFS_FS if GFS2_FS_LOCKING_DLM - select SYSFS if GFS2_FS_LOCKING_DLM - select IP_SCTP if DLM_SCTP select FS_POSIX_ACL select CRC32 select QUOTACTL @@ -29,7 +25,8 @@ config GFS2_FS config GFS2_FS_LOCKING_DLM bool "GFS2 DLM locking" - depends on (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && HOTPLUG + depends on (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && \ + HOTPLUG && DLM && CONFIGFS_FS && SYSFS help Multiple node locking module for GFS2 -- cgit v0.10.2 From 22e7a424854b80f00bd5686b6539726b8ca95420 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Tue, 27 Mar 2012 18:21:00 +0200 Subject: MAINTAINERS: update Bluetooth tree locations Make use of a shared tree setup to limit the confusions on which tree is current. Signed-off-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/MAINTAINERS b/MAINTAINERS index 0ddc77fe..6555183 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1517,8 +1517,8 @@ M: Gustavo Padovan M: Johan Hedberg L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git S: Maintained F: drivers/bluetooth/ @@ -1528,8 +1528,8 @@ M: Gustavo Padovan M: Johan Hedberg L: linux-bluetooth@vger.kernel.org W: http://www.bluez.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jh/bluetooth.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git S: Maintained F: net/bluetooth/ F: include/net/bluetooth/ -- cgit v0.10.2 From 3d9ea9e3af048ab6b8dced15248384e548ba05ea Mon Sep 17 00:00:00 2001 From: Don Morris Date: Thu, 15 Mar 2012 11:07:30 -0700 Subject: iop-adma: Corrected array overflow in RAID6 Xscale(R) test. Bug: cppcheck reported overflow in array assignment (for loop walks 0 to IOP_ADMA_NUM_SRC_TEST+2, array size is IOP_ADMA_NUM_SRC_TEST). Reported as: https://bugzilla.kernel.org/show_bug.cgi?id=42677 Test code pq_src array was grown by two elements to correspond with actual usage (IOP_ADMA_NUM_SRC_TEST+2), stack consumption was kept constant by modifying the pq_dest two element array which is only used when pq_src is referenced up to IOP_ADMA_NUM_SRC_TEST elements into the address of the new last two elements of the pq_src array. This is presumed to be the original intent but would be reliant on compilers always having pq_dest contiguous with the final element of pq_src. Note: This is a re-send of a request for review from two weeks ago. Looking for review (or shootdown), adding LKML to list for a wider audience. Thanks. Updated per review comments of Sergei Shtylyov Signed-off-by: Don Morris Signed-off-by: Dan Williams diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 04be90b..9b1951d 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -1271,8 +1271,8 @@ iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device) struct page **pq_hw = &pq[IOP_ADMA_NUM_SRC_TEST+2]; /* address conversion buffers (dma_map / page_address) */ void *pq_sw[IOP_ADMA_NUM_SRC_TEST+2]; - dma_addr_t pq_src[IOP_ADMA_NUM_SRC_TEST]; - dma_addr_t pq_dest[2]; + dma_addr_t pq_src[IOP_ADMA_NUM_SRC_TEST+2]; + dma_addr_t *pq_dest = &pq_src[IOP_ADMA_NUM_SRC_TEST]; int i; struct dma_async_tx_descriptor *tx; -- cgit v0.10.2 From 3f17790c2d8524c3ddc4946bd716714becf079e1 Mon Sep 17 00:00:00 2001 From: Hemant Gupta Date: Wed, 28 Mar 2012 17:09:09 +0530 Subject: Bluetooth: Use correct flags for checking HCI_SSP_ENABLED bit This patch uses the correct flags for checking the HCI_SSP_ENABLED bit. Without this authentication request was not being initiated. Signed-off-by: Hemant Gupta Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index daefaac..8e10328 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -427,7 +427,7 @@ enum { static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - return (test_bit(HCI_SSP_ENABLED, &hdev->flags) && + return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)); } -- cgit v0.10.2 From 6e4aff103774d6ee937a1dba9b1b4bf89100e7f6 Mon Sep 17 00:00:00 2001 From: Santosh Nayak Date: Thu, 1 Mar 2012 22:46:36 +0530 Subject: Bluetooth: Fix Endian Bug. Fix network to host endian conversion for L2CAP chan id. Signed-off-by: Santosh Nayak Acked-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index c4fe583..29122ed 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -82,7 +82,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (la.l2_cid) - err = l2cap_add_scid(chan, la.l2_cid); + err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid)); else err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); @@ -123,7 +123,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al if (la.l2_cid && la.l2_psm) return -EINVAL; - err = l2cap_chan_connect(chan, la.l2_psm, la.l2_cid, &la.l2_bdaddr); + err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), + &la.l2_bdaddr); if (err) return err; -- cgit v0.10.2 From 6dfc326f0605fd87e4c10ccde10de0ce4280d72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= Date: Wed, 14 Mar 2012 21:45:16 +0200 Subject: Bluetooth: btusb: Add USB device ID "0a5c 21e8" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One more vendor-specific ID for BCM20702A0. T: Bus=01 Lev=03 Prnt=05 Port=02 Cnt=01 Dev#= 9 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0a5c ProdID=21e8 Rev=01.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=00027221F4E2 C: #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=(none) I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none) I: If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: João Paulo Rechi Vita Acked-by: Gustavo F. Padovan Signed-off-by: Johan Hedberg diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 480cad9..b633854 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -103,6 +103,7 @@ static struct usb_device_id btusb_table[] = { /* Broadcom BCM20702A0 */ { USB_DEVICE(0x0a5c, 0x21e3) }, { USB_DEVICE(0x0a5c, 0x21e6) }, + { USB_DEVICE(0x0a5c, 0x21e8) }, { USB_DEVICE(0x0a5c, 0x21f3) }, { USB_DEVICE(0x413c, 0x8197) }, -- cgit v0.10.2 From 07c0ea874d43c299d185948452945a361052b6e3 Mon Sep 17 00:00:00 2001 From: "Cho, Yu-Chen" Date: Wed, 14 Mar 2012 22:01:21 +0200 Subject: Bluetooth: Add Atheros maryann PIDVID support Add Atheros maryann 0cf3:311d PIDVID support This module is AR3012 Series. Include /sys/kernel/debug/usb/devices output here for reference before: T: Bus=04 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311d Rev= 0.01 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms after: T: Bus=04 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=311d Rev= 0.02 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Signed-off-by: Cho, Yu-Chen cked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 48442476..fa65913 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -72,6 +72,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3012 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3004) }, + { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x13d3, 0x3375) }, /* Atheros AR5BBU12 with sflash firmware */ @@ -89,6 +90,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { /* Atheros AR3012 with sflash firmware*/ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { } /* Terminating entry */ diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b633854..9a5d811 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -130,6 +130,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3012 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ -- cgit v0.10.2 From 33b69bf80a3704d45341928e4ff68b6ebd470686 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 15 Mar 2012 14:48:40 +0100 Subject: Bluetooth: hci_ldisc: fix NULL-pointer dereference on tty_close Do not close protocol driver until device has been unregistered. This fixes a race between tty_close and hci_dev_open which can result in a NULL-pointer dereference. The line discipline closes the protocol driver while we may still have hci_dev_open sleeping on the req_lock mutex resulting in a NULL-pointer dereference when lock is acquired and hci_init_req called. Bug is 100% reproducible using hciattach and a disconnected serial port: 0. # hciattach -n ttyO1 any noflow 1. hci_dev_open called from hci_power_on grabs req lock 2. hci_init_req executes but device fails to initialise (times out eventually) 3. hci_dev_open is called from hci_sock_ioctl and sleeps on req lock 4. hci_uart_tty_close detaches protocol driver and cancels init req 5. hci_dev_open (1) releases req lock 6. hci_dev_open (3) grabs req lock, calls hci_init_req, which triggers oops when request is prepared in hci_uart_send_frame [ 137.201263] Unable to handle kernel NULL pointer dereference at virtual address 00000028 [ 137.209838] pgd = c0004000 [ 137.212677] [00000028] *pgd=00000000 [ 137.216430] Internal error: Oops: 17 [#1] [ 137.220642] Modules linked in: [ 137.223846] CPU: 0 Tainted: G W (3.3.0-rc6-dirty #406) [ 137.230529] PC is at __lock_acquire+0x5c/0x1ab0 [ 137.235290] LR is at lock_acquire+0x9c/0x128 [ 137.239776] pc : [] lr : [] psr: 20000093 [ 137.239776] sp : cf869dd8 ip : c0529554 fp : c051c730 [ 137.251800] r10: 00000000 r9 : cf8673c0 r8 : 00000080 [ 137.257293] r7 : 00000028 r6 : 00000002 r5 : 00000000 r4 : c053fd70 [ 137.264129] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : 00000001 [ 137.270965] Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel [ 137.278717] Control: 10c5387d Table: 8f0f4019 DAC: 00000015 [ 137.284729] Process kworker/u:1 (pid: 7, stack limit = 0xcf8682e8) [ 137.291229] Stack: (0xcf869dd8 to 0xcf86a000) [ 137.295776] 9dc0: c0529554 00000000 [ 137.304351] 9de0: cf8673c0 cf868000 d03ea1ef cf868000 000001ef 00000470 00000000 00000002 [ 137.312927] 9e00: cf8673c0 00000001 c051c730 c00716ec 0000000c 00000440 c0529554 00000001 [ 137.321533] 9e20: c051c730 cf868000 d03ea1f3 00000000 c053b978 00000000 00000028 cf868000 [ 137.330078] 9e40: 00000000 00000000 00000002 00000000 00000000 c00733f8 00000002 00000080 [ 137.338684] 9e60: 00000000 c02a1d50 00000000 00000001 60000013 c0969a1c 60000093 c053b96c [ 137.347259] 9e80: 00000002 00000018 20000013 c02a1d50 cf0ac000 00000000 00000002 cf868000 [ 137.355834] 9ea0: 00000089 c0374130 00000002 00000000 c02a1d50 cf0ac000 0000000c cf0fc540 [ 137.364410] 9ec0: 00000018 c02a1d50 cf0fc540 00000000 cf0fc540 c0282238 c028220c cf178d80 [ 137.372985] 9ee0: 127525d8 c02821cc 9a1fa451 c032727c 9a1fa451 127525d8 cf0fc540 cf0ac4ec [ 137.381561] 9f00: cf0ac000 cf0fc540 cf0ac584 c03285f4 c0328580 cf0ac4ec cf85c740 c05510cc [ 137.390136] 9f20: ce825400 c004c914 00000002 00000000 c004c884 ce8254f5 cf869f48 00000000 [ 137.398712] 9f40: c0328580 ce825415 c0a7f914 c061af64 00000000 c048cf3c cf8673c0 cf85c740 [ 137.407287] 9f60: c05510cc c051a66c c05510ec c05510c4 cf85c750 cf868000 00000089 c004d6ac [ 137.415863] 9f80: 00000000 c0073d14 00000001 cf853ed8 cf85c740 c004d558 00000013 00000000 [ 137.424438] 9fa0: 00000000 00000000 00000000 c00516b0 00000000 00000000 cf85c740 00000000 [ 137.433013] 9fc0: 00000001 dead4ead ffffffff ffffffff c0551674 00000000 00000000 c0450aa4 [ 137.441589] 9fe0: cf869fe0 cf869fe0 cf853ed8 c005162c c0013b30 c0013b30 00ffff00 00ffff00 [ 137.450164] [] (__lock_acquire+0x5c/0x1ab0) from [] (lock_acquire+0x9c/0x128) [ 137.459503] [] (lock_acquire+0x9c/0x128) from [] (_raw_spin_lock_irqsave+0x44/0x58) [ 137.469360] [] (_raw_spin_lock_irqsave+0x44/0x58) from [] (skb_queue_tail+0x18/0x48) [ 137.479339] [] (skb_queue_tail+0x18/0x48) from [] (h4_enqueue+0x2c/0x34) [ 137.488189] [] (h4_enqueue+0x2c/0x34) from [] (hci_uart_send_frame+0x34/0x68) [ 137.497497] [] (hci_uart_send_frame+0x34/0x68) from [] (hci_send_frame+0x50/0x88) [ 137.507171] [] (hci_send_frame+0x50/0x88) from [] (hci_cmd_work+0x74/0xd4) [ 137.516204] [] (hci_cmd_work+0x74/0xd4) from [] (process_one_work+0x1a0/0x4ec) [ 137.525604] [] (process_one_work+0x1a0/0x4ec) from [] (worker_thread+0x154/0x344) [ 137.535278] [] (worker_thread+0x154/0x344) from [] (kthread+0x84/0x90) [ 137.543975] [] (kthread+0x84/0x90) from [] (kernel_thread_exit+0x0/0x8) [ 137.552734] Code: e59f4e5c e5941000 e3510000 0a000031 (e5971000) [ 137.559234] ---[ end trace 1b75b31a2719ed1e ]--- Cc: stable Signed-off-by: Johan Hovold Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index fd5adb4..98a8c05 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -299,11 +299,11 @@ static void hci_uart_tty_close(struct tty_struct *tty) hci_uart_close(hdev); if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { - hu->proto->close(hu); if (hdev) { hci_unregister_dev(hdev); hci_free_dev(hdev); } + hu->proto->close(hu); } kfree(hu); -- cgit v0.10.2 From 94324962066231a938564bebad0f941cd2d06bb2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 15 Mar 2012 14:48:41 +0100 Subject: Bluetooth: hci_core: fix NULL-pointer dereference at unregister Make sure hci_dev_open returns immediately if hci_dev_unregister has been called. This fixes a race between hci_dev_open and hci_dev_unregister which can lead to a NULL-pointer dereference. Bug is 100% reproducible using hciattach and a disconnected serial port: 0. # hciattach -n /dev/ttyO1 any noflow 1. hci_dev_open called from hci_power_on grabs req lock 2. hci_init_req executes but device fails to initialise (times out eventually) 3. hci_dev_open is called from hci_sock_ioctl and sleeps on req lock 4. hci_uart_tty_close calls hci_dev_unregister and sleeps on req lock in hci_dev_do_close 5. hci_dev_open (1) releases req lock 6. hci_dev_do_close grabs req lock and returns as device is not up 7. hci_dev_unregister sleeps in destroy_workqueue 8. hci_dev_open (3) grabs req lock, calls hci_init_req and eventually sleeps 9. hci_dev_unregister finishes, while hci_dev_open is still running... [ 79.627136] INFO: trying to register non-static key. [ 79.632354] the code is fine but needs lockdep annotation. [ 79.638122] turning off the locking correctness validator. [ 79.643920] [] (unwind_backtrace+0x0/0xf8) from [] (__lock_acquire+0x1590/0x1ab0) [ 79.653594] [] (__lock_acquire+0x1590/0x1ab0) from [] (lock_acquire+0x9c/0x128) [ 79.663085] [] (lock_acquire+0x9c/0x128) from [] (run_timer_softirq+0x150/0x3ac) [ 79.672668] [] (run_timer_softirq+0x150/0x3ac) from [] (__do_softirq+0xd4/0x22c) [ 79.682281] [] (__do_softirq+0xd4/0x22c) from [] (irq_exit+0x8c/0x94) [ 79.690856] [] (irq_exit+0x8c/0x94) from [] (handle_IRQ+0x34/0x84) [ 79.699157] [] (handle_IRQ+0x34/0x84) from [] (omap3_intc_handle_irq+0x48/0x4c) [ 79.708648] [] (omap3_intc_handle_irq+0x48/0x4c) from [] (__irq_usr+0x3c/0x60) [ 79.718048] Exception stack(0xcf281fb0 to 0xcf281ff8) [ 79.723358] 1fa0: 0001e6a0 be8dab00 0001e698 00036698 [ 79.731933] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.740509] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff [ 79.747497] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 79.756011] pgd = cf3b4000 [ 79.758850] [00000000] *pgd=8f0c7831, *pte=00000000, *ppte=00000000 [ 79.765502] Internal error: Oops: 80000007 [#1] [ 79.770294] Modules linked in: [ 79.773529] CPU: 0 Tainted: G W (3.3.0-rc6-00002-gb5d5c87 #421) [ 79.781066] PC is at 0x0 [ 79.783721] LR is at run_timer_softirq+0x16c/0x3ac [ 79.788787] pc : [<00000000>] lr : [] psr: 60000113 [ 79.788787] sp : cf281ee0 ip : 00000000 fp : cf280000 [ 79.800903] r10: 00000004 r9 : 00000100 r8 : b6f234d0 [ 79.806427] r7 : c0519c28 r6 : cf093488 r5 : c0561a00 r4 : 00000000 [ 79.813323] r3 : 00000000 r2 : c054eee0 r1 : 00000001 r0 : 00000000 [ 79.820190] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 79.827728] Control: 10c5387d Table: 8f3b4019 DAC: 00000015 [ 79.833801] Process gpsd (pid: 1265, stack limit = 0xcf2802e8) [ 79.839965] Stack: (0xcf281ee0 to 0xcf282000) [ 79.844573] 1ee0: 00000002 00000000 c0040a24 00000000 00000002 cf281f08 00200200 00000000 [ 79.853210] 1f00: 00000000 cf281f18 cf281f08 00000000 00000000 00000000 cf281f18 cf281f18 [ 79.861816] 1f20: 00000000 00000001 c056184c 00000000 00000001 b6f234d0 c0561848 00000004 [ 79.870452] 1f40: cf280000 c003a3b8 c051e79c 00000001 00000000 00000100 3fa9e7b8 0000000a [ 79.879089] 1f60: 00000025 cf280000 00000025 00000000 00000000 b6f234d0 00000000 00000004 [ 79.887756] 1f80: 00000000 c003a924 c053ad38 c0013a50 fa200000 cf281fb0 ffffffff c0008530 [ 79.896362] 1fa0: 0001e6a0 0000aab8 80000010 c037499c 0001e6a0 be8dab00 0001e698 00036698 [ 79.904998] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.913665] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff 00fbf700 04ffff00 [ 79.922302] [] (run_timer_softirq+0x16c/0x3ac) from [] (__do_softirq+0xd4/0x22c) [ 79.931945] [] (__do_softirq+0xd4/0x22c) from [] (irq_exit+0x8c/0x94) [ 79.940582] [] (irq_exit+0x8c/0x94) from [] (handle_IRQ+0x34/0x84) [ 79.948913] [] (handle_IRQ+0x34/0x84) from [] (omap3_intc_handle_irq+0x48/0x4c) [ 79.958404] [] (omap3_intc_handle_irq+0x48/0x4c) from [] (__irq_usr+0x3c/0x60) [ 79.967773] Exception stack(0xcf281fb0 to 0xcf281ff8) [ 79.973083] 1fa0: 0001e6a0 be8dab00 0001e698 00036698 [ 79.981658] 1fc0: 0002df98 0002df38 0000001f 00000000 b6f234d0 00000000 00000004 00000000 [ 79.990234] 1fe0: 0001e6f8 be8d6aa0 be8dac50 0000aab8 80000010 ffffffff [ 79.997161] Code: bad PC value [ 80.000396] ---[ end trace 6f6739840475f9ee ]--- [ 80.005279] Kernel panic - not syncing: Fatal exception in interrupt Cc: stable Signed-off-by: Johan Hovold Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 344b0f9..8f928f7 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -92,6 +92,7 @@ enum { HCI_SERVICE_CACHE, HCI_LINK_KEYS, HCI_DEBUG_KEYS, + HCI_UNREGISTER, HCI_LE_SCAN, HCI_SSP_ENABLED, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59ec99e..2054c13 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -666,6 +666,11 @@ int hci_dev_open(__u16 dev) hci_req_lock(hdev); + if (test_bit(HCI_UNREGISTER, &hdev->dev_flags)) { + ret = -ENODEV; + goto done; + } + if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { ret = -ERFKILL; goto done; @@ -1850,6 +1855,8 @@ void hci_unregister_dev(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); + set_bit(HCI_UNREGISTER, &hdev->dev_flags); + write_lock(&hci_dev_list_lock); list_del(&hdev->list); write_unlock(&hci_dev_list_lock); -- cgit v0.10.2 From 8d7e1c7f7e5f9fe8f6279752fc33fcb77afd5001 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 23 Mar 2012 09:42:15 +0200 Subject: Bluetooth: Fix memory leaks due to chan refcnt When we queue delayed work we hold(chan) and delayed work shall put(chan) after execution. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo Padovan diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3e450f4..38d934a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1309,6 +1309,7 @@ static void l2cap_monitor_timeout(struct work_struct *work) if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); return; } @@ -1317,6 +1318,7 @@ static void l2cap_monitor_timeout(struct work_struct *work) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_retrans_timeout(struct work_struct *work) @@ -1336,6 +1338,7 @@ static void l2cap_retrans_timeout(struct work_struct *work) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_chan_unlock(chan); + l2cap_chan_put(chan); } static void l2cap_drop_acked_frames(struct l2cap_chan *chan) -- cgit v0.10.2 From 84d9d0716b2d5f4a27de4801bd2dbf7aff5e1c38 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 Mar 2012 14:21:41 +0300 Subject: Bluetooth: Don't increment twice in eir_has_data_type() The parsed variable is already incremented inside the for-loop so there no need to increment it again (not to mention that the code was incrementing it the wrong amount). Reported-by: Dan Carpenter Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 8e10328..220d8e0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -907,11 +907,10 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status, static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) { - u8 field_len; - size_t parsed; + size_t parsed = 0; - for (parsed = 0; parsed < data_len - 1; parsed += field_len) { - field_len = data[0]; + while (parsed < data_len - 1) { + u8 field_len = data[0]; if (field_len == 0) break; -- cgit v0.10.2 From 6c0c331e4c8ff6c0f7fa6cc5fd08d853d6c579c4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 26 Mar 2012 14:21:42 +0300 Subject: Bluetooth: Check for minimum data length in eir_has_data_type() If passed 0 as data_length the (parsed < data_length - 1) test will be true and cause a buffer overflow. In practice we need at least two bytes for the element length and type so add a test for it to the very beginning of the function. Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 220d8e0..6822d25 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -909,6 +909,9 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) { size_t parsed = 0; + if (data_len < 2) + return false; + while (parsed < data_len - 1) { u8 field_len = data[0]; -- cgit v0.10.2 From 55ed7d4d1469eafbe3ad7e8fcd44f5af27845a81 Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Wed, 28 Mar 2012 10:25:36 +0800 Subject: Bluetooth: Add support for Atheros [04ca:3005] Add another vendor specific ID for Atheros AR3012 device. This chip is wrapped by Lite-On Technology Corp. output of usb-devices: T: Bus=04 Lev=01 Prnt=01 Port=03 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=04ca ProdID=3005 Rev=00.02 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb Signed-off-by: AceLan Kao Signed-off-by: Gustavo Padovan diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index fa65913..ae9edca 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -74,6 +74,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x0CF3, 0x3004) }, { USB_DEVICE(0x0CF3, 0x311D) }, { USB_DEVICE(0x13d3, 0x3375) }, + { USB_DEVICE(0x04CA, 0x3005) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -92,6 +93,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9a5d811..ba89cd0 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -132,6 +132,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, -- cgit v0.10.2 From 531563850b29726bf37a81e877277902881ab77e Mon Sep 17 00:00:00 2001 From: Brian Gix Date: Fri, 9 Mar 2012 14:07:03 -0800 Subject: Bluetooth: mgmt: Fix corruption of device_connected pkt Incorrect pointer passed to eir_append_data made mgmt_device_connected event unparsable by mgmt user space entity. Signed-off-by: Brian Gix Signed-off-by: Johan Hedberg diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7fcff88..0e169da 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2936,7 +2936,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, name, name_len); if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0) - eir_len = eir_append_data(&ev->eir[eir_len], eir_len, + eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); put_unaligned_le16(eir_len, &ev->eir_len); -- cgit v0.10.2 From 76ec9de843c3cff41b3b15b752e1d08d91f0ad18 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 12 Mar 2012 12:13:11 +0200 Subject: Bluetooth: mgmt: Add missing endian conversion Add missing endian conversion for page scan interval and window. Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0e169da..4ef275c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2523,13 +2523,18 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, if (cp->val) { type = PAGE_SCAN_TYPE_INTERLACED; - acp.interval = 0x0024; /* 22.5 msec page scan interval */ + + /* 22.5 msec page scan interval */ + acp.interval = __constant_cpu_to_le16(0x0024); } else { type = PAGE_SCAN_TYPE_STANDARD; /* default */ - acp.interval = 0x0800; /* default 1.28 sec page scan */ + + /* default 1.28 sec page scan */ + acp.interval = __constant_cpu_to_le16(0x0800); } - acp.window = 0x0012; /* default 11.25 msec page scan window */ + /* default 11.25 msec page scan window */ + acp.window = __constant_cpu_to_le16(0x0012); err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), &acp); -- cgit v0.10.2 From c732a2af12e20f2784c8b0c9d2e289579313a413 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Mon, 19 Mar 2012 09:42:31 +0200 Subject: Bluetooth: mgmt: Fix timeout type Silence sparse warnings: net/bluetooth/mgmt.c:865:19: warning: cast to restricted __le16 Signed-off-by: Andrei Emeltchenko Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ffc1377..ebfd91f 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -117,7 +117,7 @@ struct mgmt_mode { #define MGMT_OP_SET_DISCOVERABLE 0x0006 struct mgmt_cp_set_discoverable { __u8 val; - __u16 timeout; + __le16 timeout; } __packed; #define MGMT_SET_DISCOVERABLE_SIZE 3 -- cgit v0.10.2 From e9986f303dc0f285401de28cf96f42f4dd23a4a1 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Thu, 29 Mar 2012 10:09:44 +0200 Subject: virtio-blk: Call revalidate_disk() upon online disk resize If a virtio disk is open in guest and a disk resize operation is done, (virsh blockresize), new size is not visible to tools like "fdisk -l". This seems to be happening as we update only part->nr_sects and not bdev->bd_inode size. Call revalidate_disk() which should take care of it. I tested growing disk size of already open disk and it works for me. Signed-off-by: Vivek Goyal Signed-off-by: Jens Axboe diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index c4a60ba..0e4ef3d 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -351,6 +351,7 @@ static void virtblk_config_changed_work(struct work_struct *work) cap_str_10, cap_str_2); set_capacity(vblk->disk, capacity); + revalidate_disk(vblk->disk); done: mutex_unlock(&vblk->config_lock); } -- cgit v0.10.2 From 2e8b506310f6433d5558387fd568d4bfb1d6a799 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Wed, 28 Mar 2012 16:41:11 -0400 Subject: Bluetooth: btusb: typo in Broadcom SoftSailing id I was trying to backport the following commit to RHEL-6 From 0cea73465cd22373c5cd43a3edd25fbd4bb532ef Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 21 Sep 2011 11:37:15 +0200 Subject: [PATCH] btusb: add device entry for Broadcom SoftSailing and noticed it wasn't working on an HP Elitebook. Looking into the patch I noticed a very subtle typo in the ids. The patch has '0x05ac' instead of '0x0a5c'. A snippet of the lsusb -v output also shows this: Bus 002 Device 003: ID 0a5c:21e1 Broadcom Corp. Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 1 bDeviceProtocol 1 bMaxPacketSize0 64 idVendor 0x0a5c Broadcom Corp. idProduct 0x21e1 bcdDevice 1.12 iManufacturer 1 Broadcom Corp iProduct 2 BCM20702A0 iSerial 3 60D819F0338C bNumConfigurations 1 Looking at other Broadcom ids, the fix matches them whereas the original patch matches Apple's ids. Tested on an HP Elitebook 8760w. The btusb binds and the userspace stuff loads correctly. Cc: Oliver Neukum Signed-off-by: Don Zickus Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ba89cd0..3311b81 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -61,7 +61,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, /* Broadcom SoftSailing reporting vendor specific */ - { USB_DEVICE(0x05ac, 0x21e1) }, + { USB_DEVICE(0x0a5c, 0x21e1) }, /* Apple MacBookPro 7,1 */ { USB_DEVICE(0x05ac, 0x8213) }, -- cgit v0.10.2 From 8bcb6c7d48eb341b1f49f814cdcbe05eb6f15680 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Fri, 30 Mar 2012 12:33:28 +0200 Subject: block: use lockdep_assert_held for queue locking Instead of an ugly open coded variant. Cc: axboe@kernel.dk Signed-off-by: Andi Kleen Signed-off-by: Jens Axboe diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 5eed6a7..f2ddb94 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -1218,7 +1218,7 @@ void blk_throtl_drain(struct request_queue *q) struct bio_list bl; struct bio *bio; - WARN_ON_ONCE(!queue_is_locked(q)); + queue_lockdep_assert_held(q); bio_list_init(&bl); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 606cf33..2aa2466 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -426,14 +426,10 @@ struct request_queue { (1 << QUEUE_FLAG_SAME_COMP) | \ (1 << QUEUE_FLAG_ADD_RANDOM)) -static inline int queue_is_locked(struct request_queue *q) +static inline void queue_lockdep_assert_held(struct request_queue *q) { -#ifdef CONFIG_SMP - spinlock_t *lock = q->queue_lock; - return lock && spin_is_locked(lock); -#else - return 1; -#endif + if (q->queue_lock) + lockdep_assert_held(q->queue_lock); } static inline void queue_flag_set_unlocked(unsigned int flag, @@ -445,7 +441,7 @@ static inline void queue_flag_set_unlocked(unsigned int flag, static inline int queue_flag_test_and_clear(unsigned int flag, struct request_queue *q) { - WARN_ON_ONCE(!queue_is_locked(q)); + queue_lockdep_assert_held(q); if (test_bit(flag, &q->queue_flags)) { __clear_bit(flag, &q->queue_flags); @@ -458,7 +454,7 @@ static inline int queue_flag_test_and_clear(unsigned int flag, static inline int queue_flag_test_and_set(unsigned int flag, struct request_queue *q) { - WARN_ON_ONCE(!queue_is_locked(q)); + queue_lockdep_assert_held(q); if (!test_bit(flag, &q->queue_flags)) { __set_bit(flag, &q->queue_flags); @@ -470,7 +466,7 @@ static inline int queue_flag_test_and_set(unsigned int flag, static inline void queue_flag_set(unsigned int flag, struct request_queue *q) { - WARN_ON_ONCE(!queue_is_locked(q)); + queue_lockdep_assert_held(q); __set_bit(flag, &q->queue_flags); } @@ -487,7 +483,7 @@ static inline int queue_in_flight(struct request_queue *q) static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) { - WARN_ON_ONCE(!queue_is_locked(q)); + queue_lockdep_assert_held(q); __clear_bit(flag, &q->queue_flags); } -- cgit v0.10.2 From aa2bf9bc6414b6972b9e51903c1ce7b1f057aee2 Mon Sep 17 00:00:00 2001 From: Sasikantha babu Date: Wed, 21 Mar 2012 20:10:54 +0530 Subject: itimer: Schedule silent NULL pointer fixup in setitimer() for removal setitimer() should return -EFAULT if called with an invalid pointer for value. The current code excludes a NULL pointer from this rule and silently uses it to stop the timer. This violates the spec. Warn about user space apps which rely on that feature and schedule it for removal. [ tglx: Massaged changelog, warn message and Doc entry ] Signed-off-by: Sasikantha babu Link: http://lkml.kernel.org/r/1332340854-26053-1-git-send-email-sasikanth.v19@gmail.com Signed-off-by: Thomas Gleixner diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 0cad480..32fae81 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -529,3 +529,11 @@ When: 3.5 Why: The old kmap_atomic() with two arguments is deprecated, we only keep it for backward compatibility for few cycles and then drop it. Who: Cong Wang + +---------------------------- + +What: setitimer accepts user NULL pointer (value) +When: 3.6 +Why: setitimer is not returning -EFAULT if user pointer is NULL. This + violates the spec. +Who: Sasikantha Babu diff --git a/kernel/itimer.c b/kernel/itimer.c index 22000c3..c70369a 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -284,8 +284,11 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, if (value) { if(copy_from_user(&set_buffer, value, sizeof(set_buffer))) return -EFAULT; - } else + } else { memset((char *) &set_buffer, 0, sizeof(set_buffer)); + WARN_ONCE(1, "setitimer: new_value pointer is NULL." + " Misfeature support will be removed\n"); + } error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL); if (error || !ovalue) -- cgit v0.10.2 From cb85a6ed67e979c59a29b7b4e8217e755b951cf4 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 30 Mar 2012 12:23:08 +0200 Subject: proc: stats: Use arch_idle_time for idle and iowait times if available Git commit a25cac5198d4ff28 "proc: Consider NO_HZ when printing idle and iowait times" changes the code for /proc/stat to use get_cpu_idle_time_us and get_cpu_iowait_time_us if the system is running with nohz enabled. For architectures which define arch_idle_time (currently s390 only) this is a change for the worse. The result of arch_idle_time is supposed to be the exact sleep time of the target cpu and should be used instead of the value kept by the scheduler. Signed-off-by: Martin Schwidefsky Reviewed-by: Michal Hocko Reviewed-by: Srivatsa S. Bhat Link: http://lkml.kernel.org/r/20120330122308.18720283@de.ibm.com Signed-off-by: Thomas Gleixner diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 6a0c62d..64c3b31 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c @@ -18,19 +18,39 @@ #ifndef arch_irq_stat #define arch_irq_stat() 0 #endif -#ifndef arch_idle_time -#define arch_idle_time(cpu) 0 -#endif + +#ifdef arch_idle_time + +static cputime64_t get_idle_time(int cpu) +{ + cputime64_t idle; + + idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; + if (cpu_online(cpu) && !nr_iowait_cpu(cpu)) + idle += arch_idle_time(cpu); + return idle; +} + +static cputime64_t get_iowait_time(int cpu) +{ + cputime64_t iowait; + + iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; + if (cpu_online(cpu) && nr_iowait_cpu(cpu)) + iowait += arch_idle_time(cpu); + return iowait; +} + +#else static u64 get_idle_time(int cpu) { u64 idle, idle_time = get_cpu_idle_time_us(cpu, NULL); - if (idle_time == -1ULL) { + if (idle_time == -1ULL) /* !NO_HZ so we can rely on cpustat.idle */ idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; - idle += arch_idle_time(cpu); - } else + else idle = usecs_to_cputime64(idle_time); return idle; @@ -49,6 +69,8 @@ static u64 get_iowait_time(int cpu) return iowait; } +#endif + static int show_stat(struct seq_file *p, void *v) { int i, j; -- cgit v0.10.2 From 92fd918c2416404c2ec09829b25243b9a785dc9b Mon Sep 17 00:00:00 2001 From: Eliot Blennerhassett Date: Fri, 30 Mar 2012 09:52:25 +1300 Subject: ALSA: asihpi - fix return value of hpios_locked_mem_alloc() Make this function consistent with others in this module by returning 1 for error, instead of -ENOMEM (reverts function signature change from a938fb1e) Signed-off-by: Eliot Blennerhassett Signed-off-by: Takashi Iwai diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h index 8c63200..bc86cb7 100644 --- a/sound/pci/asihpi/hpi_internal.h +++ b/sound/pci/asihpi/hpi_internal.h @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2012 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -42,7 +42,7 @@ On error *pLockedMemHandle marked invalid, non-zero returned. If this function succeeds, then HpiOs_LockedMem_GetVirtAddr() and HpiOs_LockedMem_GetPyhsAddr() will always succed on the returned handle. */ -int hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle, +u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_locked_mem_handle, /**< memory handle */ u32 size, /**< Size in bytes to allocate */ struct pci_dev *p_os_reference diff --git a/sound/pci/asihpi/hpios.c b/sound/pci/asihpi/hpios.c index 87f4385..5ef4fe9 100644 --- a/sound/pci/asihpi/hpios.c +++ b/sound/pci/asihpi/hpios.c @@ -1,7 +1,7 @@ /****************************************************************************** AudioScience HPI driver - Copyright (C) 1997-2011 AudioScience Inc. + Copyright (C) 1997-2012 AudioScience Inc. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -39,11 +39,11 @@ void hpios_delay_micro_seconds(u32 num_micro_sec) } -/** Allocated an area of locked memory for bus master DMA operations. +/** Allocate an area of locked memory for bus master DMA operations. -On error, return -ENOMEM, and *pMemArea.size = 0 +If allocation fails, return 1, and *pMemArea.size = 0 */ -int hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, +u16 hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, struct pci_dev *pdev) { /*?? any benefit in using managed dmam_alloc_coherent? */ @@ -62,7 +62,7 @@ int hpios_locked_mem_alloc(struct consistent_dma_area *p_mem_area, u32 size, HPI_DEBUG_LOG(WARNING, "failed to allocate %d bytes locked memory\n", size); p_mem_area->size = 0; - return -ENOMEM; + return 1; } } -- cgit v0.10.2 From 327ef2e9048a5e39bf84d7f17f78a87e7a068742 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 23 Mar 2012 13:05:48 +0530 Subject: spi/pL022: include types.h to remove compilation warnings linux/pl022.h uses definitions like, u8, u16, etc, which have dependency of types.h file, which isn't included in it. So, we get compilation warnings. This patch includes types.h there to fix these warnings. Signed-off-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Grant Likely diff --git a/include/linux/amba/pl022.h b/include/linux/amba/pl022.h index b8c5112..76dd1b1 100644 --- a/include/linux/amba/pl022.h +++ b/include/linux/amba/pl022.h @@ -25,6 +25,8 @@ #ifndef _SSP_PL022_H #define _SSP_PL022_H +#include + /** * whether SSP is in loopback mode or not */ -- cgit v0.10.2 From 9232b9b1b57dc5c01f435433e70e26c122bf4e44 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 20 Mar 2012 16:10:09 +0530 Subject: spi/davinci: Fix DMA API usage in davinci The driver uses NULL for dma_unmap_single instead of the struct device that the API expects. Signed-off-by: Shubhrajyoti D Tested-by: Akshay Shankarmurthy Signed-off-by: Grant Likely diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 31bfba8..9b2901f 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -653,7 +653,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", rx_buf_count); if (t->tx_buf) - dma_unmap_single(NULL, t->tx_dma, t->len, + dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE); return -ENOMEM; } @@ -692,10 +692,10 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) if (spicfg->io_type == SPI_IO_TYPE_DMA) { if (t->tx_buf) - dma_unmap_single(NULL, t->tx_dma, t->len, + dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE); - dma_unmap_single(NULL, t->rx_dma, rx_buf_count, + dma_unmap_single(&spi->dev, t->rx_dma, rx_buf_count, DMA_FROM_DEVICE); clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN); -- cgit v0.10.2 From 5039a86973cd35bdb2f64d28ee12f13fe2bb5a4c Mon Sep 17 00:00:00 2001 From: Kenth Eriksson Date: Fri, 30 Mar 2012 17:05:30 +0200 Subject: spi/mpc83xx: fix NULL pdata dereference bug Commit 178db7d3, "spi: Fix device unregistration when unregistering the bus master", changed device initialization to be children of the bus master, not children of the bus masters parent device. The pdata pointer used in fsl_spi_chipselect must updated to reflect the changed initialization. Signed-off-by: Kenth Eriksson Acked-by: Joakim Tjernlund Signed-off-by: Grant Likely diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 24cacff..5f748c0 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -139,10 +139,12 @@ static void fsl_spi_change_mode(struct spi_device *spi) static void fsl_spi_chipselect(struct spi_device *spi, int value) { struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); - struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; + struct fsl_spi_platform_data *pdata; bool pol = spi->mode & SPI_CS_HIGH; struct spi_mpc8xxx_cs *cs = spi->controller_state; + pdata = spi->dev.parent->parent->platform_data; + if (value == BITBANG_CS_INACTIVE) { if (pdata->cs_control) pdata->cs_control(spi, !pol); -- cgit v0.10.2 From cc4d22ae541ccd989ef163c46a38afde131e1644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 29 Mar 2012 21:54:18 +0200 Subject: spi/imx: mark base member in spi_imx_data as __iomem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes 36 sparse warnings like: drivers/spi/spi-imx.c:143:1: warning: incorrect type in argument 1 (different address spaces) drivers/spi/spi-imx.c:143:1: expected void const volatile [noderef] * drivers/spi/spi-imx.c:143:1: got void * Signed-off-by: Uwe Kleine-König Signed-off-by: Grant Likely diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 31054e3..373f4ff 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -83,7 +83,7 @@ struct spi_imx_data { struct spi_bitbang bitbang; struct completion xfer_done; - void *base; + void __iomem *base; int irq; struct clk *clk; unsigned long spi_clk; -- cgit v0.10.2 From 3872c48b14259d8c0a00c9fff06a4a4123f7f4eb Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 31 Mar 2012 12:45:43 +0200 Subject: tick: Document TICK_ONESHOT config option This option has been selected from arch code as it was assumed that it's necessary to support oneshot mode clockevent devices. But it's just a core internal helper to compile tick-oneshot.c if NOHZ or HIG_RES_TIMERS are selected. Reported-by: Russell King Signed-off-by: Thomas Gleixner diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index 2cf9cc7..a20dc8a 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -1,6 +1,10 @@ # # Timer subsystem related configuration options # + +# Core internal switch. Selected by NO_HZ / HIGH_RES_TIMERS. This is +# only related to the tick functionality. Oneshot clockevent devices +# are supported independ of this. config TICK_ONESHOT bool -- cgit v0.10.2 From 5bf14c0727a07ded1bd9fa6d77923d7e6dc32833 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Sun, 1 Apr 2012 14:33:39 -0700 Subject: block: Make cfq_target_latency tunable through sysfs. In cfq, when we calculate a time slice for a process(or a cfqq to be precise), we have to consider the cfq_target_latency so that all the sync request have an estimated latency(300ms) and it is controlled by cfq_target_latency. But in some hadoop test, we have found that if there are many processes doing sequential read(24 for example), the throughput is bad because every process can only work for about 25ms and the cfqq is switched. That leads to a higher disk seek. We can achive the good throughput by setting low_latency=0, but then some read's latency is too much for the application. So this patch makes cfq_target_latency tunable through sysfs so that we can tune it and find some magic number which is not bad for both the throughput and the read latency. Cc: Jens Axboe Signed-off-by: Tao Ma Signed-off-by: Jens Axboe diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 4572952..3c38536 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -295,6 +295,7 @@ struct cfq_data { unsigned int cfq_slice_idle; unsigned int cfq_group_idle; unsigned int cfq_latency; + unsigned int cfq_target_latency; /* * Fallback dummy cfqq for extreme OOM conditions @@ -604,7 +605,7 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg) { struct cfq_rb_root *st = &cfqd->grp_service_tree; - return cfq_target_latency * cfqg->weight / st->total_weight; + return cfqd->cfq_target_latency * cfqg->weight / st->total_weight; } static inline unsigned @@ -2271,7 +2272,8 @@ new_workload: * to have higher weight. A more accurate thing would be to * calculate system wide asnc/sync ratio. */ - tmp = cfq_target_latency * cfqg_busy_async_queues(cfqd, cfqg); + tmp = cfqd->cfq_target_latency * + cfqg_busy_async_queues(cfqd, cfqg); tmp = tmp/cfqd->busy_queues; slice = min_t(unsigned, slice, tmp); @@ -3737,6 +3739,7 @@ static void *cfq_init_queue(struct request_queue *q) cfqd->cfq_back_penalty = cfq_back_penalty; cfqd->cfq_slice[0] = cfq_slice_async; cfqd->cfq_slice[1] = cfq_slice_sync; + cfqd->cfq_target_latency = cfq_target_latency; cfqd->cfq_slice_async_rq = cfq_slice_async_rq; cfqd->cfq_slice_idle = cfq_slice_idle; cfqd->cfq_group_idle = cfq_group_idle; @@ -3788,6 +3791,7 @@ SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0); SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0); +SHOW_FUNCTION(cfq_target_latency_show, cfqd->cfq_target_latency, 1); #undef SHOW_FUNCTION #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ @@ -3821,6 +3825,7 @@ STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0); STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0); +STORE_FUNCTION(cfq_target_latency_store, &cfqd->cfq_target_latency, 1, UINT_MAX, 1); #undef STORE_FUNCTION #define CFQ_ATTR(name) \ @@ -3838,6 +3843,7 @@ static struct elv_fs_entry cfq_attrs[] = { CFQ_ATTR(slice_idle), CFQ_ATTR(group_idle), CFQ_ATTR(low_latency), + CFQ_ATTR(target_latency), __ATTR_NULL }; -- cgit v0.10.2 From 407ac95e2271a310016ced97f407676e79c53c06 Mon Sep 17 00:00:00 2001 From: Tao Ma Date: Sun, 1 Apr 2012 14:33:40 -0700 Subject: Documentation: Add sysfs ABI change for cfq's target latency. Cc: Jens Axboe Cc: Greg Kroah-Hartman Signed-off-by: Tao Ma Signed-off-by: Jens Axboe diff --git a/Documentation/ABI/testing/sysfs-cfq-target-latency b/Documentation/ABI/testing/sysfs-cfq-target-latency new file mode 100644 index 0000000..df0f782 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-cfq-target-latency @@ -0,0 +1,8 @@ +What: /sys/block//iosched/target_latency +Date: March 2012 +contact: Tao Ma +Description: + The /sys/block//iosched/target_latency only exists + when the user sets cfq to /sys/block//scheduler. + It contains an estimated latency time for the cfq. cfq will + use it to calculate the time slice used for every task. -- cgit v0.10.2 From d2ef406866620f0450ad0b4c7fb5c2796c7bf245 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Mon, 2 Apr 2012 17:45:20 +0300 Subject: IB/mlx4: Don't return an invalid speed when a port is down When the IB port is down, the active_speed value returned by the MAD_IFC command is seven (7) which isn't among the defined IB speeds in enum ib_port_speed, and this invalid speed value is passed up to higher layers or applications who do port query. Fix that by setting the speed to be SDR -- the lowest possible -- when the port is down. Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 75d3056..669673e 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -253,6 +253,11 @@ static int ib_link_query_port(struct ib_device *ibdev, u8 port, if (out_mad->data[15] & 0x1) props->active_speed = IB_SPEED_FDR10; } + + /* Avoid wrong speed value returned by FW if the IB link is down. */ + if (props->state == IB_PORT_DOWN) + props->active_speed = IB_SPEED_SDR; + out: kfree(in_mad); kfree(out_mad); -- cgit v0.10.2 From 0559d8dc13a1cd68b5e64c0b61659f36c7b5c89f Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 2 Apr 2012 10:57:31 -0700 Subject: IB/core: Don't return EINVAL from sysfs rate attribute for invalid speeds Commit e9319b0cb00d ("IB/core: Fix SDR rates in sysfs") changed our sysfs rate attribute to return EINVAL to userspace if the underlying device driver returns an invalid rate. Apparently some drivers do this when the link is down and some userspace pukes if it gets an error when reading this attribute, so avoid a regression by not return an error to match the old code. Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 83b720e..246fdc1 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -179,7 +179,7 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, { struct ib_port_attr attr; char *speed = ""; - int rate = -1; /* in deci-Gb/sec */ + int rate; /* in deci-Gb/sec */ ssize_t ret; ret = ib_query_port(p->ibdev, p->port_num, &attr); @@ -187,9 +187,6 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, return ret; switch (attr.active_speed) { - case IB_SPEED_SDR: - rate = 25; - break; case IB_SPEED_DDR: speed = " DDR"; rate = 50; @@ -210,6 +207,10 @@ static ssize_t rate_show(struct ib_port *p, struct port_attribute *unused, speed = " EDR"; rate = 250; break; + case IB_SPEED_SDR: + default: /* default to SDR for invalid rates */ + rate = 25; + break; } rate *= ib_width_enum_to_int(attr.active_width); -- cgit v0.10.2 From f0cdcf3ab6c62b3f774a2af15dfa01988e7a9b02 Mon Sep 17 00:00:00 2001 From: Zeng Zhaoming Date: Fri, 30 Mar 2012 00:13:02 +0800 Subject: ASoC: sgtl5000: Enable VAG when DAC/ADC up As manual described, VAG is an internal voltage reference of DAC/ADC, So enabled it before DAC/ADC up. One more thing should care about is VAG fully ramped down requires 400ms, wait it to avoid pop. Signed-off-by: Zeng Zhaoming Signed-off-by: Shawn Guo Signed-off-by: Mark Brown diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index d192626..8e92fb8 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -143,11 +143,11 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, } /* - * using codec assist to small pop, hp_powerup or lineout_powerup - * should stay setting until vag_powerup is fully ramped down, - * vag fully ramped down require 400ms. + * As manual described, ADC/DAC only works when VAG powerup, + * So enabled VAG before ADC/DAC up. + * In power down case, we need wait 400ms when vag fully ramped down. */ -static int small_pop_event(struct snd_soc_dapm_widget *w, +static int power_vag_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { switch (event) { @@ -156,7 +156,7 @@ static int small_pop_event(struct snd_soc_dapm_widget *w, SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); break; - case SND_SOC_DAPM_PRE_PMD: + case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_VAG_POWERUP, 0); msleep(400); @@ -201,12 +201,8 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, - small_pop_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), - SND_SOC_DAPM_PGA_E("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0, - small_pop_event, - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0), + SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0), SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux), @@ -221,8 +217,11 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { 0, SGTL5000_CHIP_DIG_POWER, 1, 0), - SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), + SND_SOC_DAPM_SUPPLY("VAG_POWER", SGTL5000_CHIP_ANA_POWER, 7, 0, + power_vag_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), }; @@ -231,9 +230,11 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = { {"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */ {"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */ + {"ADC", NULL, "VAG_POWER"}, {"ADC", NULL, "Capture Mux"}, /* adc_mux --> adc */ {"AIFOUT", NULL, "ADC"}, /* adc --> i2s_out */ + {"DAC", NULL, "VAG_POWER"}, {"DAC", NULL, "AIFIN"}, /* i2s-->dac,skip audio mux */ {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */ {"LO", NULL, "DAC"}, /* dac --> line_out */ -- cgit v0.10.2 From cd1506736f3a77429f619ede817a119a7ff5f7e5 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 30 Mar 2012 17:07:17 -0600 Subject: ASoC: tegra: ensure clocks are enabled when touching registers Debugfs files could be accessed any time, so explicitly enable clocks when reading registers to generate debugfs file content. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 33509de..2d98c92 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -79,11 +79,15 @@ static int tegra_i2s_show(struct seq_file *s, void *unused) struct tegra_i2s *i2s = s->private; int i; + clk_enable(i2s->clk_i2s); + for (i = 0; i < ARRAY_SIZE(regs); i++) { u32 val = tegra_i2s_read(i2s, regs[i].offset); seq_printf(s, "%s = %08x\n", regs[i].name, val); } + clk_disable(i2s->clk_i2s); + return 0; } diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c index 475428c..9ff2c60 100644 --- a/sound/soc/tegra/tegra_spdif.c +++ b/sound/soc/tegra/tegra_spdif.c @@ -79,11 +79,15 @@ static int tegra_spdif_show(struct seq_file *s, void *unused) struct tegra_spdif *spdif = s->private; int i; + clk_enable(spdif->clk_spdif_out); + for (i = 0; i < ARRAY_SIZE(regs); i++) { u32 val = tegra_spdif_read(spdif, regs[i].offset); seq_printf(s, "%s = %08x\n", regs[i].name, val); } + clk_disable(spdif->clk_spdif_out); + return 0; } -- cgit v0.10.2 From e95cee0e36c671db2804f2763b547a86930061ea Mon Sep 17 00:00:00 2001 From: Martin Jansa Date: Mon, 2 Apr 2012 10:24:08 +0200 Subject: ASoC: pxa: pxa2xx-i2s: add io.h for IOMEM macro * fixes sound/soc/pxa/pxa2xx-i2s.c:86:2: error: implicit declaration of function 'IOMEM' [-Werror=implicit-function-declaration] sound/soc/pxa/pxa2xx-i2s.c:86:2: error: initializer element is not constant after 23019a733bb83c8499f192fb428b7e6e81c95a34 removed IOMEM definition from arch/arm/mach-pxa/include/mach/hardware.h Signed-off-by: Martin Jansa Signed-off-by: Mark Brown diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 609abd5..d085837 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From c0d78c23423ee6ec774ac53f129e61839dde1908 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 2 Apr 2012 14:57:01 +0800 Subject: regulator: anatop: fix 'anatop_regulator' name collision There is a name collision between 'struct platform_driver anatop_regulator' and 'struct anatop_regulator', which causes some section mismatch warnings like below. WARNING: vmlinux.o(.data+0x154d4): Section mismatch in reference from the variable anatop_regulator to the function .devinit.text:anatop_regulator_probe() The variable anatop_regulator references the function __devinit anatop_regulator_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Rename 'struct platform_driver anatop_regulator' to 'struct platform_driver anatop_regulator_driver' to fix the warnings. Signed-off-by: Shawn Guo Cc: Ying-Chun Liu (PaulLiu) Signed-off-by: Mark Brown diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 17499a5..e365d11 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -213,7 +213,7 @@ static struct of_device_id __devinitdata of_anatop_regulator_match_tbl[] = { { /* end */ } }; -static struct platform_driver anatop_regulator = { +static struct platform_driver anatop_regulator_driver = { .driver = { .name = "anatop_regulator", .owner = THIS_MODULE, @@ -225,13 +225,13 @@ static struct platform_driver anatop_regulator = { static int __init anatop_regulator_init(void) { - return platform_driver_register(&anatop_regulator); + return platform_driver_register(&anatop_regulator_driver); } postcore_initcall(anatop_regulator_init); static void __exit anatop_regulator_exit(void) { - platform_driver_unregister(&anatop_regulator); + platform_driver_unregister(&anatop_regulator_driver); } module_exit(anatop_regulator_exit); -- cgit v0.10.2 From 6c284903731eae12ae62aa138f479d48ccbcf1d1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 3 Apr 2012 09:45:43 +0300 Subject: MAINTAINERS: Add missing ASoC OMAP co-maintainer Peter Ujfalusi has been co-maintaining sound/soc/omap/ for years but was missing from this MAINTAINERS entry. Signed-off-by: Jarkko Nikula Acked-by: Liam Girdwood Signed-off-by: Mark Brown diff --git a/MAINTAINERS b/MAINTAINERS index eecf344..85c599b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4807,6 +4807,7 @@ F: arch/arm/mach-omap2/clockdomain2xxx_3xxx.c F: arch/arm/mach-omap2/clockdomain44xx.c OMAP AUDIO SUPPORT +M: Peter Ujfalusi M: Jarkko Nikula L: alsa-devel@alsa-project.org (subscribers-only) L: linux-omap@vger.kernel.org -- cgit v0.10.2 From dcf9af822803bcc2cd9e8009648547e6060b59a0 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 3 Apr 2012 21:27:58 +0900 Subject: drm/exynos: fixed page align and code clean. 1M section, 64k page count also should be rounded up so this patch rounds up them and caculates page count of them properly and also checks memory flags from user. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 4a3a5f7..52d42cd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -41,7 +41,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, DRM_DEBUG_KMS("%s\n", __FILE__); - if (flags & EXYNOS_BO_NONCONTIG) { + if (IS_NONCONTIG_BUFFER(flags)) { DRM_DEBUG_KMS("not support allocation type.\n"); return -EINVAL; } @@ -52,13 +52,13 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, } if (buf->size >= SZ_1M) { - npages = (buf->size >> SECTION_SHIFT) + 1; + npages = buf->size >> SECTION_SHIFT; page_size = SECTION_SIZE; } else if (buf->size >= SZ_64K) { - npages = (buf->size >> 16) + 1; + npages = buf->size >> 16; page_size = SZ_64K; } else { - npages = (buf->size >> PAGE_SHIFT) + 1; + npages = buf->size >> PAGE_SHIFT; page_size = PAGE_SIZE; } @@ -119,9 +119,6 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, buf->pages[i] = phys_to_page(start_addr); - sgl = sg_next(sgl); - sg_set_page(sgl, buf->pages[i+1], end_addr - start_addr, 0); - DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)buf->kvaddr, (unsigned long)buf->dma_addr, @@ -150,7 +147,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev, * non-continuous memory would be released by exynos * gem framework. */ - if (flags & EXYNOS_BO_NONCONTIG) { + if (IS_NONCONTIG_BUFFER(flags)) { DRM_DEBUG_KMS("not support allocation type.\n"); return; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index fa1aa94..26d5197 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -56,9 +56,28 @@ static unsigned int convert_to_vm_err_msg(int msg) return out_msg; } -static unsigned int mask_gem_flags(unsigned int flags) +static int check_gem_flags(unsigned int flags) { - return flags &= EXYNOS_BO_NONCONTIG; + if (flags & ~(EXYNOS_BO_MASK)) { + DRM_ERROR("invalid flags.\n"); + return -EINVAL; + } + + return 0; +} + +static unsigned long roundup_gem_size(unsigned long size, unsigned int flags) +{ + if (!IS_NONCONTIG_BUFFER(flags)) { + if (size >= SZ_1M) + return roundup(size, SECTION_SIZE); + else if (size >= SZ_64K) + return roundup(size, SZ_64K); + else + goto out; + } +out: + return roundup(size, PAGE_SIZE); } static struct page **exynos_gem_get_pages(struct drm_gem_object *obj, @@ -319,10 +338,17 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, struct exynos_drm_gem_buf *buf; int ret; - size = roundup(size, PAGE_SIZE); - DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); + if (!size) { + DRM_ERROR("invalid size.\n"); + return ERR_PTR(-EINVAL); + } - flags = mask_gem_flags(flags); + size = roundup_gem_size(size, flags); + DRM_DEBUG_KMS("%s\n", __FILE__); + + ret = check_gem_flags(flags); + if (ret) + return ERR_PTR(ret); buf = exynos_drm_init_buf(dev, size); if (!buf) @@ -331,7 +357,7 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, exynos_gem_obj = exynos_drm_gem_init(dev, size); if (!exynos_gem_obj) { ret = -ENOMEM; - goto err; + goto err_fini_buf; } exynos_gem_obj->buffer = buf; @@ -347,18 +373,19 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, ret = exynos_drm_gem_get_pages(&exynos_gem_obj->base); if (ret < 0) { drm_gem_object_release(&exynos_gem_obj->base); - goto err; + goto err_fini_buf; } } else { ret = exynos_drm_alloc_buf(dev, buf, flags); if (ret < 0) { drm_gem_object_release(&exynos_gem_obj->base); - goto err; + goto err_fini_buf; } } return exynos_gem_obj; -err: + +err_fini_buf: exynos_drm_fini_buf(dev, buf); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index e40fbad..4ed8420 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -29,6 +29,8 @@ #define to_exynos_gem_obj(x) container_of(x,\ struct exynos_drm_gem_obj, base) +#define IS_NONCONTIG_BUFFER(f) (f & EXYNOS_BO_NONCONTIG) + /* * exynos drm gem buffer structure. * diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h index 3963116..1bb2d47 100644 --- a/include/drm/exynos_drm.h +++ b/include/drm/exynos_drm.h @@ -96,7 +96,8 @@ struct drm_exynos_plane_set_zpos { /* memory type definitions. */ enum e_drm_exynos_gem_mem_type { /* Physically Non-Continuous memory. */ - EXYNOS_BO_NONCONTIG = 1 << 0 + EXYNOS_BO_NONCONTIG = 1 << 0, + EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG }; #define DRM_EXYNOS_GEM_CREATE 0x00 -- cgit v0.10.2 From 61db75d83ca2ac7d46b72fe94b253bbe277bb178 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Tue, 3 Apr 2012 21:49:15 +0900 Subject: drm/exynos: fixed duplicated page allocation bug. this patch fixes that buf->pages is allocated two times when it allocates physically continuous memory region and removes unnecessary codes. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 52d42cd..de8d209 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -34,7 +34,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, unsigned int flags, struct exynos_drm_gem_buf *buf) { - dma_addr_t start_addr, end_addr; + dma_addr_t start_addr; unsigned int npages, page_size, i = 0; struct scatterlist *sgl; int ret = 0; @@ -76,26 +76,13 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, return -ENOMEM; } - buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size, - &buf->dma_addr, GFP_KERNEL); - if (!buf->kvaddr) { - DRM_ERROR("failed to allocate buffer.\n"); - ret = -ENOMEM; - goto err1; - } - - start_addr = buf->dma_addr; - end_addr = buf->dma_addr + buf->size; - - buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL); - if (!buf->pages) { - DRM_ERROR("failed to allocate pages.\n"); - ret = -ENOMEM; - goto err2; - } - - start_addr = buf->dma_addr; - end_addr = buf->dma_addr + buf->size; + buf->kvaddr = dma_alloc_writecombine(dev->dev, buf->size, + &buf->dma_addr, GFP_KERNEL); + if (!buf->kvaddr) { + DRM_ERROR("failed to allocate buffer.\n"); + ret = -ENOMEM; + goto err1; + } buf->pages = kzalloc(sizeof(struct page) * npages, GFP_KERNEL); if (!buf->pages) { @@ -105,20 +92,17 @@ static int lowlevel_buffer_allocate(struct drm_device *dev, } sgl = buf->sgt->sgl; + start_addr = buf->dma_addr; while (i < npages) { buf->pages[i] = phys_to_page(start_addr); sg_set_page(sgl, buf->pages[i], page_size, 0); sg_dma_address(sgl) = start_addr; start_addr += page_size; - if (end_addr - start_addr < page_size) - break; sgl = sg_next(sgl); i++; } - buf->pages[i] = phys_to_page(start_addr); - DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n", (unsigned long)buf->kvaddr, (unsigned long)buf->dma_addr, -- cgit v0.10.2 From 79026ff2b6e7bee5b79a61e0721b6d9bf0e99b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 3 Apr 2012 09:33:58 -0700 Subject: Input: tps6507x-ts - fix MODULE_ALIAS to match driver name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is needed to make module auto loading work. [dtor@mail.ru: remove file name from comment] Signed-off-by: Uwe Kleine-König Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index 6c6f6d8..f7eda3d0 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -1,6 +1,4 @@ /* - * drivers/input/touchscreen/tps6507x_ts.c - * * Touchscreen driver for the tps6507x chip. * * Copyright (c) 2009 RidgeRun (todd.fischer@ridgerun.com) @@ -376,4 +374,4 @@ module_platform_driver(tps6507x_ts_driver); MODULE_AUTHOR("Todd Fischer "); MODULE_DESCRIPTION("TPS6507x - TouchScreen driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:tps6507x-tsc"); +MODULE_ALIAS("platform:tps6507x-ts"); -- cgit v0.10.2 From d626dad58f02e13730ded6ac84d6a9e53123f0e8 Mon Sep 17 00:00:00 2001 From: Oskari Saarenmaa Date: Tue, 3 Apr 2012 09:46:32 -0700 Subject: Input: sentelic - filter taps in absolute mode Taps in absolute positioning single-finger mode are currently reported as physical clicks by the driver. This should be handled by userspace, not the kernel. When a tap occurs, the FSP_PB0_LBTN bit is set, but the FSP_PB0_PHY_BTN is not. We use this to filter out physical clicks from taps. Signed-off-by: Oskari Saarenmaa Reviewed-by: Tai-hwa Liang Reviewed-by: Chase Douglas Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index a977bfa..661a0ca 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -741,6 +741,14 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) } } else { /* SFAC packet */ + if ((packet[0] & (FSP_PB0_LBTN|FSP_PB0_PHY_BTN)) == + FSP_PB0_LBTN) { + /* On-pad click in SFAC mode should be handled + * by userspace. On-pad clicks in MFMC mode + * are real clickpad clicks, and not ignored. + */ + packet[0] &= ~FSP_PB0_LBTN; + } /* no multi-finger information */ ad->last_mt_fgr = 0; -- cgit v0.10.2 From 7b78f13603c6fcb64e020a0bbe31a651ea2b657b Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Wed, 4 Apr 2012 10:45:27 +0200 Subject: perf tools: Fix getrusage() related build failure on glibc trunk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On a system running glibc trunk perf doesn't build: CC builtin-sched.o builtin-sched.c: In function ‘get_cpu_usage_nsec_parent’: builtin-sched.c:399:16: error: storage size of ‘ru’ isn’t known builtin-sched.c:403:2: error: implicit declaration of function ‘getrusage’ [-Werror=implicit-function-declaration] [...] Fix it by including sys/resource.h. Signed-off-by: Markus Trippelsdorf Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20120404084527.GA294@x4 Signed-off-by: Ingo Molnar diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fb8b5f8..1cad3af 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -17,6 +17,7 @@ #include "util/debug.h" #include +#include #include #include -- cgit v0.10.2 From fef9516425cb3a03a4a95b4de3cf8c575521df9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Apr 2012 12:06:24 +0100 Subject: MAINTAINERS: Don't list everyone working on Wolfson drivers Rather than listing every single person who works on the drivers include the mailing list where they can all be found. Leave myself as a human contact. Signed-off-by: Mark Brown diff --git a/MAINTAINERS b/MAINTAINERS index 85c599b..5190cf2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7463,8 +7463,7 @@ F: include/linux/wm97xx.h WOLFSON MICROELECTRONICS DRIVERS M: Mark Brown -M: Ian Lartey -M: Dimitris Papastamos +L: patches@opensource.wolfsonmicro.com T: git git://opensource.wolfsonmicro.com/linux-2.6-asoc T: git git://opensource.wolfsonmicro.com/linux-2.6-audioplus W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices -- cgit v0.10.2 From 7358e51082b68e2026628220510a29197e2b9933 Mon Sep 17 00:00:00 2001 From: Kautuk Consul Date: Mon, 26 Mar 2012 06:40:49 +0000 Subject: sparc/mm/fault_64.c: Port OOM changes to do_sparc64_fault Commit d065bd810b6deb67d4897a14bfe21f8eb526ba99 (mm: retry page fault when blocking on disk transfer) and commit 37b23e0525d393d48a7d59f870b3bc061a30ccdb (x86,mm: make pagefault killable) The above commits introduced changes into the x86 pagefault handler for making the page fault handler retryable as well as killable. These changes reduce the mmap_sem hold time, which is crucial during OOM killer invocation. Port these changes to 64-bit sparc. Signed-off-by: Kautuk Consul Signed-off-by: David S. Miller diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c index 504c062..1fe0429 100644 --- a/arch/sparc/mm/fault_64.c +++ b/arch/sparc/mm/fault_64.c @@ -279,6 +279,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) unsigned int insn = 0; int si_code, fault_code, fault; unsigned long address, mm_rss; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; fault_code = get_thread_fault_code(); @@ -333,6 +334,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) insn = get_fault_insn(regs, insn); goto handle_kernel_fault; } + +retry: down_read(&mm->mmap_sem); } @@ -423,7 +426,12 @@ good_area: goto bad_area; } - fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE) ? FAULT_FLAG_WRITE : 0); + flags |= ((fault_code & FAULT_CODE_WRITE) ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -431,12 +439,27 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + current->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, + 1, regs, address); + } else { + current->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, + 1, regs, address); + } + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + + goto retry; + } } up_read(&mm->mmap_sem); -- cgit v0.10.2 From c29554f53e4679d30f4eb39cad7700023cbaae67 Mon Sep 17 00:00:00 2001 From: Kautuk Consul Date: Mon, 26 Mar 2012 06:47:54 +0000 Subject: sparc/mm/fault_32.c: Port OOM changes to do_sparc_fault Commit d065bd810b6deb67d4897a14bfe21f8eb526ba99 (mm: retry page fault when blocking on disk transfer) and commit 37b23e0525d393d48a7d59f870b3bc061a30ccdb (x86,mm: make pagefault killable) The above commits introduced changes into the x86 pagefault handler for making the page fault handler retryable as well as killable. These changes reduce the mmap_sem hold time, which is crucial during OOM killer invocation. Port these changes to 32-bit sparc. Signed-off-by: Kautuk Consul Signed-off-by: David S. Miller diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index 7705c67..df3155a 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -225,6 +225,8 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long g2; int from_user = !(regs->psr & PSR_PS); int fault, code; + unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | + (write ? FAULT_FLAG_WRITE : 0)); if(text_fault) address = regs->pc; @@ -251,6 +253,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); +retry: down_read(&mm->mmap_sem); /* @@ -289,7 +292,11 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0); + fault = handle_mm_fault(mm, vma, address, flags); + + if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) + return; + if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) goto out_of_memory; @@ -297,13 +304,29 @@ good_area: goto do_sigbus; BUG(); } - if (fault & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs, address); - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + + if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (fault & VM_FAULT_MAJOR) { + current->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, + 1, regs, address); + } else { + current->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, + 1, regs, address); + } + if (fault & VM_FAULT_RETRY) { + flags &= ~FAULT_FLAG_ALLOW_RETRY; + + /* No need to up_read(&mm->mmap_sem) as we would + * have already released it in __lock_page_or_retry + * in mm/filemap.c. + */ + + goto retry; + } } + up_read(&mm->mmap_sem); return; -- cgit v0.10.2 From d657784b70ef653350d7aa49da90a8484c29da7d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Wed, 4 Apr 2012 21:20:01 +0200 Subject: sparc32,leon: fix leon build Minimal fix to allow leon to be built. Signed-off-by: Sam Ravnborg Cc: Konrad Eisele Cc: Daniel Hellstrom Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index aba6b95..19f5605 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c @@ -45,7 +45,6 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) void __devinit pcibios_fixup_bus(struct pci_bus *pbus) { - struct leon_pci_info *info = pbus->sysdata; struct pci_dev *dev; int i, has_io, has_mem; u16 cmd; @@ -111,18 +110,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) -{ - /* - * Currently the OpenBoot nodes are not connected with the PCI device, - * this is because the LEON PROM does not create PCI nodes. Eventually - * this will change and the same approach as pcic.c can be used to - * match PROM nodes with pci devices. - */ - return NULL; -} -EXPORT_SYMBOL(pci_device_to_OF_node); - void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) { #ifdef CONFIG_PCI_DEBUG -- cgit v0.10.2 From 5e2f7d617b574dadf3ad125e4821ce1b180b1626 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Wed, 4 Apr 2012 22:11:16 -0400 Subject: GFS2: Make sure rindex is uptodate before starting transactions This patch removes the call from gfs2_blk2rgrd to function gfs2_rindex_update and replaces it with individual calls. The former way turned out to be too problematic. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 197c5c4..03c04fe 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -724,7 +724,11 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, int metadata; unsigned int revokes = 0; int x; - int error = 0; + int error; + + error = gfs2_rindex_update(sdp); + if (error) + return error; if (!*top) sm->sm_first = 0; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index c35573a..a836056 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -1844,6 +1844,10 @@ static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len, unsigned int x, size = len * sizeof(u64); int error; + error = gfs2_rindex_update(sdp); + if (error) + return error; + memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); ht = kzalloc(size, GFP_NOFS); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index c98a60e..a9ba244 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1031,7 +1031,13 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) struct buffer_head *bh; struct gfs2_holder ghs[3]; struct gfs2_rgrpd *rgd; - int error = -EROFS; + int error; + + error = gfs2_rindex_update(sdp); + if (error) + return error; + + error = -EROFS; gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); @@ -1224,6 +1230,10 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, return 0; } + error = gfs2_rindex_update(sdp); + if (error) + return error; + if (odip != ndip) { error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE, 0, &r_gh); @@ -1345,7 +1355,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, error = alloc_required; if (error < 0) goto out_gunlock; - error = 0; if (alloc_required) { struct gfs2_qadata *qa = gfs2_qadata_get(ndip); diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 19354a2..3df65c9 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -332,9 +332,6 @@ struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact) struct rb_node *n, *next; struct gfs2_rgrpd *cur; - if (gfs2_rindex_update(sdp)) - return NULL; - spin_lock(&sdp->sd_rindex_spin); n = sdp->sd_rindex_tree.rb_node; while (n) { @@ -928,6 +925,10 @@ int gfs2_fitrim(struct file *filp, void __user *argp) } else if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; + ret = gfs2_rindex_update(sdp); + if (ret) + return ret; + rgd = gfs2_blk2rgrpd(sdp, r.start, 0); rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0); diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 2e5ba42..927f4df 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c @@ -238,6 +238,10 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, unsigned int x; int error; + error = gfs2_rindex_update(sdp); + if (error) + return error; + if (GFS2_EA_IS_STUFFED(ea)) return 0; @@ -1330,6 +1334,10 @@ static int ea_dealloc_indirect(struct gfs2_inode *ip) unsigned int x; int error; + error = gfs2_rindex_update(sdp); + if (error) + return error; + memset(&rlist, 0, sizeof(struct gfs2_rgrp_list)); error = gfs2_meta_read(ip->i_gl, ip->i_eattr, DIO_WAIT, &indbh); @@ -1439,6 +1447,10 @@ static int ea_dealloc_block(struct gfs2_inode *ip) struct gfs2_holder gh; int error; + error = gfs2_rindex_update(sdp); + if (error) + return error; + rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1); if (!rgd) { gfs2_consist_inode(ip); -- cgit v0.10.2 From 1f99e44cf059d2ed43c5a0724fa738b83800f725 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 4 Apr 2012 23:28:01 -0700 Subject: ASoC: ak4642: fixup: mute needs +1 step ak4642 out_tlv is +12.0dB to -115.0 dB, and it supports mute. But current settings didn't care +1 step for mute. This patch adds it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Cc: stable@vger.kernel.org diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index f8e10ce..b3e24f2 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -140,7 +140,7 @@ * min : 0xFE : -115.0 dB * mute: 0xFF */ -static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1); +static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1); static const struct snd_kcontrol_new ak4642_snd_controls[] = { -- cgit v0.10.2 From 6b1c762da98fd0d475a4539f94541aec91a8de30 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 5 Apr 2012 11:21:09 +0900 Subject: drm/exynos: add format list of plane NV12, NV12M and NV12MT are added to format list of plane to use these formats for hdmi vp layer. Signed-off-by: Seung-Woo Kim Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index c277a3a..f92fe4c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -24,6 +24,10 @@ struct exynos_plane { static const uint32_t formats[] = { DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_NV12, + DRM_FORMAT_NV12M, + DRM_FORMAT_NV12MT, }; static int -- cgit v0.10.2 From 6d27f09a6398ee086b11804aa3a16609876f0c7c Mon Sep 17 00:00:00 2001 From: Ryosuke Saito Date: Thu, 5 Apr 2012 08:09:34 -0600 Subject: mtip32xx: fix error handling in mtip_init() Ensure that block device is properly unregistered, if pci_register_driver() fails. Signed-off-by: Ryosuke Saito Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 04f69e6da..c37073d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3605,18 +3605,25 @@ MODULE_DEVICE_TABLE(pci, mtip_pci_tbl); */ static int __init mtip_init(void) { + int error; + printk(KERN_INFO MTIP_DRV_NAME " Version " MTIP_DRV_VERSION "\n"); /* Allocate a major block device number to use with this driver. */ - mtip_major = register_blkdev(0, MTIP_DRV_NAME); - if (mtip_major < 0) { + error = register_blkdev(0, MTIP_DRV_NAME); + if (error <= 0) { printk(KERN_ERR "Unable to register block device (%d)\n", - mtip_major); + error); return -EBUSY; } + mtip_major = error; /* Register our PCI operations. */ - return pci_register_driver(&mtip_pci_driver); + error = pci_register_driver(&mtip_pci_driver); + if (error) + unregister_blkdev(mtip_major, MTIP_DRV_NAME); + + return error; } /* -- cgit v0.10.2 From 00792ac4e0d88e82fc489a5e1c4d4435125a301c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 5 Apr 2012 09:45:51 -0300 Subject: ASoC: imx-audmux: Fix ssi port numbers in sysfs Doing a 'cat /sys/kernel/debug/audmux/ssi7' causes the following oops to be printed by the kernel: Uhandled fault: external abort on non-linefetch (0x008) at 0xf53b003c Internal error: : 8 [#1] PREEMPT Modules linked in: CPU: 0 Not tainted (3.3.0-00033-gecc726e-dirty #307) PC is at audmux_read_file+0x68/0x2f4 LR is at clk_enable+0x3c/0x48 pc : [] lr : [] psr: a0000013 sp : c3ad3f38 ip : c30a4000 fp : 00000003 r10: 00001000 r9 : be83fb00 r8 : c3ad3f80 r7 : c3ad3f80 r6 : 00000007 r5 : 00031010 r4 : c30a5000 r3 : f53b0000 r2 : 0000003c r1 : 380fa100 r0 : c068dda0 Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 0005317f Table: 83034000 DAC: 00000015 Process cat (pid: 1042, stack limit = 0xc3ad2270) Stack: (0xc3ad3f38 to 0xc3ad4000) 3f20: c3139180 00000000 3f40: c3bc6500 00001000 be83fb00 c3ad3f80 00001000 c3ad2000 00000000 c0095f3c 3f60: 00000003 c3bc6508 c3bc6500 be83fb00 00000000 00000000 00001000 c0096010 3f80: 00000000 00000000 b6fe2050 00000000 00001000 be83fb00 00000003 00000003 3fa0: c000eb88 c000e9e0 00001000 be83fb00 00000003 be83fb00 00001000 00000000 3fc0: 00001000 be83fb00 00000003 00000003 00000001 00000001 00000000 00000003 3fe0: 000bec8c be83fae0 0000f808 b6ea8d5c 60000010 00000003 7dff7ede 749bedf1 [] (audmux_read_file+0x68/0x2f4) from [] (vfs_read+0xb0/0x144) [] (vfs_read+0xb0/0x144) from [] (sys_read+0x40/0x70) [] (sys_read+0x40/0x70) from [] (ret_fast_syscall+0x0/0x2c) Code: e1a02186 e2822004 e3500000 e7935186 (e7937002) ---[ end trace 4d046e31309023de ]--- Fix the ssi port numbers in sysfs to fix this problem. Reported-by: Joan Carles Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c index 601df80..912a342 100644 --- a/sound/soc/imx/imx-audmux.c +++ b/sound/soc/imx/imx-audmux.c @@ -158,7 +158,7 @@ static void __init audmux_debugfs_init(void) return; } - for (i = 1; i < 8; i++) { + for (i = 0; i < MX31_AUDMUX_PORT6_SSI_PINS_6 + 1; i++) { snprintf(buf, sizeof(buf), "ssi%d", i); if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, (void *)i, &audmux_debugfs_fops)) -- cgit v0.10.2 From 66bb2a7f835a28a9405f3f6571fbf34156e6bc1e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 5 Apr 2012 10:57:51 -0300 Subject: ASoC: imx-audmux: Check for NULL pointer Check for NULL pointer before accessing it. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c index 912a342..0fe66c3 100644 --- a/sound/soc/imx/imx-audmux.c +++ b/sound/soc/imx/imx-audmux.c @@ -79,6 +79,9 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; + if (!audmux_base) + return -ENOSYS; + if (audmux_clk) clk_prepare_enable(audmux_clk); -- cgit v0.10.2 From 66f3b913e68e8e62bd2f9499495eeb6cc81b2662 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Thu, 29 Mar 2012 09:47:53 -0300 Subject: Bluetooth: Fix userspace compatibility issue with mgmt interface To ensure that old user space versions do not accidentally pick up and try to use the management channel, use a different channel number. Reported-by: Keith Packard Acked-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 8f928f7..d47e523 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1328,8 +1328,8 @@ struct sockaddr_hci { #define HCI_DEV_NONE 0xffff #define HCI_CHANNEL_RAW 0 -#define HCI_CHANNEL_CONTROL 1 #define HCI_CHANNEL_MONITOR 2 +#define HCI_CHANNEL_CONTROL 3 struct hci_filter { unsigned long type_mask; -- cgit v0.10.2 From 3fec6b6d5a53d37194735268b9e220f75ca37f19 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 5 Apr 2012 12:28:01 -0600 Subject: ASoC: set idle_bias_off=1 for all platform DAPM contexts The ASoC core currently defaults to using STANDBY rather than OFF for idle ASoC platform devices, which causes a permanent pm_runtime_get() on them. This keeps the device active unnecessarily. This can be especially problematic when the ASoC platform device and DAI device are the same device. The distinction between OFF and STANDBY is likely not relevant for ASoC platform drivers, since they aren't analog devices. So, solve this issue by hard-coding idle_bias_off = 1 for all ASoC platform devices. If this turns out to be a problem, this value could be sourced from the snd_soc_platform_driver, similarly to soc_probe_codec(). Note: Prior to this change, this caused a large (10) runtime_active count for the Tegra I2S controller even when not in use, and a leak in that value as streams were started and stopped. This change probably hides a bug. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a4deebc..8d2ebf5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1087,6 +1087,8 @@ static int soc_probe_platform(struct snd_soc_card *card, snd_soc_dapm_new_controls(&platform->dapm, driver->dapm_widgets, driver->num_dapm_widgets); + platform->dapm.idle_bias_off = 1; + if (driver->probe) { ret = driver->probe(platform); if (ret < 0) { -- cgit v0.10.2 From 4bea8b5cf8c6e875fa43e617cd52858a07ae8ea8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Apr 2012 11:16:24 -0300 Subject: perf top: Add intel_idle to the skip list TODO: Accrue the cycles in the skip_list to an idle total, and show this on the 'top' UI, as suggested by Steven. Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/n/tip-9nfecmgghgl5747rjxqpc28f@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e3c63ae..fab0a1c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -615,6 +615,7 @@ process_hotkey: /* Tag samples to be skipped. */ static const char *skip_symbols[] = { + "intel_idle", "default_idle", "native_safe_halt", "cpu_idle", -- cgit v0.10.2 From 8b84a568117fde9b77575f2060274eddab424c32 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Apr 2012 16:15:59 -0300 Subject: perf annotate: Fix hist decay We were only decaying the entries for the offsets that were associated with an objdump line. That way, when we accrued the whole instruction addr range, more than 100% was appearing in some cases in the live annotation TUI. Fix it by not traversing the source code line at all, just iterate thru the complete addr range decaying each one. Reported-by: Mike Galbraith Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-hcae5oxa22syjrnalsxz7s6n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 199f69e..70f5a4d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -561,16 +561,12 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - struct objdump_line *pos; - int len = sym->end - sym->start; + int len = sym->end - sym->start, offset; h->sum = 0; - - list_for_each_entry(pos, ¬es->src->source, node) { - if (pos->offset != -1 && pos->offset < len) { - h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; - h->sum += h->addr[pos->offset]; - } + for (offset = 0; offset < len; ++offset) { + h->addr[offset] = h->addr[offset] * 7 / 8; + h->sum += h->addr[offset]; } } -- cgit v0.10.2 From 63fa471dd49e9c9ce029d910d1024330d9b1b145 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 27 Mar 2012 03:14:18 -0400 Subject: perf hists: Catch and handle out-of-date hist entry maps. When a process exec()'s, all the maps are retired, but we keep the hist entries around which hold references to those outdated maps. If the same library gets mapped in for which we have hist entries, a new map will be created. But when we take a perf entry hit within that map, we'll find the existing hist entry with the older map. This causes symbol translations to be done incorrectly. For example, the perf entry processing will lookup the correct uptodate map entry and use that to calculate the symbol and DSO relative address. But later when we update the histogram we'll translate the address using the outdated map file instead leading to conditions such as out-of-range offsets in symbol__inc_addr_samples(). Therefore, update the map of the hist_entry dynamically at lookup/ creation time. Signed-off-by: David S. Miller Cc: stable@kernel.org Link: http://lkml.kernel.org/r/20120327.031418.1220315351537060808.davem@davemloft.net Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2ec4b60..9f6d630 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -256,6 +256,18 @@ static struct hist_entry *add_hist_entry(struct hists *hists, if (!cmp) { he->period += period; ++he->nr_events; + + /* If the map of an existing hist_entry has + * become out-of-date due to an exec() or + * similar, update it. Otherwise we will + * mis-adjust symbol addresses when computing + * the history counter to increment. + */ + if (he->ms.map != entry->ms.map) { + he->ms.map = entry->ms.map; + if (he->ms.map) + he->ms.map->referenced = true; + } goto out; } -- cgit v0.10.2 From 8493fe1daf15324eb13a4cc2f94e258716daa568 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 4 Apr 2012 22:21:31 +0200 Subject: perf hists browser: Fix NULL deref in hists browsing code If there's an event with no samples in data file, the perf report command can segfault after entering the event details menu. Following steps reproduce the issue: # ./perf record -e syscalls:sys_enter_kexec_load,syscalls:sys_enter_mmap ls # ./perf report # enter '0 syscalls:sys_enter_kexec_load' menu # pres ENTER twice Above steps are valid assuming ls wont run kexec.. ;) The check for sellection to be NULL is missing. The fix makes sure it's being check. Above steps now endup with menu being displayed allowing 'Exit' as the only option. Signed-off-by: Jiri Olsa Cc: Corey Ashford Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1333570898-10505-2-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index d7a1c4a..2f83e5d 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -125,6 +125,9 @@ static int callchain__count_rows(struct rb_root *chain) static bool map_symbol__toggle_fold(struct map_symbol *self) { + if (!self) + return false; + if (!self->has_children) return false; -- cgit v0.10.2 From 21b764e075e74f8af90da9f623aa3e2167484687 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 Apr 2012 16:10:35 -0700 Subject: ioat: ring size variables need to be 32bit to avoid overflow The alloc order can be up to 16 and 1 << 16 will over flow the 16bit integer. Change the appropriate variables to 16bit to avoid overflow. Reported-by: Jim Harris Signed-off-by: Dave Jiang Signed-off-by: Dan Williams diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index cb8864d..143cb1b 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -575,9 +575,9 @@ bool reshape_ring(struct ioat2_dma_chan *ioat, int order) */ struct ioat_chan_common *chan = &ioat->base; struct dma_chan *c = &chan->common; - const u16 curr_size = ioat2_ring_size(ioat); + const u32 curr_size = ioat2_ring_size(ioat); const u16 active = ioat2_ring_active(ioat); - const u16 new_size = 1 << order; + const u32 new_size = 1 << order; struct ioat_ring_ent **ring; u16 i; diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h index a2c413b..be2a55b 100644 --- a/drivers/dma/ioat/dma_v2.h +++ b/drivers/dma/ioat/dma_v2.h @@ -74,7 +74,7 @@ static inline struct ioat2_dma_chan *to_ioat2_chan(struct dma_chan *c) return container_of(chan, struct ioat2_dma_chan, base); } -static inline u16 ioat2_ring_size(struct ioat2_dma_chan *ioat) +static inline u32 ioat2_ring_size(struct ioat2_dma_chan *ioat) { return 1 << ioat->alloc_order; } @@ -91,7 +91,7 @@ static inline u16 ioat2_ring_pending(struct ioat2_dma_chan *ioat) return CIRC_CNT(ioat->head, ioat->issued, ioat2_ring_size(ioat)); } -static inline u16 ioat2_ring_space(struct ioat2_dma_chan *ioat) +static inline u32 ioat2_ring_space(struct ioat2_dma_chan *ioat) { return ioat2_ring_size(ioat) - ioat2_ring_active(ioat); } -- cgit v0.10.2 From f26df1a1a9452573af7b6cea9a4723593e838568 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 Apr 2012 16:10:41 -0700 Subject: ioatdma: DMA copy alignment needed to address IOAT DMA silicon errata Silicon errata where when RAID and legacy descriptors are mixed, the legacy (memcpy and friends) operation must have alignment of 64 bytes to avoid hanging. This effects Intel Xeon C55xx, C35xx, E5-2600. Signed-off-by: Dave Jiang Signed-off-by: Dan Williams diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 2dbf32b..dfe925f 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -1147,6 +1147,44 @@ static int ioat3_reset_hw(struct ioat_chan_common *chan) return ioat2_reset_sync(chan, msecs_to_jiffies(200)); } +static bool is_jf_ioat(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_JSF0: + case PCI_DEVICE_ID_INTEL_IOAT_JSF1: + case PCI_DEVICE_ID_INTEL_IOAT_JSF2: + case PCI_DEVICE_ID_INTEL_IOAT_JSF3: + case PCI_DEVICE_ID_INTEL_IOAT_JSF4: + case PCI_DEVICE_ID_INTEL_IOAT_JSF5: + case PCI_DEVICE_ID_INTEL_IOAT_JSF6: + case PCI_DEVICE_ID_INTEL_IOAT_JSF7: + case PCI_DEVICE_ID_INTEL_IOAT_JSF8: + case PCI_DEVICE_ID_INTEL_IOAT_JSF9: + return true; + default: + return false; + } +} + +static bool is_snb_ioat(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_SNB0: + case PCI_DEVICE_ID_INTEL_IOAT_SNB1: + case PCI_DEVICE_ID_INTEL_IOAT_SNB2: + case PCI_DEVICE_ID_INTEL_IOAT_SNB3: + case PCI_DEVICE_ID_INTEL_IOAT_SNB4: + case PCI_DEVICE_ID_INTEL_IOAT_SNB5: + case PCI_DEVICE_ID_INTEL_IOAT_SNB6: + case PCI_DEVICE_ID_INTEL_IOAT_SNB7: + case PCI_DEVICE_ID_INTEL_IOAT_SNB8: + case PCI_DEVICE_ID_INTEL_IOAT_SNB9: + return true; + default: + return false; + } +} + int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) { struct pci_dev *pdev = device->pdev; @@ -1167,6 +1205,9 @@ int __devinit ioat3_dma_probe(struct ioatdma_device *device, int dca) dma->device_alloc_chan_resources = ioat2_alloc_chan_resources; dma->device_free_chan_resources = ioat2_free_chan_resources; + if (is_jf_ioat(pdev) || is_snb_ioat(pdev)) + dma->copy_align = 6; + dma_cap_set(DMA_INTERRUPT, dma->cap_mask); dma->device_prep_dma_interrupt = ioat3_prep_interrupt_lock; -- cgit v0.10.2 From a2bd1140a264b561e38d99e656cd843c2d840e86 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 4 Apr 2012 16:10:46 -0700 Subject: netdma: adding alignment check for NETDMA ops This is the fallout from adding memcpy alignment workaround for certain IOATDMA hardware. NetDMA will only use DMA engine that can handle byte align ops. Acked-by: David S. Miller Signed-off-by: Dave Jiang Signed-off-by: Dan Williams diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index a6c6051..0f1ca74 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -332,6 +332,20 @@ struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) } EXPORT_SYMBOL(dma_find_channel); +/* + * net_dma_find_channel - find a channel for net_dma + * net_dma has alignment requirements + */ +struct dma_chan *net_dma_find_channel(void) +{ + struct dma_chan *chan = dma_find_channel(DMA_MEMCPY); + if (chan && !is_dma_copy_aligned(chan->device, 1, 1, 1)) + return NULL; + + return chan; +} +EXPORT_SYMBOL(net_dma_find_channel); + /** * dma_issue_pending_all - flush all pending operations across all channels */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 679b349d..a5bb3ad 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -948,6 +948,7 @@ int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device); void dma_run_dependencies(struct dma_async_tx_descriptor *tx); struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type); +struct dma_chan *net_dma_find_channel(void); #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) /* --- Helper iov-locking functions --- */ diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 22ef5f9..8712c5d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1450,7 +1450,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if ((available < target) && (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) && !sysctl_tcp_low_latency && - dma_find_channel(DMA_MEMCPY)) { + net_dma_find_channel()) { preempt_enable_no_resched(); tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len); @@ -1665,7 +1665,7 @@ do_prequeue: if (!(flags & MSG_TRUNC)) { #ifdef CONFIG_NET_DMA if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); + tp->ucopy.dma_chan = net_dma_find_channel(); if (tp->ucopy.dma_chan) { tp->ucopy.dma_cookie = dma_skb_copy_datagram_iovec( diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5e315f..27c676d 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5190,7 +5190,7 @@ static int tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, return 0; if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); + tp->ucopy.dma_chan = net_dma_find_channel(); if (tp->ucopy.dma_chan && skb_csum_unnecessary(skb)) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fd54c5f..3810b6f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1727,7 +1727,7 @@ process: #ifdef CONFIG_NET_DMA struct tcp_sock *tp = tcp_sk(sk); if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); + tp->ucopy.dma_chan = net_dma_find_channel(); if (tp->ucopy.dma_chan) ret = tcp_v4_do_rcv(sk, skb); else diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05a..fcb3e4f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1755,7 +1755,7 @@ process: #ifdef CONFIG_NET_DMA struct tcp_sock *tp = tcp_sk(sk); if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan = dma_find_channel(DMA_MEMCPY); + tp->ucopy.dma_chan = net_dma_find_channel(); if (tp->ucopy.dma_chan) ret = tcp_v6_do_rcv(sk, skb); else -- cgit v0.10.2 From 31d68e7b66f168e623902e194af1e52b8cf75d71 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Mar 2012 12:55:57 -0300 Subject: perf annotate: Validate addr in symbol__inc_addr_samples This routine was checking only if the provided address was after sym->end, not if it was before sym->start. Fix that by checking for both and return in both cases -ERANGE, so that tools can communicate this to the user properly, or if they chose so, to abort. This problem was reported previously but the fixes involved either doing what was being done for the > end case, i.e. silently drop the sample, returning 0, or aborting at this function, which is in a lib (or better, is slated to be at some point) and shouldn't abort. The 'report' tool already checks this value and uses pr_debug to warn the user. This patch makes the 'top' tool check it too and warn once per map where such range problem takes place. Reported-by: David Miller Reported-by: Sorin Dumitru Reported-by: Stephane Eranian Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-lw8gs7p9i9nhldilo82tzpne@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fab0a1c..8ef59f8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -42,6 +42,7 @@ #include "util/debug.h" #include +#include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include @@ -162,12 +164,40 @@ static void __zero_source_counters(struct hist_entry *he) symbol__annotate_zero_histograms(sym); } +static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) +{ + struct utsname uts; + int err = uname(&uts); + + ui__warning("Out of bounds address found:\n\n" + "Addr: %" PRIx64 "\n" + "DSO: %s %c\n" + "Map: %" PRIx64 "-%" PRIx64 "\n" + "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n" + "Arch: %s\n" + "Kernel: %s\n" + "Tools: %s\n\n" + "Not all samples will be on the annotation output.\n\n" + "Please report to linux-kernel@vger.kernel.org\n", + ip, map->dso->long_name, dso__symtab_origin(map->dso), + map->start, map->end, sym->start, sym->end, + sym->binding == STB_GLOBAL ? 'g' : + sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, + err ? "[unknown]" : uts.machine, + err ? "[unknown]" : uts.release, perf_version_string); + if (use_browser <= 0) + sleep(5); + + map->erange_warned = true; +} + static void perf_top__record_precise_ip(struct perf_top *top, struct hist_entry *he, int counter, u64 ip) { struct annotation *notes; struct symbol *sym; + int err; if (he == NULL || he->ms.sym == NULL || ((top->sym_filter_entry == NULL || @@ -189,9 +219,12 @@ static void perf_top__record_precise_ip(struct perf_top *top, } ip = he->ms.map->map_ip(he->ms.map, ip); - symbol__inc_addr_samples(sym, he->ms.map, counter, ip); + err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); pthread_mutex_unlock(¬es->lock); + + if (err == -ERANGE && !he->ms.map->erange_warned) + ui__warn_map_erange(he->ms.map, sym, ip); } static void perf_top__show_details(struct perf_top *top) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 70f5a4d..08c6d13 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -64,8 +64,8 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr > sym->end) - return 0; + if (addr < sym->start || addr > sym->end) + return -ERANGE; offset = addr - sym->start; h = annotation__histogram(notes, evidx); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index dea6d1c..35ae568 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -38,6 +38,7 @@ void map__init(struct map *self, enum map_type type, RB_CLEAR_NODE(&self->rb_node); self->groups = NULL; self->referenced = false; + self->erange_warned = false; } struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b100c20..81371ba 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -33,6 +33,7 @@ struct map { u64 end; u8 /* enum map_type */ type; bool referenced; + bool erange_warned; u32 priv; u64 pgoff; -- cgit v0.10.2 From 46ed99d1b7c92920ce9e313152522847647aae4f Mon Sep 17 00:00:00 2001 From: Emil Goode Date: Sun, 1 Apr 2012 20:48:04 +0200 Subject: x86: vsyscall: Use NULL instead 0 for a pointer argument This patch silences the following sparse warning: arch/x86/kernel/vsyscall_64.c:250:34: warning: Using plain integer as NULL pointer Signed-off-by: Emil Goode Acked-by: Andy Lutomirski Cc: john.stultz@linaro.org Link: http://lkml.kernel.org/r/1333306084-3776-1-git-send-email-emilgoode@gmail.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index f386dc4..7515cf0e 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -216,9 +216,9 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) current_thread_info()->sig_on_uaccess_error = 1; /* - * 0 is a valid user pointer (in the access_ok sense) on 32-bit and + * NULL is a valid user pointer (in the access_ok sense) on 32-bit and * 64-bit, so we don't need to special-case it here. For all the - * vsyscalls, 0 means "don't write anything" not "write it at + * vsyscalls, NULL means "don't write anything" not "write it at * address 0". */ ret = -EFAULT; @@ -247,7 +247,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) ret = sys_getcpu((unsigned __user *)regs->di, (unsigned __user *)regs->si, - 0); + NULL); break; } -- cgit v0.10.2 From 6f103929f8979d2638e58d7f7fda0beefcb8ee7e Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 27 Mar 2012 15:09:37 -0400 Subject: nohz: Fix stale jiffies update in tick_nohz_restart() Fix tick_nohz_restart() to not use a stale ktime_t "now" value when calling tick_do_update_jiffies64(now). If we reach this point in the loop it means that we crossed a tick boundary since we grabbed the "now" timestamp, so at this point "now" refers to a time in the old jiffy, so using the old value for "now" is incorrect, and is likely to give us a stale jiffies value. In particular, the first time through the loop the tick_do_update_jiffies64(now) call is always a no-op, since the caller, tick_nohz_restart_sched_tick(), will have already called tick_do_update_jiffies64(now) with that "now" value. Note that tick_nohz_stop_sched_tick() already uses the correct approach: when we notice we cross a jiffy boundary, grab a new timestamp with ktime_get(), and *then* update jiffies. Signed-off-by: Neal Cardwell Cc: Ben Segall Cc: Ingo Molnar Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1332875377-23014-1-git-send-email-ncardwell@google.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 3526038..6a3a5b9 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -534,9 +534,9 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) hrtimer_get_expires(&ts->sched_timer), 0)) break; } - /* Update jiffies and reread time */ - tick_do_update_jiffies64(now); + /* Reread time and update jiffies */ now = ktime_get(); + tick_do_update_jiffies64(now); } } -- cgit v0.10.2 From 8abe05c6eb358967f16bce8a02c88d57c82cfbd6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 5 Apr 2012 23:11:16 -0600 Subject: ASoC: tegra: fix i2s compilation when !CONFIG_DEBUG_FS Commit d4a2eca "ASoC: Tegra I2S: Remove dependency on pdev->id" changed the prototype of tegra_i2s_debug_add, but didn't update the dummy inline used when !CONFIG_DEBUG_FS. Fix that. Signed-off-by: Stephen Warren Signed-off-by: Mark Brown Cc: # 3.3 diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 2d98c92..e533499 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c @@ -116,7 +116,7 @@ static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) debugfs_remove(i2s->debug); } #else -static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) +static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s) { } -- cgit v0.10.2 From 2ca052a3710fac208eee690faefdeb8bbd4586a1 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Mon, 2 Apr 2012 16:15:33 -0700 Subject: x86: Use correct byte-sized register constraint in __xchg_op() x86-64 can access the low half of any register, but i386 can only do it with a subset of registers. 'r' causes compilation failures on i386, but 'q' expresses the constraint properly. Signed-off-by: Jeremy Fitzhardinge Link: http://lkml.kernel.org/r/4F7A3315.501@goop.org Reported-by: Leigh Scott Tested-by: Thomas Reitmayr Signed-off-by: H. Peter Anvin Cc: v3.3 diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index b3b7332..bc18d0e 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -43,7 +43,7 @@ extern void __add_wrong_size(void) switch (sizeof(*(ptr))) { \ case __X86_CASE_B: \ asm volatile (lock #op "b %b0, %1\n" \ - : "+r" (__ret), "+m" (*(ptr)) \ + : "+q" (__ret), "+m" (*(ptr)) \ : : "memory", "cc"); \ break; \ case __X86_CASE_W: \ -- cgit v0.10.2 From 8c91c5325e107ec17e40a59a47c6517387d64eb7 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 6 Apr 2012 09:30:57 -0700 Subject: x86: Use correct byte-sized register constraint in __add() Similar to: 2ca052a x86: Use correct byte-sized register constraint in __xchg_op() ... the __add() macro also needs to use a "q" constraint in the byte-sized case, lest we try to generate an illegal register. Link: http://lkml.kernel.org/r/4F7A3315.501@goop.org Signed-off-by: H. Peter Anvin Cc: Jeremy Fitzhardinge Cc: Leigh Scott Cc: Thomas Reitmayr Cc: v3.3 diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index bc18d0e..99480e5 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -173,7 +173,7 @@ extern void __add_wrong_size(void) switch (sizeof(*(ptr))) { \ case __X86_CASE_B: \ asm volatile (lock "addb %b1, %0\n" \ - : "+m" (*(ptr)) : "ri" (inc) \ + : "+m" (*(ptr)) : "qi" (inc) \ : "memory", "cc"); \ break; \ case __X86_CASE_W: \ -- cgit v0.10.2 From 1b2e19f17ed327af6add02978efdf354e4f8e4df Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 6 Apr 2012 11:37:47 -0600 Subject: block: make auto block plug flush threshold per-disk based We do auto block plug flush to reduce latency, the threshold is 16 requests. This works well if the task is accessing one or two drives. The problem is if the task is accessing a raid 0 device and the raid disk number is big, say 8 or 16, 16/8 = 2 or 16/16=1, we will have heavy lock contention. This patch makes the threshold per-disk based. The latency should be still ok accessing one or two drives. The setup with application accessing a lot of drives in the meantime uaually is big machine, avoiding lock contention is more important, because any contention will actually increase latency. Signed-off-by: Shaohua Li Signed-off-by: Jens Axboe diff --git a/block/blk-core.c b/block/blk-core.c index 414e822..1f61b74 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -1277,7 +1277,8 @@ static bool attempt_plug_merge(struct request_queue *q, struct bio *bio, list_for_each_entry_reverse(rq, &plug->list, queuelist) { int el_ret; - (*request_count)++; + if (rq->q == q) + (*request_count)++; if (rq->q != q || !blk_rq_merge_ok(rq, bio)) continue; -- cgit v0.10.2 From a8edc42a11e1d7b7e158d4026670fd83854dfcc2 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 22 Mar 2012 14:01:07 -0700 Subject: usb: Put USB Kconfig items back under USB. commit 53c6bc24fdc8db87109a5760579cbb060fa644cf (usb: Don't make USB_ARCH_HAS_{XHCI,OHCI,EHCI} depend on USB_SUPPORT.) Removed the dependency of the USB_ARCH_HAS_* symbols on USB_SUPPORT. However the resulting Kconfig somehow caused many of the USB configuration items to appear under the top level devices menu. To fix this we reunite the 'menuconfig USB_SUPPORT' with the 'if USB_SUPPORT', and the config items magically go back to their desired location. Reported-by: Julian Wollrath Reported-by: Nobuhiro Iwamatsu Reported-by: Borislav Petkov Reported-by: Rupesh Gujare Reported-by: Feng King Reported-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: David Daney Tested-by: Peter Chen Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index cbd8f5f..76316a3 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -2,14 +2,6 @@ # USB device configuration # -menuconfig USB_SUPPORT - bool "USB support" - depends on HAS_IOMEM - default y - ---help--- - This option adds core support for Universal Serial Bus (USB). - You will also need drivers from the following menu to make use of it. - # many non-PCI SOC chips embed OHCI config USB_ARCH_HAS_OHCI boolean @@ -63,6 +55,14 @@ config USB_ARCH_HAS_XHCI boolean default PCI +menuconfig USB_SUPPORT + bool "USB support" + depends on HAS_IOMEM + default y + ---help--- + This option adds core support for Universal Serial Bus (USB). + You will also need drivers from the following menu to make use of it. + if USB_SUPPORT config USB_COMMON -- cgit v0.10.2 From 2e8dc2f2c1f669401f4bb07ccdb92ae8e44a9f00 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sat, 17 Mar 2012 15:23:49 +0100 Subject: usb/usbmon: correct the data interpretation of usbmon's output The doc says that the data | 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000 is the SCSI command 0x5e. According to the usbmon source, it dumps one byte after the other. The first 4 bytes are US_BULK_CB_SIGN which is correct. After that we see the TAG which is 0x5e. The cdb is 0x00 in this example. In order to correct this, I change the example to a READ_10 command which is 0x28 so it is not just a zero somewhere in the stream. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 5335fa8..c42bb9c 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -183,10 +183,10 @@ An input control transfer to get a port status. d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 < d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000 -An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper -to a storage device at address 5: +An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte +Bulk wrapper to a storage device at address 5: -dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000 +dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000 dd65f0e8 4128379808 C Bo:1:005:2 0 31 > * Raw binary format and API -- cgit v0.10.2 From c825bab0cef8b90bab8b63eb5686b8c8eb22e798 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Mon, 19 Mar 2012 15:20:57 +0800 Subject: usb: storage: fix lockdep warning inside usb_stor_pre_reset(v2) This patch fixes one lockdep warning[1] inside usb_stor_pre_reset. If the current configuration includes multiple mass storage interfaces, the 'AA' lockdep warning will be triggered since the lock class of 'us->dev_mutex' is acquired two times in .reset path. It isn't a real deadlock, so just take the lockdep_set_class annotation to remove the warning. [1], lockdep warning log :[ INFO: possible recursive locking detected ] :3.3.0-0.rc5.git3.1.fc17.x86_64 #1 Tainted: G W :--------------------------------------------- :usb-storage/14846 is trying to acquire lock: : (&(us->dev_mutex)){+.+.+.}, at: [] usb_stor_pre_reset+0x1c/0x20 [usb_storage] :but task is already holding lock: : (&(us->dev_mutex)){+.+.+.}, at: [] usb_stor_pre_reset+0x1c/0x20 [usb_storage] :other info that might help us debug this: : Possible unsafe locking scenario: : CPU0 : ---- : lock(&(us->dev_mutex)); : lock(&(us->dev_mutex)); : *** DEADLOCK *** : May be due to missing lock nesting notation :2 locks held by usb-storage/14846: : #0: (&__lockdep_no_validate__){......}, at: [] usb_lock_device_for_reset+0x95/0x100 : #1: (&(us->dev_mutex)){+.+.+.}, at: [] usb_stor_pre_reset+0x1c/0x20 [usb_storage] :stack backtrace: :Pid: 14846, comm: usb-storage Tainted: G W 3.3.0-0.rc5.git3.1.fc17.x86_64 #1 :Call Trace: : [] __lock_acquire+0x168f/0x1bb0 : [] ? native_sched_clock+0x13/0x80 : [] ? sched_clock+0x9/0x10 : [] ? sched_clock+0x9/0x10 : [] ? sched_clock_local+0x25/0xa0 : [] lock_acquire+0xa1/0x1e0 : [] ? usb_stor_pre_reset+0x1c/0x20 [usb_storage] : [] mutex_lock_nested+0x76/0x3a0 : [] ? usb_stor_pre_reset+0x1c/0x20 [usb_storage] : [] ? usb_stor_pre_reset+0x1c/0x20 [usb_storage] : [] usb_stor_pre_reset+0x1c/0x20 [usb_storage] : [] usb_reset_device+0x7d/0x190 : [] usb_stor_port_reset+0x7c/0x80 [usb_storage] : [] usb_stor_invoke_transport+0x94/0x560 [usb_storage] : [] ? mark_held_locks+0xb2/0x130 : [] ? _raw_spin_unlock_irq+0x30/0x50 : [] usb_stor_transparent_scsi_command+0xe/0x10 [usb_storage] : [] usb_stor_control_thread+0x173/0x280 [usb_storage] : [] ? fill_inquiry_response+0x20/0x20 [usb_storage] : [] kthread+0xb7/0xc0 : [] kernel_thread_helper+0x4/0x10 : [] ? retint_restore_args+0x13/0x13 : [] ? kthread_worker_fn+0x1a0/0x1a0 : [] ? gs_change+0x13/0x13 Reported-By: Dave Jones Signed-off-by: Ming Lei Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index c18538e..2653e73 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -132,6 +132,35 @@ static struct us_unusual_dev for_dynamic_ids = #undef COMPLIANT_DEV #undef USUAL_DEV +#ifdef CONFIG_LOCKDEP + +static struct lock_class_key us_interface_key[USB_MAXINTERFACES]; + +static void us_set_lock_class(struct mutex *mutex, + struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_host_config *config = udev->actconfig; + int i; + + for (i = 0; i < config->desc.bNumInterfaces; i++) { + if (config->interface[i] == intf) + break; + } + + BUG_ON(i == config->desc.bNumInterfaces); + + lockdep_set_class(mutex, &us_interface_key[i]); +} + +#else + +static void us_set_lock_class(struct mutex *mutex, + struct usb_interface *intf) +{ +} + +#endif #ifdef CONFIG_PM /* Minimal support for suspend and resume */ @@ -895,6 +924,7 @@ int usb_stor_probe1(struct us_data **pus, *pus = us = host_to_us(host); memset(us, 0, sizeof(struct us_data)); mutex_init(&(us->dev_mutex)); + us_set_lock_class(&us->dev_mutex, intf); init_completion(&us->cmnd_ready); init_completion(&(us->notify)); init_waitqueue_head(&us->delay_wait); -- cgit v0.10.2 From bcf398537630bf20b4dbe59ba855b69f404c93cf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 22 Mar 2012 11:00:21 -0400 Subject: USB: don't clear urb->dev in scatter-gather library This patch (as1517b) fixes an error in the USB scatter-gather library. The library code uses urb->dev to determine whether or nor an URB is currently active; the completion handler sets urb->dev to NULL. However the core unlinking routines need to use urb->dev. Since unlinking always racing with completion, the completion handler must not clear urb->dev -- it can lead to invalid memory accesses when a transfer has to be cancelled. This patch fixes the problem by getting rid of the lines that clear urb->dev after urb has been submitted. As a result we may end up trying to unlink an URB that failed in submission or that has already completed, so an extra check is added after each unlink to avoid printing an error message when this happens. The checks are updated in both sg_complete() and sg_cancel(), and the second is updated to match the first (currently it prints out unnecessary warning messages if a device is unplugged while a transfer is in progress). Signed-off-by: Alan Stern Reported-and-tested-by: Illia Zaitsev CC: Ming Lei CC: Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index b3bdfed..aed3e07 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -308,7 +308,8 @@ static void sg_complete(struct urb *urb) retval = usb_unlink_urb(io->urbs [i]); if (retval != -EINPROGRESS && retval != -ENODEV && - retval != -EBUSY) + retval != -EBUSY && + retval != -EIDRM) dev_err(&io->dev->dev, "%s, unlink --> %d\n", __func__, retval); @@ -317,7 +318,6 @@ static void sg_complete(struct urb *urb) } spin_lock(&io->lock); } - urb->dev = NULL; /* on the last completion, signal usb_sg_wait() */ io->bytes += urb->actual_length; @@ -524,7 +524,6 @@ void usb_sg_wait(struct usb_sg_request *io) case -ENXIO: /* hc didn't queue this one */ case -EAGAIN: case -ENOMEM: - io->urbs[i]->dev = NULL; retval = 0; yield(); break; @@ -542,7 +541,6 @@ void usb_sg_wait(struct usb_sg_request *io) /* fail any uncompleted urbs */ default: - io->urbs[i]->dev = NULL; io->urbs[i]->status = retval; dev_dbg(&io->dev->dev, "%s, submit --> %d\n", __func__, retval); @@ -593,7 +591,10 @@ void usb_sg_cancel(struct usb_sg_request *io) if (!io->urbs [i]->dev) continue; retval = usb_unlink_urb(io->urbs [i]); - if (retval != -EINPROGRESS && retval != -EBUSY) + if (retval != -EINPROGRESS + && retval != -ENODEV + && retval != -EBUSY + && retval != -EIDRM) dev_warn(&io->dev->dev, "%s, unlink --> %d\n", __func__, retval); } -- cgit v0.10.2 From da8bfb090c2b30af9f3879443355f7eb1d0fe10a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 28 Mar 2012 16:13:28 -0400 Subject: USB documentation: explain lifetime rules for unlinking URBs This patch (as1534c) updates the documentation for usb_unlink_urb and related functions. It explains that the caller must prevent the URB being unlinked from getting deallocated while the unlink is taking place. Signed-off-by: Alan Stern CC: Ming Lei Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt index 8ffce74..00d2c64 100644 --- a/Documentation/usb/URB.txt +++ b/Documentation/usb/URB.txt @@ -168,6 +168,28 @@ that if the completion handler or anyone else tries to resubmit it they will get a -EPERM error. Thus you can be sure that when usb_kill_urb() returns, the URB is totally idle. +There is a lifetime issue to consider. An URB may complete at any +time, and the completion handler may free the URB. If this happens +while usb_unlink_urb or usb_kill_urb is running, it will cause a +memory-access violation. The driver is responsible for avoiding this, +which often means some sort of lock will be needed to prevent the URB +from being deallocated while it is still in use. + +On the other hand, since usb_unlink_urb may end up calling the +completion handler, the handler must not take any lock that is held +when usb_unlink_urb is invoked. The general solution to this problem +is to increment the URB's reference count while holding the lock, then +drop the lock and call usb_unlink_urb or usb_kill_urb, and then +decrement the URB's reference count. You increment the reference +count by calling + + struct urb *usb_get_urb(struct urb *urb) + +(ignore the return value; it is the same as the argument) and +decrement the reference count by calling usb_free_urb. Of course, +none of this is necessary if there's no danger of the URB being freed +by the completion handler. + 1.7. What about the completion handler? diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 7239a73..cd9b3a2 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -539,6 +539,10 @@ EXPORT_SYMBOL_GPL(usb_submit_urb); * never submitted, or it was unlinked before, or the hardware is already * finished with it), even if the completion handler has not yet run. * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + * * Unlinking and Endpoint Queues: * * [The behaviors and guarantees described below do not apply to virtual @@ -603,6 +607,10 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb); * with error -EPERM. Thus even if the URB's completion handler always * tries to resubmit, it will not succeed and the URB will become idle. * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + * * This routine may not be used in an interrupt context (such as a bottom * half or a completion handler), or when holding a spinlock, or in other * situations where the caller can't schedule(). @@ -640,6 +648,10 @@ EXPORT_SYMBOL_GPL(usb_kill_urb); * with error -EPERM. Thus even if the URB's completion handler always * tries to resubmit, it will not succeed and the URB will become idle. * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + * * This routine may not be used in an interrupt context (such as a bottom * half or a completion handler), or when holding a spinlock, or in other * situations where the caller can't schedule(). -- cgit v0.10.2 From a2457ee691edeffb511dbff9a69008f480192197 Mon Sep 17 00:00:00 2001 From: Michael BRIGHT Date: Thu, 22 Mar 2012 18:42:52 +0100 Subject: USB: remove compile warning on gadget/inode.c Removed unused "restart:" label, which was causing compiler warning. Signed-off-by: Michael BRIGHT Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 8793f32..e58b164 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1574,7 +1574,6 @@ static void destroy_ep_files (struct dev_data *dev) DBG (dev, "%s %d\n", __func__, dev->state); /* dev->state must prevent interference */ -restart: spin_lock_irq (&dev->lock); while (!list_empty(&dev->epfiles)) { struct ep_data *ep; -- cgit v0.10.2 From c3d8b76f61586714cdc5f219ba45592a54caaa55 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 21 Mar 2012 20:15:18 +0100 Subject: serial: PL011: move interrupt clearing Commit 360f748b204275229f8398cb2f9f53955db1503b "serial: PL011: clear pending interrupts" attempts to clear interrupts by writing to a yet-unassigned memory address. This fixes the issue. The breaking patch is marked for stable so should be carried along with the other patch. Cc: Shreshtha Kumar Sahu Cc: Russell King Cc: stable Cc: Nicolas Pitre Reported-by: Viresh Kumar Signed-off-by: Linus Walleij Tested-by: Grant Likely Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 0c65c9e..3d569cd 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1946,10 +1946,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) goto unmap; } - /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); - uap->vendor = vendor; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; @@ -1967,6 +1963,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.line = i; pl011_dma_probe(uap); + /* Ensure interrupts from this UART are masked and cleared */ + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); amba_ports[i] = uap; -- cgit v0.10.2 From 4f32456e5ed4852abc9b555c887dfb3481ea9cab Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:15 +0200 Subject: ALSA: hda - Fix proc output for ADC amp values of CX20549 The CX20549 has only one single input amp on it's input converter widget. Fix printing of values in the codec file in /proc/asound. Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9a9f372..56b4f74 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -851,6 +851,9 @@ struct hda_codec { unsigned int pin_amp_workaround:1; /* pin out-amp takes index * (e.g. Conexant codecs) */ + unsigned int single_adc_amp:1; /* adc in-amp takes no index + * (e.g. CX20549 codec) + */ unsigned int no_sticky_stream:1; /* no sticky-PCM stream assignment */ unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 254ab52..e59e2f0 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -651,9 +651,16 @@ static void print_codec_info(struct snd_info_entry *entry, snd_iprintf(buffer, " Amp-In caps: "); print_amp_caps(buffer, codec, nid, HDA_INPUT); snd_iprintf(buffer, " Amp-In vals: "); - print_amp_vals(buffer, codec, nid, HDA_INPUT, - wid_caps & AC_WCAP_STEREO, - wid_type == AC_WID_PIN ? 1 : conn_len); + if (wid_type == AC_WID_PIN || + (codec->single_adc_amp && + wid_type == AC_WID_AUD_IN)) + print_amp_vals(buffer, codec, nid, HDA_INPUT, + wid_caps & AC_WCAP_STEREO, + 1); + else + print_amp_vals(buffer, codec, nid, HDA_INPUT, + wid_caps & AC_WCAP_STEREO, + conn_len); } if (wid_caps & AC_WCAP_OUT_AMP) { snd_iprintf(buffer, " Amp-Out caps: "); diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index e6eafb1..368617a 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -141,7 +141,6 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; unsigned int pin_eapd_ctrls:1; - unsigned int single_adc_amp:1; unsigned int adc_switching:1; @@ -1111,6 +1110,7 @@ static int patch_cxt5045(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; codec->pin_amp_workaround = 1; + codec->single_adc_amp = 1; spec->multiout.max_channels = 2; spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); @@ -4220,7 +4220,7 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; - if (spec->single_adc_amp) + if (codec->single_adc_amp) idx = 0; return cx_auto_add_volume_idx(codec, label, pfx, cidx, adc_nid, HDA_INPUT, idx); @@ -4275,7 +4275,7 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) if (cidx < 0) continue; input_conn[i] = spec->imux_info[i].adc; - if (!spec->single_adc_amp) + if (!codec->single_adc_amp) input_conn[i] |= cidx << 8; if (i > 0 && input_conn[i] != input_conn[0]) multi_connection = 1; @@ -4470,7 +4470,7 @@ static int patch_conexant_auto(struct hda_codec *codec) switch (codec->vendor_id) { case 0x14f15045: - spec->single_adc_amp = 1; + codec->single_adc_amp = 1; break; case 0x14f15051: add_cx5051_fake_mutes(codec); -- cgit v0.10.2 From 3edbbb9ec5621478dc3c3b1c66ecb7d177b35c20 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:16 +0200 Subject: ALSA: hda - Rename capture sources of CX20549 to match common conventions This includes renaming "Line In" to line, also in the mixer settings. Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 368617a..c0a3a17 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -686,27 +686,27 @@ static const struct hda_channel_mode cxt5045_modes[1] = { static const struct hda_input_mux cxt5045_capture_source = { .num_items = 2, .items = { - { "IntMic", 0x1 }, - { "ExtMic", 0x2 }, + { "Internal Mic", 0x1 }, + { "Mic", 0x2 }, } }; static const struct hda_input_mux cxt5045_capture_source_benq = { .num_items = 5, .items = { - { "IntMic", 0x1 }, - { "ExtMic", 0x2 }, - { "LineIn", 0x3 }, - { "CD", 0x4 }, - { "Mixer", 0x0 }, + { "CD", 0x4 }, + { "Internal Mic", 0x1 }, + { "Mic", 0x2 }, + { "Line", 0x3 }, + { "Mixer", 0x0 }, } }; static const struct hda_input_mux cxt5045_capture_source_hp530 = { .num_items = 2, .items = { - { "ExtMic", 0x1 }, - { "IntMic", 0x2 }, + { "Mic", 0x1 }, + { "Internal Mic", 0x2 }, } }; @@ -826,10 +826,10 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("Line Capture Volume", 0x1a, 0x03, HDA_INPUT), + HDA_CODEC_MUTE("Line Capture Switch", 0x1a, 0x03, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT), -- cgit v0.10.2 From cbf2d28e83d47792bd7af000017042dbc59f5df6 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:17 +0200 Subject: ALSA: hda - fix record volume controls of CX20459 ("Venice") The "input converter" widget of the CX20459 has only one input amplifier, expose that one as "Capture Volume/Capture Switch". The actual record source selection is already exposed through the separately installed input mux. Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c0a3a17..4b51c8f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -797,10 +797,8 @@ static void cxt5045_hp_unsol_event(struct hda_codec *codec, } static const struct snd_kcontrol_new cxt5045_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT), @@ -821,27 +819,18 @@ static const struct snd_kcontrol_new cxt5045_mixers[] = { }; static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Capture Volume", 0x1a, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Line Capture Switch", 0x1a, 0x03, HDA_INPUT), HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT), - {} }; static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { - HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT), @@ -977,16 +966,8 @@ static const struct snd_kcontrol_new cxt5045_test_mixer[] = { .put = conexant_mux_enum_put, }, /* Audio input controls */ - HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), { } /* end */ }; -- cgit v0.10.2 From e6e03daecd2c82437b550ad1a62052c22fdb2b5b Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:18 +0200 Subject: ALSA: hda - Remove CD control from model=benq for CX20549 The ID used for detection of the BenQ R55E actually identifies the Quanta TW3 ODM design, which is also used for the Gigabyte W551 laptop series. Schematics on the internet clearly indicate that the "Port C" (analog input connected to record source #4 and mixer input #4) is unconnected. Playing an audio CD through analog playback (using cdplay from cdtools) produces no sound, even with the mixer input labelled "CD" enabled, and the volume control in the CD drive set to maximum. This indicates the connection is really not present. Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4b51c8f..4b36548 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -692,9 +692,8 @@ static const struct hda_input_mux cxt5045_capture_source = { }; static const struct hda_input_mux cxt5045_capture_source_benq = { - .num_items = 5, + .num_items = 4, .items = { - { "CD", 0x4 }, { "Internal Mic", 0x1 }, { "Mic", 0x2 }, { "Line", 0x3 }, @@ -819,9 +818,6 @@ static const struct snd_kcontrol_new cxt5045_mixers[] = { }; static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { - HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x3, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x3, HDA_INPUT), -- cgit v0.10.2 From 51969d62c3b26e887dae734de421b320a296ac58 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:19 +0200 Subject: ALSA: hda - CX20549 doesn't need pin_amp_workaround. CX20549 (ctx5045) doesn't accept data on index 1 for output pins, as shown in the following hda-var transaction: $ hda-verb /dev/snd/hwC0D0 0x10 set_amp_gain 0xb126 nid = 0x10, verb = 0x300, param = 0xb126 value = 0x0 $ hda-verb /dev/snd/hwC0D0 0x10 get_amp_gain 0x8001 nid = 0x10, verb = 0xb00, param = 0x8001 value = 0x0 Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4b36548..84337e6 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1086,7 +1086,6 @@ static int patch_cxt5045(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; - codec->pin_amp_workaround = 1; codec->single_adc_amp = 1; spec->multiout.max_channels = 2; @@ -4443,7 +4442,6 @@ static int patch_conexant_auto(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; - codec->pin_amp_workaround = 1; switch (codec->vendor_id) { case 0x14f15045: @@ -4451,7 +4449,10 @@ static int patch_conexant_auto(struct hda_codec *codec) break; case 0x14f15051: add_cx5051_fake_mutes(codec); + codec->pin_amp_workaround = 1; break; + default: + codec->pin_amp_workaround = 1; } apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl); -- cgit v0.10.2 From 250f32747e62cb415b85083e247184188f24e566 Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Fri, 6 Apr 2012 15:34:20 +0200 Subject: ALSA: hda - clean up CX20549 test mixer setup name pins consistently (MIC1/LINE1/HP-OUT/CD) on all controls affecting those pins. remove duplicate SET_AMP_GAIN_MUTE to 0x17/index 0 and 0x17/index 1 really select MIC1, not Mixer out for recording "Mixer out" for recording is not a "pin", adjust comment Signed-off-by: Michael Karcher Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 84337e6..3848711 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -930,10 +930,10 @@ static const struct snd_kcontrol_new cxt5045_test_mixer[] = { /* Output controls */ HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Node 11 Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Node 11 Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Node 12 Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Node 12 Playback Switch", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("HP-OUT Playback Volume", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("HP-OUT Playback Switch", 0x11, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("LINE1 Playback Volume", 0x12, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("LINE1 Playback Switch", 0x12, 0x0, HDA_OUTPUT), /* Modes for retasking pin widgets */ CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), @@ -944,16 +944,16 @@ static const struct snd_kcontrol_new cxt5045_test_mixer[] = { /* Loopback mixer controls */ - HDA_CODEC_VOLUME("Mixer-1 Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-1 Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-2 Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-2 Switch", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-3 Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-3 Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-4 Volume", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-4 Switch", 0x17, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Mixer-5 Volume", 0x17, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mixer-5 Switch", 0x17, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("PCM Volume", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("PCM Switch", 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("MIC1 pin Volume", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("MIC1 pin Switch", 0x17, 0x1, HDA_INPUT), + HDA_CODEC_VOLUME("LINE1 pin Volume", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_MUTE("LINE1 pin Switch", 0x17, 0x2, HDA_INPUT), + HDA_CODEC_VOLUME("HP-OUT pin Volume", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_MUTE("HP-OUT pin Switch", 0x17, 0x3, HDA_INPUT), + HDA_CODEC_VOLUME("CD pin Volume", 0x17, 0x4, HDA_INPUT), + HDA_CODEC_MUTE("CD pin Switch", 0x17, 0x4, HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Source", @@ -985,10 +985,6 @@ static const struct hda_verb cxt5045_test_init_verbs[] = { {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, - /* Start with output sum widgets muted and their output gains at min */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Unmute retasking pin widget output buffers since the default * state appears to be output. As the pin mode is changed by the * user the pin mode control will take care of enabling the pin's @@ -1003,11 +999,11 @@ static const struct hda_verb cxt5045_test_init_verbs[] = { /* Set ADC connection select to match default mixer setting (mic1 * pin) */ - {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x17, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Mute all inputs to mixer widget (even unconnected ones) */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ -- cgit v0.10.2 From ef798d0207e02e05bfabc7ba96e8a6f2cc07066e Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Wed, 21 Mar 2012 23:36:50 +0100 Subject: kyrofb: fix on x86_64 kyrofb is completely broken on x86_64 because the registers are defined as unsigned long. Change them to u32 to make the driver work. Tested with Hercules 3D Prophet 4000XT. Signed-off-by: Ondrej Zary Acked-by: Paul Mundt Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/kyro/STG4000Reg.h b/drivers/video/kyro/STG4000Reg.h index 5d62698..50f4670 100644 --- a/drivers/video/kyro/STG4000Reg.h +++ b/drivers/video/kyro/STG4000Reg.h @@ -73,210 +73,210 @@ typedef enum _OVRL_PIX_FORMAT { /* Register Table */ typedef struct { /* 0h */ - volatile unsigned long Thread0Enable; /* 0x0000 */ - volatile unsigned long Thread1Enable; /* 0x0004 */ - volatile unsigned long Thread0Recover; /* 0x0008 */ - volatile unsigned long Thread1Recover; /* 0x000C */ - volatile unsigned long Thread0Step; /* 0x0010 */ - volatile unsigned long Thread1Step; /* 0x0014 */ - volatile unsigned long VideoInStatus; /* 0x0018 */ - volatile unsigned long Core2InSignStart; /* 0x001C */ - volatile unsigned long Core1ResetVector; /* 0x0020 */ - volatile unsigned long Core1ROMOffset; /* 0x0024 */ - volatile unsigned long Core1ArbiterPriority; /* 0x0028 */ - volatile unsigned long VideoInControl; /* 0x002C */ - volatile unsigned long VideoInReg0CtrlA; /* 0x0030 */ - volatile unsigned long VideoInReg0CtrlB; /* 0x0034 */ - volatile unsigned long VideoInReg1CtrlA; /* 0x0038 */ - volatile unsigned long VideoInReg1CtrlB; /* 0x003C */ - volatile unsigned long Thread0Kicker; /* 0x0040 */ - volatile unsigned long Core2InputSign; /* 0x0044 */ - volatile unsigned long Thread0ProgCtr; /* 0x0048 */ - volatile unsigned long Thread1ProgCtr; /* 0x004C */ - volatile unsigned long Thread1Kicker; /* 0x0050 */ - volatile unsigned long GPRegister1; /* 0x0054 */ - volatile unsigned long GPRegister2; /* 0x0058 */ - volatile unsigned long GPRegister3; /* 0x005C */ - volatile unsigned long GPRegister4; /* 0x0060 */ - volatile unsigned long SerialIntA; /* 0x0064 */ - - volatile unsigned long Fill0[6]; /* GAP 0x0068 - 0x007C */ - - volatile unsigned long SoftwareReset; /* 0x0080 */ - volatile unsigned long SerialIntB; /* 0x0084 */ - - volatile unsigned long Fill1[37]; /* GAP 0x0088 - 0x011C */ - - volatile unsigned long ROMELQV; /* 0x011C */ - volatile unsigned long WLWH; /* 0x0120 */ - volatile unsigned long ROMELWL; /* 0x0124 */ - - volatile unsigned long dwFill_1; /* GAP 0x0128 */ - - volatile unsigned long IntStatus; /* 0x012C */ - volatile unsigned long IntMask; /* 0x0130 */ - volatile unsigned long IntClear; /* 0x0134 */ - - volatile unsigned long Fill2[6]; /* GAP 0x0138 - 0x014C */ - - volatile unsigned long ROMGPIOA; /* 0x0150 */ - volatile unsigned long ROMGPIOB; /* 0x0154 */ - volatile unsigned long ROMGPIOC; /* 0x0158 */ - volatile unsigned long ROMGPIOD; /* 0x015C */ - - volatile unsigned long Fill3[2]; /* GAP 0x0160 - 0x0168 */ - - volatile unsigned long AGPIntID; /* 0x0168 */ - volatile unsigned long AGPIntClassCode; /* 0x016C */ - volatile unsigned long AGPIntBIST; /* 0x0170 */ - volatile unsigned long AGPIntSSID; /* 0x0174 */ - volatile unsigned long AGPIntPMCSR; /* 0x0178 */ - volatile unsigned long VGAFrameBufBase; /* 0x017C */ - volatile unsigned long VGANotify; /* 0x0180 */ - volatile unsigned long DACPLLMode; /* 0x0184 */ - volatile unsigned long Core1VideoClockDiv; /* 0x0188 */ - volatile unsigned long AGPIntStat; /* 0x018C */ + volatile u32 Thread0Enable; /* 0x0000 */ + volatile u32 Thread1Enable; /* 0x0004 */ + volatile u32 Thread0Recover; /* 0x0008 */ + volatile u32 Thread1Recover; /* 0x000C */ + volatile u32 Thread0Step; /* 0x0010 */ + volatile u32 Thread1Step; /* 0x0014 */ + volatile u32 VideoInStatus; /* 0x0018 */ + volatile u32 Core2InSignStart; /* 0x001C */ + volatile u32 Core1ResetVector; /* 0x0020 */ + volatile u32 Core1ROMOffset; /* 0x0024 */ + volatile u32 Core1ArbiterPriority; /* 0x0028 */ + volatile u32 VideoInControl; /* 0x002C */ + volatile u32 VideoInReg0CtrlA; /* 0x0030 */ + volatile u32 VideoInReg0CtrlB; /* 0x0034 */ + volatile u32 VideoInReg1CtrlA; /* 0x0038 */ + volatile u32 VideoInReg1CtrlB; /* 0x003C */ + volatile u32 Thread0Kicker; /* 0x0040 */ + volatile u32 Core2InputSign; /* 0x0044 */ + volatile u32 Thread0ProgCtr; /* 0x0048 */ + volatile u32 Thread1ProgCtr; /* 0x004C */ + volatile u32 Thread1Kicker; /* 0x0050 */ + volatile u32 GPRegister1; /* 0x0054 */ + volatile u32 GPRegister2; /* 0x0058 */ + volatile u32 GPRegister3; /* 0x005C */ + volatile u32 GPRegister4; /* 0x0060 */ + volatile u32 SerialIntA; /* 0x0064 */ + + volatile u32 Fill0[6]; /* GAP 0x0068 - 0x007C */ + + volatile u32 SoftwareReset; /* 0x0080 */ + volatile u32 SerialIntB; /* 0x0084 */ + + volatile u32 Fill1[37]; /* GAP 0x0088 - 0x011C */ + + volatile u32 ROMELQV; /* 0x011C */ + volatile u32 WLWH; /* 0x0120 */ + volatile u32 ROMELWL; /* 0x0124 */ + + volatile u32 dwFill_1; /* GAP 0x0128 */ + + volatile u32 IntStatus; /* 0x012C */ + volatile u32 IntMask; /* 0x0130 */ + volatile u32 IntClear; /* 0x0134 */ + + volatile u32 Fill2[6]; /* GAP 0x0138 - 0x014C */ + + volatile u32 ROMGPIOA; /* 0x0150 */ + volatile u32 ROMGPIOB; /* 0x0154 */ + volatile u32 ROMGPIOC; /* 0x0158 */ + volatile u32 ROMGPIOD; /* 0x015C */ + + volatile u32 Fill3[2]; /* GAP 0x0160 - 0x0168 */ + + volatile u32 AGPIntID; /* 0x0168 */ + volatile u32 AGPIntClassCode; /* 0x016C */ + volatile u32 AGPIntBIST; /* 0x0170 */ + volatile u32 AGPIntSSID; /* 0x0174 */ + volatile u32 AGPIntPMCSR; /* 0x0178 */ + volatile u32 VGAFrameBufBase; /* 0x017C */ + volatile u32 VGANotify; /* 0x0180 */ + volatile u32 DACPLLMode; /* 0x0184 */ + volatile u32 Core1VideoClockDiv; /* 0x0188 */ + volatile u32 AGPIntStat; /* 0x018C */ /* - volatile unsigned long Fill4[0x0400/4 - 0x0190/4]; //GAP 0x0190 - 0x0400 - volatile unsigned long Fill5[0x05FC/4 - 0x0400/4]; //GAP 0x0400 - 0x05FC Fog Table - volatile unsigned long Fill6[0x0604/4 - 0x0600/4]; //GAP 0x0600 - 0x0604 - volatile unsigned long Fill7[0x0680/4 - 0x0608/4]; //GAP 0x0608 - 0x0680 - volatile unsigned long Fill8[0x07FC/4 - 0x0684/4]; //GAP 0x0684 - 0x07FC + volatile u32 Fill4[0x0400/4 - 0x0190/4]; //GAP 0x0190 - 0x0400 + volatile u32 Fill5[0x05FC/4 - 0x0400/4]; //GAP 0x0400 - 0x05FC Fog Table + volatile u32 Fill6[0x0604/4 - 0x0600/4]; //GAP 0x0600 - 0x0604 + volatile u32 Fill7[0x0680/4 - 0x0608/4]; //GAP 0x0608 - 0x0680 + volatile u32 Fill8[0x07FC/4 - 0x0684/4]; //GAP 0x0684 - 0x07FC */ - volatile unsigned long Fill4[412]; /* 0x0190 - 0x07FC */ - - volatile unsigned long TACtrlStreamBase; /* 0x0800 */ - volatile unsigned long TAObjDataBase; /* 0x0804 */ - volatile unsigned long TAPtrDataBase; /* 0x0808 */ - volatile unsigned long TARegionDataBase; /* 0x080C */ - volatile unsigned long TATailPtrBase; /* 0x0810 */ - volatile unsigned long TAPtrRegionSize; /* 0x0814 */ - volatile unsigned long TAConfiguration; /* 0x0818 */ - volatile unsigned long TAObjDataStartAddr; /* 0x081C */ - volatile unsigned long TAObjDataEndAddr; /* 0x0820 */ - volatile unsigned long TAXScreenClip; /* 0x0824 */ - volatile unsigned long TAYScreenClip; /* 0x0828 */ - volatile unsigned long TARHWClamp; /* 0x082C */ - volatile unsigned long TARHWCompare; /* 0x0830 */ - volatile unsigned long TAStart; /* 0x0834 */ - volatile unsigned long TAObjReStart; /* 0x0838 */ - volatile unsigned long TAPtrReStart; /* 0x083C */ - volatile unsigned long TAStatus1; /* 0x0840 */ - volatile unsigned long TAStatus2; /* 0x0844 */ - volatile unsigned long TAIntStatus; /* 0x0848 */ - volatile unsigned long TAIntMask; /* 0x084C */ - - volatile unsigned long Fill5[235]; /* GAP 0x0850 - 0x0BF8 */ - - volatile unsigned long TextureAddrThresh; /* 0x0BFC */ - volatile unsigned long Core1Translation; /* 0x0C00 */ - volatile unsigned long TextureAddrReMap; /* 0x0C04 */ - volatile unsigned long RenderOutAGPRemap; /* 0x0C08 */ - volatile unsigned long _3DRegionReadTrans; /* 0x0C0C */ - volatile unsigned long _3DPtrReadTrans; /* 0x0C10 */ - volatile unsigned long _3DParamReadTrans; /* 0x0C14 */ - volatile unsigned long _3DRegionReadThresh; /* 0x0C18 */ - volatile unsigned long _3DPtrReadThresh; /* 0x0C1C */ - volatile unsigned long _3DParamReadThresh; /* 0x0C20 */ - volatile unsigned long _3DRegionReadAGPRemap; /* 0x0C24 */ - volatile unsigned long _3DPtrReadAGPRemap; /* 0x0C28 */ - volatile unsigned long _3DParamReadAGPRemap; /* 0x0C2C */ - volatile unsigned long ZBufferAGPRemap; /* 0x0C30 */ - volatile unsigned long TAIndexAGPRemap; /* 0x0C34 */ - volatile unsigned long TAVertexAGPRemap; /* 0x0C38 */ - volatile unsigned long TAUVAddrTrans; /* 0x0C3C */ - volatile unsigned long TATailPtrCacheTrans; /* 0x0C40 */ - volatile unsigned long TAParamWriteTrans; /* 0x0C44 */ - volatile unsigned long TAPtrWriteTrans; /* 0x0C48 */ - volatile unsigned long TAParamWriteThresh; /* 0x0C4C */ - volatile unsigned long TAPtrWriteThresh; /* 0x0C50 */ - volatile unsigned long TATailPtrCacheAGPRe; /* 0x0C54 */ - volatile unsigned long TAParamWriteAGPRe; /* 0x0C58 */ - volatile unsigned long TAPtrWriteAGPRe; /* 0x0C5C */ - volatile unsigned long SDRAMArbiterConf; /* 0x0C60 */ - volatile unsigned long SDRAMConf0; /* 0x0C64 */ - volatile unsigned long SDRAMConf1; /* 0x0C68 */ - volatile unsigned long SDRAMConf2; /* 0x0C6C */ - volatile unsigned long SDRAMRefresh; /* 0x0C70 */ - volatile unsigned long SDRAMPowerStat; /* 0x0C74 */ - - volatile unsigned long Fill6[2]; /* GAP 0x0C78 - 0x0C7C */ - - volatile unsigned long RAMBistData; /* 0x0C80 */ - volatile unsigned long RAMBistCtrl; /* 0x0C84 */ - volatile unsigned long FIFOBistKey; /* 0x0C88 */ - volatile unsigned long RAMBistResult; /* 0x0C8C */ - volatile unsigned long FIFOBistResult; /* 0x0C90 */ + volatile u32 Fill4[412]; /* 0x0190 - 0x07FC */ + + volatile u32 TACtrlStreamBase; /* 0x0800 */ + volatile u32 TAObjDataBase; /* 0x0804 */ + volatile u32 TAPtrDataBase; /* 0x0808 */ + volatile u32 TARegionDataBase; /* 0x080C */ + volatile u32 TATailPtrBase; /* 0x0810 */ + volatile u32 TAPtrRegionSize; /* 0x0814 */ + volatile u32 TAConfiguration; /* 0x0818 */ + volatile u32 TAObjDataStartAddr; /* 0x081C */ + volatile u32 TAObjDataEndAddr; /* 0x0820 */ + volatile u32 TAXScreenClip; /* 0x0824 */ + volatile u32 TAYScreenClip; /* 0x0828 */ + volatile u32 TARHWClamp; /* 0x082C */ + volatile u32 TARHWCompare; /* 0x0830 */ + volatile u32 TAStart; /* 0x0834 */ + volatile u32 TAObjReStart; /* 0x0838 */ + volatile u32 TAPtrReStart; /* 0x083C */ + volatile u32 TAStatus1; /* 0x0840 */ + volatile u32 TAStatus2; /* 0x0844 */ + volatile u32 TAIntStatus; /* 0x0848 */ + volatile u32 TAIntMask; /* 0x084C */ + + volatile u32 Fill5[235]; /* GAP 0x0850 - 0x0BF8 */ + + volatile u32 TextureAddrThresh; /* 0x0BFC */ + volatile u32 Core1Translation; /* 0x0C00 */ + volatile u32 TextureAddrReMap; /* 0x0C04 */ + volatile u32 RenderOutAGPRemap; /* 0x0C08 */ + volatile u32 _3DRegionReadTrans; /* 0x0C0C */ + volatile u32 _3DPtrReadTrans; /* 0x0C10 */ + volatile u32 _3DParamReadTrans; /* 0x0C14 */ + volatile u32 _3DRegionReadThresh; /* 0x0C18 */ + volatile u32 _3DPtrReadThresh; /* 0x0C1C */ + volatile u32 _3DParamReadThresh; /* 0x0C20 */ + volatile u32 _3DRegionReadAGPRemap; /* 0x0C24 */ + volatile u32 _3DPtrReadAGPRemap; /* 0x0C28 */ + volatile u32 _3DParamReadAGPRemap; /* 0x0C2C */ + volatile u32 ZBufferAGPRemap; /* 0x0C30 */ + volatile u32 TAIndexAGPRemap; /* 0x0C34 */ + volatile u32 TAVertexAGPRemap; /* 0x0C38 */ + volatile u32 TAUVAddrTrans; /* 0x0C3C */ + volatile u32 TATailPtrCacheTrans; /* 0x0C40 */ + volatile u32 TAParamWriteTrans; /* 0x0C44 */ + volatile u32 TAPtrWriteTrans; /* 0x0C48 */ + volatile u32 TAParamWriteThresh; /* 0x0C4C */ + volatile u32 TAPtrWriteThresh; /* 0x0C50 */ + volatile u32 TATailPtrCacheAGPRe; /* 0x0C54 */ + volatile u32 TAParamWriteAGPRe; /* 0x0C58 */ + volatile u32 TAPtrWriteAGPRe; /* 0x0C5C */ + volatile u32 SDRAMArbiterConf; /* 0x0C60 */ + volatile u32 SDRAMConf0; /* 0x0C64 */ + volatile u32 SDRAMConf1; /* 0x0C68 */ + volatile u32 SDRAMConf2; /* 0x0C6C */ + volatile u32 SDRAMRefresh; /* 0x0C70 */ + volatile u32 SDRAMPowerStat; /* 0x0C74 */ + + volatile u32 Fill6[2]; /* GAP 0x0C78 - 0x0C7C */ + + volatile u32 RAMBistData; /* 0x0C80 */ + volatile u32 RAMBistCtrl; /* 0x0C84 */ + volatile u32 FIFOBistKey; /* 0x0C88 */ + volatile u32 RAMBistResult; /* 0x0C8C */ + volatile u32 FIFOBistResult; /* 0x0C90 */ /* - volatile unsigned long Fill11[0x0CBC/4 - 0x0C94/4]; //GAP 0x0C94 - 0x0CBC - volatile unsigned long Fill12[0x0CD0/4 - 0x0CC0/4]; //GAP 0x0CC0 - 0x0CD0 3DRegisters + volatile u32 Fill11[0x0CBC/4 - 0x0C94/4]; //GAP 0x0C94 - 0x0CBC + volatile u32 Fill12[0x0CD0/4 - 0x0CC0/4]; //GAP 0x0CC0 - 0x0CD0 3DRegisters */ - volatile unsigned long Fill7[16]; /* 0x0c94 - 0x0cd0 */ + volatile u32 Fill7[16]; /* 0x0c94 - 0x0cd0 */ - volatile unsigned long SDRAMAddrSign; /* 0x0CD4 */ - volatile unsigned long SDRAMDataSign; /* 0x0CD8 */ - volatile unsigned long SDRAMSignConf; /* 0x0CDC */ + volatile u32 SDRAMAddrSign; /* 0x0CD4 */ + volatile u32 SDRAMDataSign; /* 0x0CD8 */ + volatile u32 SDRAMSignConf; /* 0x0CDC */ /* DWFILL; //GAP 0x0CE0 */ - volatile unsigned long dwFill_2; - - volatile unsigned long ISPSignature; /* 0x0CE4 */ - - volatile unsigned long Fill8[454]; /*GAP 0x0CE8 - 0x13FC */ - - volatile unsigned long DACPrimAddress; /* 0x1400 */ - volatile unsigned long DACPrimSize; /* 0x1404 */ - volatile unsigned long DACCursorAddr; /* 0x1408 */ - volatile unsigned long DACCursorCtrl; /* 0x140C */ - volatile unsigned long DACOverlayAddr; /* 0x1410 */ - volatile unsigned long DACOverlayUAddr; /* 0x1414 */ - volatile unsigned long DACOverlayVAddr; /* 0x1418 */ - volatile unsigned long DACOverlaySize; /* 0x141C */ - volatile unsigned long DACOverlayVtDec; /* 0x1420 */ - - volatile unsigned long Fill9[9]; /* GAP 0x1424 - 0x1444 */ - - volatile unsigned long DACVerticalScal; /* 0x1448 */ - volatile unsigned long DACPixelFormat; /* 0x144C */ - volatile unsigned long DACHorizontalScal; /* 0x1450 */ - volatile unsigned long DACVidWinStart; /* 0x1454 */ - volatile unsigned long DACVidWinEnd; /* 0x1458 */ - volatile unsigned long DACBlendCtrl; /* 0x145C */ - volatile unsigned long DACHorTim1; /* 0x1460 */ - volatile unsigned long DACHorTim2; /* 0x1464 */ - volatile unsigned long DACHorTim3; /* 0x1468 */ - volatile unsigned long DACVerTim1; /* 0x146C */ - volatile unsigned long DACVerTim2; /* 0x1470 */ - volatile unsigned long DACVerTim3; /* 0x1474 */ - volatile unsigned long DACBorderColor; /* 0x1478 */ - volatile unsigned long DACSyncCtrl; /* 0x147C */ - volatile unsigned long DACStreamCtrl; /* 0x1480 */ - volatile unsigned long DACLUTAddress; /* 0x1484 */ - volatile unsigned long DACLUTData; /* 0x1488 */ - volatile unsigned long DACBurstCtrl; /* 0x148C */ - volatile unsigned long DACCrcTrigger; /* 0x1490 */ - volatile unsigned long DACCrcDone; /* 0x1494 */ - volatile unsigned long DACCrcResult1; /* 0x1498 */ - volatile unsigned long DACCrcResult2; /* 0x149C */ - volatile unsigned long DACLinecount; /* 0x14A0 */ - - volatile unsigned long Fill10[151]; /*GAP 0x14A4 - 0x16FC */ - - volatile unsigned long DigVidPortCtrl; /* 0x1700 */ - volatile unsigned long DigVidPortStat; /* 0x1704 */ + volatile u32 dwFill_2; + + volatile u32 ISPSignature; /* 0x0CE4 */ + + volatile u32 Fill8[454]; /*GAP 0x0CE8 - 0x13FC */ + + volatile u32 DACPrimAddress; /* 0x1400 */ + volatile u32 DACPrimSize; /* 0x1404 */ + volatile u32 DACCursorAddr; /* 0x1408 */ + volatile u32 DACCursorCtrl; /* 0x140C */ + volatile u32 DACOverlayAddr; /* 0x1410 */ + volatile u32 DACOverlayUAddr; /* 0x1414 */ + volatile u32 DACOverlayVAddr; /* 0x1418 */ + volatile u32 DACOverlaySize; /* 0x141C */ + volatile u32 DACOverlayVtDec; /* 0x1420 */ + + volatile u32 Fill9[9]; /* GAP 0x1424 - 0x1444 */ + + volatile u32 DACVerticalScal; /* 0x1448 */ + volatile u32 DACPixelFormat; /* 0x144C */ + volatile u32 DACHorizontalScal; /* 0x1450 */ + volatile u32 DACVidWinStart; /* 0x1454 */ + volatile u32 DACVidWinEnd; /* 0x1458 */ + volatile u32 DACBlendCtrl; /* 0x145C */ + volatile u32 DACHorTim1; /* 0x1460 */ + volatile u32 DACHorTim2; /* 0x1464 */ + volatile u32 DACHorTim3; /* 0x1468 */ + volatile u32 DACVerTim1; /* 0x146C */ + volatile u32 DACVerTim2; /* 0x1470 */ + volatile u32 DACVerTim3; /* 0x1474 */ + volatile u32 DACBorderColor; /* 0x1478 */ + volatile u32 DACSyncCtrl; /* 0x147C */ + volatile u32 DACStreamCtrl; /* 0x1480 */ + volatile u32 DACLUTAddress; /* 0x1484 */ + volatile u32 DACLUTData; /* 0x1488 */ + volatile u32 DACBurstCtrl; /* 0x148C */ + volatile u32 DACCrcTrigger; /* 0x1490 */ + volatile u32 DACCrcDone; /* 0x1494 */ + volatile u32 DACCrcResult1; /* 0x1498 */ + volatile u32 DACCrcResult2; /* 0x149C */ + volatile u32 DACLinecount; /* 0x14A0 */ + + volatile u32 Fill10[151]; /*GAP 0x14A4 - 0x16FC */ + + volatile u32 DigVidPortCtrl; /* 0x1700 */ + volatile u32 DigVidPortStat; /* 0x1704 */ /* - volatile unsigned long Fill11[0x1FFC/4 - 0x1708/4]; //GAP 0x1708 - 0x1FFC - volatile unsigned long Fill17[0x3000/4 - 0x2FFC/4]; //GAP 0x2000 - 0x2FFC ALUT + volatile u32 Fill11[0x1FFC/4 - 0x1708/4]; //GAP 0x1708 - 0x1FFC + volatile u32 Fill17[0x3000/4 - 0x2FFC/4]; //GAP 0x2000 - 0x2FFC ALUT */ - volatile unsigned long Fill11[1598]; + volatile u32 Fill11[1598]; /* DWFILL; //GAP 0x3000 ALUT 256MB offset */ - volatile unsigned long Fill_3; + volatile u32 Fill_3; } STG4000REG; -- cgit v0.10.2 From 93019734555f8df32239c5922fe2b770c0a08eaa Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 24 Mar 2012 11:38:02 +0100 Subject: fbdev: fix au1*fb builds Commit 1c16697bf9d5b206cb0d2b905a54de5e077296be ("drivers/video/au*fb.c: use devm_ functions) introduced 2 build failures in the au1100fb and au1200fb drivers, fix them. Signed-off-by: Manuel Lauss Signed-off-by: Florian Tobias Schandinat diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c index befcbd8..ffbce45 100644 --- a/drivers/video/au1100fb.c +++ b/drivers/video/au1100fb.c @@ -499,7 +499,8 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) au1100fb_fix.mmio_start = regs_res->start; au1100fb_fix.mmio_len = resource_size(regs_res); - if (!devm_request_mem_region(au1100fb_fix.mmio_start, + if (!devm_request_mem_region(&dev->dev, + au1100fb_fix.mmio_start, au1100fb_fix.mmio_len, DRIVER_NAME)) { print_err("fail to lock memory region at 0x%08lx", @@ -516,7 +517,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev) fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres * (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS; - fbdev->fb_mem = dmam_alloc_coherent(&dev->dev, &dev->dev, + fbdev->fb_mem = dmam_alloc_coherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), &fbdev->fb_phys, GFP_KERNEL); if (!fbdev->fb_mem) { diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 3e9a773..7ca79f0 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1724,7 +1724,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) /* Allocate the framebuffer to the maximum screen size */ fbdev->fb_len = (win->w[plane].xres * win->w[plane].yres * bpp) / 8; - fbdev->fb_mem = dmam_alloc_noncoherent(&dev->dev, &dev->dev, + fbdev->fb_mem = dmam_alloc_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), &fbdev->fb_phys, GFP_KERNEL); if (!fbdev->fb_mem) { -- cgit v0.10.2 From 70499329202a68f7485415e009e04213672f6811 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Thu, 5 Apr 2012 15:48:25 -0700 Subject: ARM: S5PV210: fix unused LDO supply field from wm8994_pdata According to commit 719a4240("mfd: Remove unused LDO supply field from WM8994 pdata"), the LDO supply field should be removed from the initializer. Cc: Mark Brown Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c index a9ea64e..48d018f 100644 --- a/arch/arm/mach-s5pv210/mach-aquila.c +++ b/arch/arm/mach-s5pv210/mach-aquila.c @@ -484,8 +484,8 @@ static struct wm8994_pdata wm8994_platform_data = { .gpio_defaults[8] = 0x0100, .gpio_defaults[9] = 0x0100, .gpio_defaults[10] = 0x0100, - .ldo[0] = { S5PV210_MP03(6), NULL, &wm8994_ldo1_data }, /* XM0FRNB_2 */ - .ldo[1] = { 0, NULL, &wm8994_ldo2_data }, + .ldo[0] = { S5PV210_MP03(6), &wm8994_ldo1_data }, /* XM0FRNB_2 */ + .ldo[1] = { 0, &wm8994_ldo2_data }, }; /* GPIO I2C PMIC */ diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c index 2cf5ed7..a8933de 100644 --- a/arch/arm/mach-s5pv210/mach-goni.c +++ b/arch/arm/mach-s5pv210/mach-goni.c @@ -674,8 +674,8 @@ static struct wm8994_pdata wm8994_platform_data = { .gpio_defaults[8] = 0x0100, .gpio_defaults[9] = 0x0100, .gpio_defaults[10] = 0x0100, - .ldo[0] = { S5PV210_MP03(6), NULL, &wm8994_ldo1_data }, /* XM0FRNB_2 */ - .ldo[1] = { 0, NULL, &wm8994_ldo2_data }, + .ldo[0] = { S5PV210_MP03(6), &wm8994_ldo1_data }, /* XM0FRNB_2 */ + .ldo[1] = { 0, &wm8994_ldo2_data }, }; /* GPIO I2C PMIC */ -- cgit v0.10.2 From 0d923490f7dd5d96bc894a09a178117442b8795b Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 5 Apr 2012 16:08:25 -0700 Subject: ARM: EXYNOS: Add missing definition for IRQ_I2S0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes following build error when sound support is selected on EXYNOS4 platform. sound/soc/samsung/idma.c: In function ‘idma_close’: sound/soc/samsung/idma.c:327:11: error: ‘IRQ_I2S0’ undeclared (first use in this function) Signed-off-by: Tushar Behera Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index 9bee853..591e785 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h @@ -212,6 +212,8 @@ #define IRQ_MFC EXYNOS4_IRQ_MFC #define IRQ_SDO EXYNOS4_IRQ_SDO +#define IRQ_I2S0 EXYNOS4_IRQ_I2S0 + #define IRQ_ADC EXYNOS4_IRQ_ADC0 #define IRQ_TC EXYNOS4_IRQ_PEN0 -- cgit v0.10.2 From 32db797f10d465365a52d269c0b313b6b702e711 Mon Sep 17 00:00:00 2001 From: Jonghwan Choi Date: Thu, 5 Apr 2012 22:31:31 -0700 Subject: ARM: EXYNOS: Fix compile error in exynos5250-cpufreq.c This patch is omitted in v2 patch of Jaecheol Lee. drivers/cpufreq/exynos5250-cpufreq.c: In function 'set_clkdiv': drivers/cpufreq/exynos5250-cpufreq.c:144: error: 'EXYNOS5_CLKDIV_STATCPU0' undeclared (first use in this function) drivers/cpufreq/exynos5250-cpufreq.c:144: error: (Each undeclared identifier is reported only once drivers/cpufreq/exynos5250-cpufreq.c:144: error: for each function it appears in.) drivers/cpufreq/exynos5250-cpufreq.c:150: error: 'EXYNOS5_CLKDIV_CPU1' undeclared (first use in this function) drivers/cpufreq/exynos5250-cpufreq.c:152: error: 'EXYNOS5_CLKDIV_STATCPU1' undeclared (first use in this function) drivers/cpufreq/exynos5250-cpufreq.c: In function 'set_apll': drivers/cpufreq/exynos5250-cpufreq.c:166: error: 'EXYNOS5_CLKMUX_STATCPU' undeclared (first use in this function) drivers/cpufreq/exynos5250-cpufreq.c:173: error: 'EXYNOS5_APLL_LOCK' undeclared (first use in this function) drivers/cpufreq/exynos5250-cpufreq.c: In function 'exynos5250_cpufreq_init': drivers/cpufreq/exynos5250-cpufreq.c:312: error: 'EXYNOS5_CLKDIV_CPU1' undeclared (first use in this function) Cc: Jaecheol Lee Signed-off-by: Jonghwan Choi Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h index e141c1f..d9578a5 100644 --- a/arch/arm/mach-exynos/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos/include/mach/regs-clock.h @@ -255,9 +255,15 @@ /* For EXYNOS5250 */ +#define EXYNOS5_APLL_LOCK EXYNOS_CLKREG(0x00000) #define EXYNOS5_APLL_CON0 EXYNOS_CLKREG(0x00100) #define EXYNOS5_CLKSRC_CPU EXYNOS_CLKREG(0x00200) +#define EXYNOS5_CLKMUX_STATCPU EXYNOS_CLKREG(0x00400) #define EXYNOS5_CLKDIV_CPU0 EXYNOS_CLKREG(0x00500) +#define EXYNOS5_CLKDIV_CPU1 EXYNOS_CLKREG(0x00504) +#define EXYNOS5_CLKDIV_STATCPU0 EXYNOS_CLKREG(0x00600) +#define EXYNOS5_CLKDIV_STATCPU1 EXYNOS_CLKREG(0x00604) + #define EXYNOS5_MPLL_CON0 EXYNOS_CLKREG(0x04100) #define EXYNOS5_CLKSRC_CORE1 EXYNOS_CLKREG(0x04204) -- cgit v0.10.2 From c65390f4dd49755863f6d772ec538ee4757c08d7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Apr 2012 01:36:28 -0400 Subject: fix breakage in mtdchar_open(), sanitize failure exits simple_release_fs() should be only done on failure there. Signed-off-by: Al Viro diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 94eb05b..58fc65f 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -106,16 +106,14 @@ static int mtdchar_open(struct inode *inode, struct file *file) } if (mtd->type == MTD_ABSENT) { - put_mtd_device(mtd); ret = -ENODEV; - goto out; + goto out1; } mtd_ino = iget_locked(mnt->mnt_sb, devnum); if (!mtd_ino) { - put_mtd_device(mtd); ret = -ENOMEM; - goto out; + goto out1; } if (mtd_ino->i_state & I_NEW) { mtd_ino->i_private = mtd; @@ -127,23 +125,25 @@ static int mtdchar_open(struct inode *inode, struct file *file) /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { - iput(mtd_ino); - put_mtd_device(mtd); ret = -EACCES; - goto out; + goto out2; } mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); if (!mfi) { - iput(mtd_ino); - put_mtd_device(mtd); ret = -ENOMEM; - goto out; + goto out2; } mfi->ino = mtd_ino; mfi->mtd = mtd; file->private_data = mfi; + mutex_unlock(&mtd_mutex); + return 0; +out2: + iput(mtd_ino); +out1: + put_mtd_device(mtd); out: mutex_unlock(&mtd_mutex); simple_release_fs(&mnt, &count); -- cgit v0.10.2 From 640946f20390e492694f9d7470656f2262385951 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2012 19:22:25 -0400 Subject: dentry leak in simple_fill_super() failure exit d_genocide() does _not_ evict dentries; it just removes extra ref pinning each of those. Normally it's followed by shrinking the tree (it's done just before generic_shutdown_super() by kill_litter_super()), but in case of simple_fill_super() nothing of that kind will follow. Just do shrink_dcache_parent() manually. Signed-off-by: Al Viro diff --git a/fs/libfs.c b/fs/libfs.c index 358094f..18d08f5 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -529,6 +529,7 @@ int simple_fill_super(struct super_block *s, unsigned long magic, return 0; out: d_genocide(root); + shrink_dcache_parent(root); dput(root); return -ENOMEM; } -- cgit v0.10.2 From b1349f2536efcb592927ab6f8687c36c3c124f6b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2012 19:02:48 -0400 Subject: typo fix in Documentation/filesystems/vfs.txt Signed-off-by: Al Viro diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index e916e3d..0d04920 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -114,7 +114,7 @@ members are defined: struct file_system_type { const char *name; int fs_flags; - struct dentry (*mount) (struct file_system_type *, int, + struct dentry *(*mount) (struct file_system_type *, int, const char *, void *); void (*kill_sb) (struct super_block *); struct module *owner; -- cgit v0.10.2 From 45038367c271f83b649b16551bf2d8174b203cb9 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Add new bitwise flag 'dd_flag' * Merged the following flags into one variable 'dd_flag': * drv_cleanup_done * resumeflag * Added the following flags into 'dd_flag' * remove pending * init done * Removed 'ftlrebuildflag' (similar flag is already part of mti_port->flags) Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index c37073d..34b395d 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -36,6 +36,7 @@ #include #include #include <../drivers/ata/ahci.h> +#include #include "mtip32xx.h" #define HW_CMD_SLOT_SZ (MTIP_MAX_COMMAND_SLOTS * 32) @@ -44,6 +45,7 @@ #define HW_PORT_PRIV_DMA_SZ \ (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ) +#define HOST_CAP_NZDMA (1 << 19) #define HOST_HSORG 0xFC #define HSORG_DISABLE_SLOTGRP_INTR (1<<24) #define HSORG_DISABLE_SLOTGRP_PXIS (1<<16) @@ -139,6 +141,12 @@ static void mtip_command_cleanup(struct driver_data *dd) int group = 0, commandslot = 0, commandindex = 0; struct mtip_cmd *command; struct mtip_port *port = dd->port; + static int in_progress; + + if (in_progress) + return; + + in_progress = 1; for (group = 0; group < 4; group++) { for (commandslot = 0; commandslot < 32; commandslot++) { @@ -165,7 +173,8 @@ static void mtip_command_cleanup(struct driver_data *dd) up(&port->cmd_slot); - atomic_set(&dd->drv_cleanup_done, true); + set_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag); + in_progress = 0; } /* @@ -262,6 +271,9 @@ static int hba_reset_nosleep(struct driver_data *dd) && time_before(jiffies, timeout)) mdelay(1); + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) + return -1; + if (readl(dd->mmio + HOST_CTL) & HOST_RESET) return -1; @@ -451,6 +463,9 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + /* * Chip quirk: escalate to hba reset if * PxCMD.CR not clear after 500 ms @@ -479,6 +494,9 @@ static void mtip_restart_port(struct mtip_port *port) while (time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + /* Clear PxSCTL.DET */ writel(readl(port->mmio + PORT_SCR_CTL) & ~1, port->mmio + PORT_SCR_CTL); @@ -490,6 +508,9 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return; + if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) dev_warn(&port->dd->pdev->dev, "COM reset failed\n"); @@ -520,7 +541,7 @@ static void mtip_timeout_function(unsigned long int data) if (unlikely(!port)) return; - if (atomic_read(&port->dd->resumeflag) == true) { + if (test_bit(MTIP_DD_FLAG_RESUME_BIT, &port->dd->dd_flag)) { mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(30000)); return; @@ -970,6 +991,9 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) /* don't proceed further */ return IRQ_HANDLED; } + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag)) + return rv; mtip_process_errors(dd, port_stat & PORT_IRQ_ERR); } @@ -1040,6 +1064,9 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) msleep(20); continue; /* svc thd is actively issuing commands */ } + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) + return -EFAULT; /* * Ignore s_active bit 0 of array element 0. * This bit will always be set @@ -1161,6 +1188,12 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command did not complete [%d] " "within timeout of %lu ms\n", atomic, timeout); + if (mtip_check_surprise_removal(port->dd->pdev) || + test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + rv = -ENXIO; + goto exec_ic_exit; + } rv = -EAGAIN; } @@ -1168,6 +1201,15 @@ static int mtip_exec_internal_command(struct mtip_port *port, & (1 << MTIP_TAG_INTERNAL)) { dev_warn(&port->dd->pdev->dev, "Retiring internal command but CI is 1.\n"); + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } + goto exec_ic_exit; } } else { @@ -1177,8 +1219,14 @@ static int mtip_exec_internal_command(struct mtip_port *port, while ((readl( port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) - && time_before(jiffies, timeout)) - ; + && time_before(jiffies, timeout)) { + if (mtip_check_surprise_removal(port->dd->pdev) || + test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + rv = -ENXIO; + goto exec_ic_exit; + } + } if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) { @@ -1186,9 +1234,17 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command did not complete [%d]\n", atomic); rv = -EAGAIN; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &port->dd->dd_flag)) { + hba_reset_nosleep(port->dd); + rv = -ENXIO; + } else { + mtip_restart_port(port); + rv = -EAGAIN; + } } } - +exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); @@ -1242,6 +1298,9 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) int rv = 0; struct host_to_dev_fis fis; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + return -EFAULT; + /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); fis.type = 0x27; @@ -1507,9 +1566,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) fis.device = command[6] & ~0x10; /* Clear the dev bit*/ - dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, " - "nsect %x, sect %x, lcyl %x, " - "hcyl %x, sel %x\n", + dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", __func__, command[0], command[1], @@ -1536,8 +1593,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) command[4] = reply->cyl_low; command[5] = reply->cyl_hi; - dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, " - "err %x , cyl_lo %x cyl_hi %x\n", + dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", __func__, command[0], command[1], @@ -2082,14 +2138,10 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, struct host_to_dev_fis *fis; struct mtip_port *port = dd->port; struct mtip_cmd *command = &port->commands[tag]; + int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; /* Map the scatter list for DMA access */ - if (dir == READ) - nents = dma_map_sg(&dd->pdev->dev, command->sg, - nents, DMA_FROM_DEVICE); - else - nents = dma_map_sg(&dd->pdev->dev, command->sg, - nents, DMA_TO_DEVICE); + nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); command->scatter_ents = nents; @@ -2129,7 +2181,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, */ command->comp_data = dd; command->comp_func = mtip_async_complete; - command->direction = (dir == READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + command->direction = dma_dir; /* * Set the completion function and data for the command passed @@ -2193,6 +2245,10 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, down(&dd->port->cmd_slot); *tag = get_slot(dd->port); + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + up(&dd->port->cmd_slot); + return NULL; + } if (unlikely(*tag < 0)) return NULL; @@ -2209,7 +2265,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, * return value * The size, in bytes, of the data copied into buf. */ -static ssize_t hw_show_registers(struct device *dev, +static ssize_t mtip_hw_show_registers(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2255,7 +2311,7 @@ static ssize_t hw_show_registers(struct device *dev, return size; } -static DEVICE_ATTR(registers, S_IRUGO, hw_show_registers, NULL); +static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); /* * Create the sysfs related attributes. @@ -2386,10 +2442,12 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) "FTL rebuild in progress. Polling for completion.\n"); start = jiffies; - dd->ftlrebuildflag = 1; timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); do { + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag))) + return -EFAULT; if (mtip_check_surprise_removal(dd->pdev)) return -EFAULT; @@ -2410,22 +2468,17 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) dev_warn(&dd->pdev->dev, "FTL rebuild complete (%d secs).\n", jiffies_to_msecs(jiffies - start) / 1000); - dd->ftlrebuildflag = 0; mtip_block_initialize(dd); - break; + return 0; } ssleep(10); } while (time_before(jiffies, timeout)); /* Check for timeout */ - if (dd->ftlrebuildflag) { - dev_err(&dd->pdev->dev, + dev_err(&dd->pdev->dev, "Timed out waiting for FTL rebuild to complete (%d secs).\n", jiffies_to_msecs(jiffies - start) / 1000); - return -EFAULT; - } - - return 0; + return -EFAULT; } /* @@ -2456,6 +2509,9 @@ static int mtip_service_thread(void *data) if (kthread_should_stop()) break; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + &dd->dd_flag))) + break; set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; @@ -2515,6 +2571,7 @@ static int mtip_hw_init(struct driver_data *dd) int i; int rv; unsigned int num_command_slots; + unsigned long timeout, timetaken; dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; @@ -2625,14 +2682,43 @@ static int mtip_hw_init(struct driver_data *dd) dd->port->mmio + i*0x80 + PORT_SDBV; } - /* Reset the HBA. */ - if (mtip_hba_reset(dd) < 0) { - dev_err(&dd->pdev->dev, - "Card did not reset within timeout\n"); - rv = -EIO; + timetaken = jiffies; + timeout = jiffies + msecs_to_jiffies(30000); + while (((readl(dd->port->mmio + PORT_SCR_STAT) & 0x0F) != 0x03) && + time_before(jiffies, timeout)) { + mdelay(100); + } + if (unlikely(mtip_check_surprise_removal(dd->pdev))) { + timetaken = jiffies - timetaken; + dev_warn(&dd->pdev->dev, + "Surprise removal detected at %u ms\n", + jiffies_to_msecs(timetaken)); + rv = -ENODEV; + goto out2 ; + } + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + timetaken = jiffies - timetaken; + dev_warn(&dd->pdev->dev, + "Removal detected at %u ms\n", + jiffies_to_msecs(timetaken)); + rv = -EFAULT; goto out2; } + /* Conditionally reset the HBA. */ + if (!(readl(dd->mmio + HOST_CAP) & HOST_CAP_NZDMA)) { + if (mtip_hba_reset(dd) < 0) { + dev_err(&dd->pdev->dev, + "Card did not reset within timeout\n"); + rv = -EIO; + goto out2; + } + } else { + /* Clear any pending interrupts on the HBA */ + writel(readl(dd->mmio + HOST_IRQ_STAT), + dd->mmio + HOST_IRQ_STAT); + } + mtip_init_port(dd->port); mtip_start_port(dd->port); @@ -2662,6 +2748,12 @@ static int mtip_hw_init(struct driver_data *dd) mod_timer(&dd->port->cmd_timer, jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); + + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + rv = -EFAULT; + goto out3; + } + if (mtip_get_identify(dd->port, NULL) < 0) { rv = -EFAULT; goto out3; @@ -2714,9 +2806,12 @@ static int mtip_hw_exit(struct driver_data *dd) * Send standby immediate (E0h) to the drive so that it * saves its state. */ - if (atomic_read(&dd->drv_cleanup_done) != true) { + if (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { - mtip_standby_immediate(dd->port); + if (test_bit(MTIP_FLAG_REBUILD_BIT, &dd->dd_flag)) + if (mtip_standby_immediate(dd->port)) + dev_warn(&dd->pdev->dev, + "STANDBY IMMEDIATE failed\n"); /* de-initialize the port. */ mtip_deinit_port(dd->port); @@ -2894,6 +2989,9 @@ static int mtip_block_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + return -ENOTTY; + switch (cmd) { case BLKFLSBUF: return -ENOTTY; @@ -2929,6 +3027,9 @@ static int mtip_block_compat_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; + if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + return -ENOTTY; + switch (cmd) { case BLKFLSBUF: return -ENOTTY; @@ -3051,6 +3152,11 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; + if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + bio_endio(bio, -ENXIO); + return; + } + if (unlikely(!bio_has_data(bio))) { blk_queue_flush(queue, 0); bio_endio(bio, 0); @@ -3063,7 +3169,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) if (unlikely((bio)->bi_vcnt > MTIP_MAX_SG)) { dev_warn(&dd->pdev->dev, - "Maximum number of SGL entries exceeded"); + "Maximum number of SGL entries exceeded\n"); bio_io_error(bio); mtip_hw_release_scatterlist(dd, tag); return; @@ -3212,8 +3318,10 @@ skip_create_disk: kobject_put(kobj); } - if (dd->mtip_svc_handler) + if (dd->mtip_svc_handler) { + set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); return rv; /* service thread created for handling rebuild */ + } start_service_thread: sprintf(thd_name, "mtip_svc_thd_%02d", index); @@ -3228,6 +3336,9 @@ start_service_thread: goto kthread_run_error; } + if (wait_for_rebuild == MTIP_FTL_REBUILD_MAGIC) + rv = wait_for_rebuild; + return rv; kthread_run_error: @@ -3274,10 +3385,12 @@ static int mtip_block_remove(struct driver_data *dd) } /* Clean up the sysfs attributes managed by the protocol layer. */ - kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); - if (kobj) { - mtip_hw_sysfs_exit(dd, kobj); - kobject_put(kobj); + if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { + kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); + if (kobj) { + mtip_hw_sysfs_exit(dd, kobj); + kobject_put(kobj); + } } /* @@ -3361,8 +3474,6 @@ static int mtip_pci_probe(struct pci_dev *pdev, return -ENOMEM; } - atomic_set(&dd->resumeflag, false); - /* Attach the private data to this PCI device. */ pci_set_drvdata(pdev, dd); @@ -3419,7 +3530,8 @@ static int mtip_pci_probe(struct pci_dev *pdev, * instance number. */ instance++; - + if (rv != MTIP_FTL_REBUILD_MAGIC) + set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); goto done; block_initialize_err: @@ -3433,9 +3545,6 @@ iomap_err: pci_set_drvdata(pdev, NULL); return rv; done: - /* Set the atomic variable as 0 */ - atomic_set(&dd->drv_cleanup_done, false); - return rv; } @@ -3451,8 +3560,10 @@ static void mtip_pci_remove(struct pci_dev *pdev) struct driver_data *dd = pci_get_drvdata(pdev); int counter = 0; + set_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag); + if (mtip_check_surprise_removal(pdev)) { - while (atomic_read(&dd->drv_cleanup_done) == false) { + while (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { counter++; msleep(20); if (counter == 10) { @@ -3490,7 +3601,7 @@ static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) return -EFAULT; } - atomic_set(&dd->resumeflag, true); + set_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); /* Disable ports & interrupts then send standby immediate */ rv = mtip_block_suspend(dd); @@ -3556,7 +3667,7 @@ static int mtip_pci_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "Unable to resume\n"); err: - atomic_set(&dd->resumeflag, false); + clear_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); return rv; } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index e0554a8..f4e46cc 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -121,6 +121,12 @@ #define MTIP_FLAG_REBUILD_BIT 5 #define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 +/* below are bit numbers in 'dd_flag' defined in driver_data */ +#define MTIP_DD_FLAG_REMOVE_PENDING_BIT 1 +#define MTIP_DD_FLAG_RESUME_BIT 2 +#define MTIP_DD_FLAG_CLEANUP_BIT 3 +#define MTIP_DD_FLAG_INIT_DONE_BIT 4 + /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { /* @@ -404,13 +410,9 @@ struct driver_data { unsigned slot_groups; /* number of slot groups the product supports */ - atomic_t drv_cleanup_done; /* Atomic variable for SRSI */ - unsigned long index; /* Index to determine the disk name */ - unsigned int ftlrebuildflag; /* FTL rebuild flag */ - - atomic_t resumeflag; /* Atomic variable to track suspend/resume */ + unsigned long dd_flag; /* NOTE: use atomic bit operations on this */ struct task_struct *mtip_svc_handler; /* task_struct of svc thd */ }; -- cgit v0.10.2 From dad40f16ff683a10f4f2bea55a0b9fd86d3db58e Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: make setting comp_time as common Moved setting completion time into mtip_issue_ncq_command() Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 34b395d..aaa8245 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -306,6 +306,10 @@ static inline void mtip_issue_ncq_command(struct mtip_port *port, int tag) port->cmd_issue[MTIP_TAG_INDEX(tag)]); spin_unlock_irqrestore(&port->cmd_issue_lock, flags); + + /* Set the command's timeout value.*/ + port->commands[tag].comp_time = jiffies + msecs_to_jiffies( + MTIP_NCQ_COMMAND_TIMEOUT_MS); } /* @@ -824,10 +828,6 @@ static void mtip_handle_tfe(struct driver_data *dd) set_bit(tag, tagaccum); - /* Update the timeout value. */ - port->commands[tag].comp_time = - jiffies + msecs_to_jiffies( - MTIP_NCQ_COMMAND_TIMEOUT_MS); /* Re-issue the command. */ mtip_issue_ncq_command(port, tag); @@ -2204,9 +2204,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, /* Issue the command to the hardware */ mtip_issue_ncq_command(port, tag); - /* Set the command's timeout value.*/ - port->commands[tag].comp_time = jiffies + msecs_to_jiffies( - MTIP_NCQ_COMMAND_TIMEOUT_MS); + return; } /* @@ -2538,10 +2536,6 @@ static int mtip_service_thread(void *data) /* Issue the command to the hardware */ mtip_issue_ncq_command(port, slot); - /* Set the command's timeout value.*/ - port->commands[slot].comp_time = jiffies + - msecs_to_jiffies(MTIP_NCQ_COMMAND_TIMEOUT_MS); - clear_bit(slot, port->cmds_to_issue); } -- cgit v0.10.2 From f65872177d838a33e90cbae25625b9bec05134ca Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Add new sysfs entry 'status' * Add support for detecting the following device status - write protect - over temp (thermal shutdown) * Add new sysfs entry 'status', possible values - online, write_protect, thermal_shutdown * Add new file 'sysfs-block-rssd' to document ABI (Reported-by: Greg Kroah-Hartman) Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/Documentation/ABI/testing/sysfs-block-rssd b/Documentation/ABI/testing/sysfs-block-rssd new file mode 100644 index 0000000..d535757 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-block-rssd @@ -0,0 +1,18 @@ +What: /sys/block/rssd*/registers +Date: March 2012 +KernelVersion: 3.3 +Contact: Asai Thambi S P +Description: This is a read-only file. Dumps below driver information and + hardware registers. + - S ACTive + - Command Issue + - Allocated + - Completed + - PORT IRQ STAT + - HOST IRQ STAT + +What: /sys/block/rssd*/status +Date: April 2012 +KernelVersion: 3.4 +Contact: Asai Thambi S P +Description: This is a read-only file. Indicates the status of the device. diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index aaa8245..79fdb063 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -725,6 +725,10 @@ static void print_tags(struct driver_data *dd, dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); } +static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, + dma_addr_t buffer_dma, unsigned int sectors); +static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, + struct smart_attr *attrib); /* * Handle an error. * @@ -735,12 +739,15 @@ static void print_tags(struct driver_data *dd, */ static void mtip_handle_tfe(struct driver_data *dd) { - int group, tag, bit, reissue; + int group, tag, bit, reissue, rv; struct mtip_port *port; - struct mtip_cmd *command; + struct mtip_cmd *cmd; u32 completed; struct host_to_dev_fis *fis; unsigned long tagaccum[SLOTBITS_IN_LONGS]; + unsigned char *buf; + char *fail_reason = NULL; + int fail_all_ncq_write = 0, fail_all_ncq_cmds = 0; dev_warn(&dd->pdev->dev, "Taskfile error\n"); @@ -772,13 +779,13 @@ static void mtip_handle_tfe(struct driver_data *dd) if (tag == MTIP_TAG_INTERNAL) continue; - command = &port->commands[tag]; - if (likely(command->comp_func)) { + cmd = &port->commands[tag]; + if (likely(cmd->comp_func)) { set_bit(tag, tagaccum); - atomic_set(&port->commands[tag].active, 0); - command->comp_func(port, + atomic_set(&cmd->active, 0); + cmd->comp_func(port, tag, - command->comp_data, + cmd->comp_data, 0); } else { dev_err(&port->dd->pdev->dev, @@ -798,6 +805,38 @@ static void mtip_handle_tfe(struct driver_data *dd) mdelay(20); mtip_restart_port(port); + /* Trying to determine the cause of the error */ + rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, + dd->port->log_buf, + dd->port->log_buf_dma, 1); + if (rv) { + dev_warn(&dd->pdev->dev, + "Error in READ LOG EXT (10h) command\n"); + /* non-critical error, don't fail the load */ + } else { + buf = (unsigned char *)dd->port->log_buf; + if (buf[259] & 0x1) { + dev_info(&dd->pdev->dev, + "Write protect bit is set.\n"); + set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + fail_all_ncq_write = 1; + fail_reason = "write protect"; + } + if (buf[288] == 0xF7) { + dev_info(&dd->pdev->dev, + "Exceeded Tmax, drive in thermal shutdown.\n"); + set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + fail_all_ncq_cmds = 1; + fail_reason = "thermal shutdown"; + } + if (buf[288] == 0xBF) { + dev_info(&dd->pdev->dev, + "Drive indicates rebuild has failed.\n"); + fail_all_ncq_cmds = 1; + fail_reason = "rebuild failed"; + } + } + /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); @@ -806,25 +845,44 @@ static void mtip_handle_tfe(struct driver_data *dd) for (bit = 0; bit < 32; bit++) { reissue = 1; tag = (group << 5) + bit; + cmd = &port->commands[tag]; /* If the active bit is set re-issue the command */ - if (atomic_read(&port->commands[tag].active) == 0) + if (atomic_read(&cmd->active) == 0) continue; - fis = (struct host_to_dev_fis *) - port->commands[tag].command; + fis = (struct host_to_dev_fis *)cmd->command; /* Should re-issue? */ if (tag == MTIP_TAG_INTERNAL || fis->command == ATA_CMD_SET_FEATURES) reissue = 0; + else { + if (fail_all_ncq_cmds || + (fail_all_ncq_write && + fis->command == ATA_CMD_FPDMA_WRITE)) { + dev_warn(&dd->pdev->dev, + " Fail: %s w/tag %d [%s].\n", + fis->command == ATA_CMD_FPDMA_WRITE ? + "write" : "read", + tag, + fail_reason != NULL ? + fail_reason : "unknown"); + atomic_set(&cmd->active, 0); + if (cmd->comp_func) { + cmd->comp_func(port, tag, + cmd->comp_data, + -ENODATA); + } + continue; + } + } /* * First check if this command has * exceeded its retries. */ - if (reissue && - (port->commands[tag].retries-- > 0)) { + if (reissue && (cmd->retries-- > 0)) { set_bit(tag, tagaccum); @@ -837,13 +895,13 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Retire a command that will not be reissued */ dev_warn(&port->dd->pdev->dev, "retiring tag %d\n", tag); - atomic_set(&port->commands[tag].active, 0); + atomic_set(&cmd->active, 0); - if (port->commands[tag].comp_func) - port->commands[tag].comp_func( + if (cmd->comp_func) + cmd->comp_func( port, tag, - port->commands[tag].comp_data, + cmd->comp_data, PORT_IRQ_TF_ERR); else dev_warn(&port->dd->pdev->dev, @@ -1374,6 +1432,7 @@ static int mtip_standby_immediate(struct mtip_port *port) { int rv; struct host_to_dev_fis fis; + unsigned long start; /* Build the FIS. */ memset(&fis, 0, sizeof(struct host_to_dev_fis)); @@ -1381,15 +1440,150 @@ static int mtip_standby_immediate(struct mtip_port *port) fis.opts = 1 << 7; fis.command = ATA_CMD_STANDBYNOW1; - /* Execute the command. Use a 15-second timeout for large drives. */ + start = jiffies; rv = mtip_exec_internal_command(port, &fis, 5, 0, 0, 0, - GFP_KERNEL, + GFP_ATOMIC, 15000); + dbg_printk(MTIP_DRV_NAME "Time taken to complete standby cmd: %d ms\n", + jiffies_to_msecs(jiffies - start)); + if (rv) + dev_warn(&port->dd->pdev->dev, + "STANDBY IMMEDIATE command failed.\n"); + + return rv; +} + +/* + * Issue a READ LOG EXT command to the device. + * + * @port pointer to the port structure. + * @page page number to fetch + * @buffer pointer to buffer + * @buffer_dma dma address corresponding to @buffer + * @sectors page length to fetch, in sectors + * + * return value + * @rv return value from mtip_exec_internal_command() + */ +static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, + dma_addr_t buffer_dma, unsigned int sectors) +{ + struct host_to_dev_fis fis; + + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_READ_LOG_EXT; + fis.sect_count = sectors & 0xFF; + fis.sect_cnt_ex = (sectors >> 8) & 0xFF; + fis.lba_low = page; + fis.lba_mid = 0; + fis.device = ATA_DEVICE_OBS; + + memset(buffer, 0, sectors * ATA_SECT_SIZE); + + return mtip_exec_internal_command(port, + &fis, + 5, + buffer_dma, + sectors * ATA_SECT_SIZE, + 0, + GFP_ATOMIC, + MTIP_INTERNAL_COMMAND_TIMEOUT_MS); +} + +/* + * Issue a SMART READ DATA command to the device. + * + * @port pointer to the port structure. + * @buffer pointer to buffer + * @buffer_dma dma address corresponding to @buffer + * + * return value + * @rv return value from mtip_exec_internal_command() + */ +static int mtip_get_smart_data(struct mtip_port *port, u8 *buffer, + dma_addr_t buffer_dma) +{ + struct host_to_dev_fis fis; + + memset(&fis, 0, sizeof(struct host_to_dev_fis)); + fis.type = 0x27; + fis.opts = 1 << 7; + fis.command = ATA_CMD_SMART; + fis.features = 0xD0; + fis.sect_count = 1; + fis.lba_mid = 0x4F; + fis.lba_hi = 0xC2; + fis.device = ATA_DEVICE_OBS; + + return mtip_exec_internal_command(port, + &fis, + 5, + buffer_dma, + ATA_SECT_SIZE, + 0, + GFP_ATOMIC, + 15000); +} + +/* + * Get the value of a smart attribute + * + * @port pointer to the port structure + * @id attribute number + * @attrib pointer to return attrib information corresponding to @id + * + * return value + * -EINVAL NULL buffer passed or unsupported attribute @id. + * -EPERM Identify data not valid, SMART not supported or not enabled + */ +static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, + struct smart_attr *attrib) +{ + int rv, i; + struct smart_attr *pattr; + + if (!attrib) + return -EINVAL; + + if (!port->identify_valid) { + dev_warn(&port->dd->pdev->dev, "IDENTIFY DATA not valid\n"); + return -EPERM; + } + if (!(port->identify[82] & 0x1)) { + dev_warn(&port->dd->pdev->dev, "SMART not supported\n"); + return -EPERM; + } + if (!(port->identify[85] & 0x1)) { + dev_warn(&port->dd->pdev->dev, "SMART not enabled\n"); + return -EPERM; + } + + memset(port->smart_buf, 0, ATA_SECT_SIZE); + rv = mtip_get_smart_data(port, port->smart_buf, port->smart_buf_dma); + if (rv) { + dev_warn(&port->dd->pdev->dev, "Failed to ge SMART data\n"); + return rv; + } + + pattr = (struct smart_attr *)(port->smart_buf + 2); + for (i = 0; i < 29; i++, pattr++) + if (pattr->attr_id == id) { + memcpy(attrib, pattr, sizeof(struct smart_attr)); + break; + } + + if (i == 29) { + dev_warn(&port->dd->pdev->dev, + "Query for invalid SMART attribute ID\n"); + rv = -EINVAL; + } return rv; } @@ -2272,7 +2466,7 @@ static ssize_t mtip_hw_show_registers(struct device *dev, int size = 0; int n; - size += sprintf(&buf[size], "%s:\ns_active:\n", __func__); + size += sprintf(&buf[size], "S ACTive:\n"); for (n = 0; n < dd->slot_groups; n++) size += sprintf(&buf[size], "0x%08x\n", @@ -2296,20 +2490,39 @@ static ssize_t mtip_hw_show_registers(struct device *dev, group_allocated); } - size += sprintf(&buf[size], "completed:\n"); + size += sprintf(&buf[size], "Completed:\n"); for (n = 0; n < dd->slot_groups; n++) size += sprintf(&buf[size], "0x%08x\n", readl(dd->port->completed[n])); - size += sprintf(&buf[size], "PORT_IRQ_STAT 0x%08x\n", + size += sprintf(&buf[size], "PORT IRQ STAT : 0x%08x\n", readl(dd->port->mmio + PORT_IRQ_STAT)); - size += sprintf(&buf[size], "HOST_IRQ_STAT 0x%08x\n", + size += sprintf(&buf[size], "HOST IRQ STAT : 0x%08x\n", readl(dd->mmio + HOST_IRQ_STAT)); return size; } + +static ssize_t mtip_hw_show_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct driver_data *dd = dev_to_disk(dev)->private_data; + int size = 0; + + if (test_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag)) + size += sprintf(buf, "%s", "thermal_shutdown\n"); + else if (test_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag)) + size += sprintf(buf, "%s", "write_protect\n"); + else + size += sprintf(buf, "%s", "online\n"); + + return size; +} + static DEVICE_ATTR(registers, S_IRUGO, mtip_hw_show_registers, NULL); +static DEVICE_ATTR(status, S_IRUGO, mtip_hw_show_status, NULL); /* * Create the sysfs related attributes. @@ -2328,7 +2541,10 @@ static int mtip_hw_sysfs_init(struct driver_data *dd, struct kobject *kobj) if (sysfs_create_file(kobj, &dev_attr_registers.attr)) dev_warn(&dd->pdev->dev, - "Error creating registers sysfs entry\n"); + "Error creating 'registers' sysfs entry\n"); + if (sysfs_create_file(kobj, &dev_attr_status.attr)) + dev_warn(&dd->pdev->dev, + "Error creating 'status' sysfs entry\n"); return 0; } @@ -2348,6 +2564,7 @@ static int mtip_hw_sysfs_exit(struct driver_data *dd, struct kobject *kobj) return -EINVAL; sysfs_remove_file(kobj, &dev_attr_registers.attr); + sysfs_remove_file(kobj, &dev_attr_status.attr); return 0; } @@ -2566,6 +2783,8 @@ static int mtip_hw_init(struct driver_data *dd) int rv; unsigned int num_command_slots; unsigned long timeout, timetaken; + unsigned char *buf; + struct smart_attr attr242; dd->mmio = pcim_iomap_table(dd->pdev)[MTIP_ABAR]; @@ -2600,7 +2819,7 @@ static int mtip_hw_init(struct driver_data *dd) /* Allocate memory for the command list. */ dd->port->command_list = dmam_alloc_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), &dd->port->command_list_dma, GFP_KERNEL); if (!dd->port->command_list) { @@ -2613,7 +2832,7 @@ static int mtip_hw_init(struct driver_data *dd) /* Clear the memory we have allocated. */ memset(dd->port->command_list, 0, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2)); + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4)); /* Setup the addresse of the RX FIS. */ dd->port->rxfis = dd->port->command_list + HW_CMD_SLOT_SZ; @@ -2629,10 +2848,19 @@ static int mtip_hw_init(struct driver_data *dd) dd->port->identify_dma = dd->port->command_tbl_dma + HW_CMD_TBL_AR_SZ; - /* Setup the address of the sector buffer. */ + /* Setup the address of the sector buffer - for some non-ncq cmds */ dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE; dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE; + /* Setup the address of the log buf - for read log command */ + dd->port->log_buf = (void *)dd->port->sector_buffer + ATA_SECT_SIZE; + dd->port->log_buf_dma = dd->port->sector_buffer_dma + ATA_SECT_SIZE; + + /* Setup the address of the smart buf - for smart read data command */ + dd->port->smart_buf = (void *)dd->port->log_buf + ATA_SECT_SIZE; + dd->port->smart_buf_dma = dd->port->log_buf_dma + ATA_SECT_SIZE; + + /* Point the command headers at the command tables. */ for (i = 0; i < num_command_slots; i++) { dd->port->commands[i].command_header = @@ -2759,6 +2987,43 @@ static int mtip_hw_init(struct driver_data *dd) return MTIP_FTL_REBUILD_MAGIC; } mtip_dump_identify(dd->port); + + /* check write protect, over temp and rebuild statuses */ + rv = mtip_read_log_page(dd->port, ATA_LOG_SATA_NCQ, + dd->port->log_buf, + dd->port->log_buf_dma, 1); + if (rv) { + dev_warn(&dd->pdev->dev, + "Error in READ LOG EXT (10h) command\n"); + /* non-critical error, don't fail the load */ + } else { + buf = (unsigned char *)dd->port->log_buf; + if (buf[259] & 0x1) { + dev_info(&dd->pdev->dev, + "Write protect bit is set.\n"); + set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + } + if (buf[288] == 0xF7) { + dev_info(&dd->pdev->dev, + "Exceeded Tmax, drive in thermal shutdown.\n"); + set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + } + if (buf[288] == 0xBF) { + dev_info(&dd->pdev->dev, + "Drive indicates rebuild has failed.\n"); + /* TODO */ + } + } + + /* get write protect progess */ + memset(&attr242, 0, sizeof(struct smart_attr)); + if (mtip_get_smart_attr(dd->port, 242, &attr242)) + dev_warn(&dd->pdev->dev, + "Unable to check write protect progress\n"); + else + dev_info(&dd->pdev->dev, + "Write protect progress: %d%% (%d blocks)\n", + attr242.cur, attr242.data); return rv; out3: @@ -2776,7 +3041,7 @@ out2: /* Free the command/command header memory. */ dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), dd->port->command_list, dd->port->command_list_dma); out1: @@ -2825,7 +3090,7 @@ static int mtip_hw_exit(struct driver_data *dd) /* Free the command/command header memory. */ dmam_free_coherent(&dd->pdev->dev, - HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 2), + HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4), dd->port->command_list, dd->port->command_list_dma); /* Free the memory allocated for the for structure. */ @@ -3378,7 +3643,7 @@ static int mtip_block_remove(struct driver_data *dd) kthread_stop(dd->mtip_svc_handler); } - /* Clean up the sysfs attributes managed by the protocol layer. */ + /* Clean up the sysfs attributes, if created */ if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); if (kobj) { diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index f4e46cc..ea5c7e7 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -127,6 +127,19 @@ #define MTIP_DD_FLAG_CLEANUP_BIT 3 #define MTIP_DD_FLAG_INIT_DONE_BIT 4 +#define MTIP_DD_FLAG_WRITE_PROTECT_BIT 5 +#define MTIP_DD_FLAG_OVER_TEMP_BIT 6 +#define MTIP_DD_FLAG_REBUILD_FAILED_BIT 7 + +__packed struct smart_attr{ + u8 attr_id; + u16 flags; + u8 cur; + u8 worst; + u32 data; + u8 res[3]; +}; + /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { /* @@ -351,6 +364,12 @@ struct mtip_port { * when the command slot and all associated data structures * are no longer needed. */ + u16 *log_buf; + dma_addr_t log_buf_dma; + + u8 *smart_buf; + dma_addr_t smart_buf_dma; + unsigned long allocated[SLOTBITS_IN_LONGS]; /* * used to queue commands when an internal command is in progress -- cgit v0.10.2 From 8182b495281764ca518781e876c91900e75088d2 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: misc changes * Handle the interrupt completion of polled internal commands * Do not check remove pending flag for standby command * On rebuild failure, - set corresponding bit dd_flag - do not send standby command * Free ida index in remove path Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 79fdb063..be96626 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -708,6 +708,14 @@ static void mtip_completion(struct mtip_port *port, complete(waiting); } +static void mtip_null_completion(struct mtip_port *port, + int tag, + void *data, + int status) +{ + return; +} + /* * Helper function for tag logging */ @@ -992,8 +1000,6 @@ static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) } } - dev_warn(&dd->pdev->dev, "IRQ status 0x%x ignored.\n", port_stat); - return; } @@ -1161,7 +1167,7 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) * -EAGAIN Time out waiting for command to complete. */ static int mtip_exec_internal_command(struct mtip_port *port, - void *fis, + struct host_to_dev_fis *fis, int fis_len, dma_addr_t buffer, int buf_len, @@ -1190,14 +1196,17 @@ static int mtip_exec_internal_command(struct mtip_port *port, set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); if (atomic == GFP_KERNEL) { - /* wait for io to complete if non atomic */ - if (mtip_quiesce_io(port, 5000) < 0) { - dev_warn(&port->dd->pdev->dev, - "Failed to quiesce IO\n"); - release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); - wake_up_interruptible(&port->svc_wait); - return -EBUSY; + if (fis->command != ATA_CMD_STANDBYNOW1) { + /* wait for io to complete if non atomic */ + if (mtip_quiesce_io(port, 5000) < 0) { + dev_warn(&port->dd->pdev->dev, + "Failed to quiesce IO\n"); + release_slot(port, MTIP_TAG_INTERNAL); + clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, + &port->flags); + wake_up_interruptible(&port->svc_wait); + return -EBUSY; + } } /* Set the completion function and data for the command. */ @@ -1207,7 +1216,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, } else { /* Clear completion - we're going to poll */ int_cmd->comp_data = NULL; - int_cmd->comp_func = NULL; + int_cmd->comp_func = mtip_null_completion; } /* Copy the command to the command table */ @@ -1273,12 +1282,14 @@ static int mtip_exec_internal_command(struct mtip_port *port, } else { /* Spin for checking if command still outstanding */ timeout = jiffies + msecs_to_jiffies(timeout); - - while ((readl( - port->cmd_issue[MTIP_TAG_INTERNAL]) - & (1 << MTIP_TAG_INTERNAL)) - && time_before(jiffies, timeout)) { - if (mtip_check_surprise_removal(port->dd->pdev) || + while ((readl(port->cmd_issue[MTIP_TAG_INTERNAL]) + & (1 << MTIP_TAG_INTERNAL)) + && time_before(jiffies, timeout)) { + if (mtip_check_surprise_removal(port->dd->pdev)) { + rv = -ENXIO; + goto exec_ic_exit; + } + if ((fis->command != ATA_CMD_STANDBYNOW1) && test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; @@ -1289,8 +1300,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, if (readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL)) { dev_err(&port->dd->pdev->dev, - "Internal command did not complete [%d]\n", - atomic); + "Internal command did not complete [atomic]\n"); rv = -EAGAIN; if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { @@ -2758,7 +2768,9 @@ static int mtip_service_thread(void *data) clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { - mtip_ftl_rebuild_poll(dd); + if (!mtip_ftl_rebuild_poll(dd)) + set_bit(MTIP_DD_FLAG_REBUILD_FAILED_BIT, + &dd->dd_flag); clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); } clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); @@ -3067,7 +3079,7 @@ static int mtip_hw_exit(struct driver_data *dd) */ if (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { - if (test_bit(MTIP_FLAG_REBUILD_BIT, &dd->dd_flag)) + if (!test_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3657,6 +3669,11 @@ static int mtip_block_remove(struct driver_data *dd) * from /dev */ del_gendisk(dd->disk); + + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + blk_cleanup_queue(dd->queue); dd->disk = NULL; dd->queue = NULL; @@ -3686,6 +3703,11 @@ static int mtip_block_shutdown(struct driver_data *dd) /* Delete our gendisk structure, and cleanup the blk queue. */ del_gendisk(dd->disk); + + spin_lock(&rssd_index_lock); + ida_remove(&rssd_index_ida, dd->index); + spin_unlock(&rssd_index_lock); + blk_cleanup_queue(dd->queue); dd->disk = NULL; dd->queue = NULL; -- cgit v0.10.2 From 8a857a880bd83ba4f217d55dd4a623a7e4b5cb47 Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:38 +0200 Subject: mtip32xx: Shorten macro names Shortened macros used to represent mtip_port->flags and dd->dd_flag Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index be96626..e57864a 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -173,7 +173,7 @@ static void mtip_command_cleanup(struct driver_data *dd) up(&port->cmd_slot); - set_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag); in_progress = 0; } @@ -271,7 +271,7 @@ static int hba_reset_nosleep(struct driver_data *dd) && time_before(jiffies, timeout)) mdelay(1); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) return -1; if (readl(dd->mmio + HOST_CTL) & HOST_RESET) @@ -467,7 +467,7 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; /* @@ -498,7 +498,7 @@ static void mtip_restart_port(struct mtip_port *port) while (time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; /* Clear PxSCTL.DET */ @@ -512,7 +512,7 @@ static void mtip_restart_port(struct mtip_port *port) && time_before(jiffies, timeout)) ; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return; if ((readl(port->mmio + PORT_SCR_STAT) & 0x01) == 0) @@ -545,7 +545,7 @@ static void mtip_timeout_function(unsigned long int data) if (unlikely(!port)) return; - if (test_bit(MTIP_DD_FLAG_RESUME_BIT, &port->dd->dd_flag)) { + if (test_bit(MTIP_DDF_RESUME_BIT, &port->dd->dd_flag)) { mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(30000)); return; @@ -572,7 +572,7 @@ static void mtip_timeout_function(unsigned long int data) cmdto_cnt++; if (cmdto_cnt == 1) - set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); /* * Clear the completed bit. This should prevent @@ -610,7 +610,7 @@ static void mtip_timeout_function(unsigned long int data) "%d commands timed out: restarting port", cmdto_cnt); mtip_restart_port(port); - clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); } @@ -765,7 +765,7 @@ static void mtip_handle_tfe(struct driver_data *dd) del_timer(&port->cmd_timer); /* Set eh_active */ - set_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); /* Loop through all the groups */ for (group = 0; group < dd->slot_groups; group++) { @@ -826,14 +826,14 @@ static void mtip_handle_tfe(struct driver_data *dd) if (buf[259] & 0x1) { dev_info(&dd->pdev->dev, "Write protect bit is set.\n"); - set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); fail_all_ncq_write = 1; fail_reason = "write protect"; } if (buf[288] == 0xF7) { dev_info(&dd->pdev->dev, "Exceeded Tmax, drive in thermal shutdown.\n"); - set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); fail_all_ncq_cmds = 1; fail_reason = "thermal shutdown"; } @@ -920,7 +920,7 @@ static void mtip_handle_tfe(struct driver_data *dd) print_tags(dd, "TFE tags reissued:", tagaccum); /* clear eh_active */ - clear_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); mod_timer(&port->cmd_timer, @@ -988,7 +988,7 @@ static inline void mtip_process_legacy(struct driver_data *dd, u32 port_stat) struct mtip_port *port = dd->port; struct mtip_cmd *cmd = &port->commands[MTIP_TAG_INTERNAL]; - if (test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && + if (test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && (cmd != NULL) && !(readl(port->cmd_issue[MTIP_TAG_INTERNAL]) & (1 << MTIP_TAG_INTERNAL))) { if (cmd->comp_func) { @@ -1055,7 +1055,7 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data) /* don't proceed further */ return IRQ_HANDLED; } - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) return rv; @@ -1123,13 +1123,12 @@ static int mtip_quiesce_io(struct mtip_port *port, unsigned long timeout) to = jiffies + msecs_to_jiffies(timeout); do { - if (test_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags) && - test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + if (test_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags) && + test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { msleep(20); continue; /* svc thd is actively issuing commands */ } - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, - &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return -EFAULT; /* * Ignore s_active bit 0 of array element 0. @@ -1193,7 +1192,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, "Internal command already active\n"); return -EBUSY; } - set_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); if (atomic == GFP_KERNEL) { if (fis->command != ATA_CMD_STANDBYNOW1) { @@ -1202,8 +1201,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, dev_warn(&port->dd->pdev->dev, "Failed to quiesce IO\n"); release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, - &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); return -EBUSY; } @@ -1256,7 +1254,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, "within timeout of %lu ms\n", atomic, timeout); if (mtip_check_surprise_removal(port->dd->pdev) || - test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; goto exec_ic_exit; @@ -1268,7 +1266,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, & (1 << MTIP_TAG_INTERNAL)) { dev_warn(&port->dd->pdev->dev, "Retiring internal command but CI is 1.\n"); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { hba_reset_nosleep(port->dd); rv = -ENXIO; @@ -1290,7 +1288,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, goto exec_ic_exit; } if ((fis->command != ATA_CMD_STANDBYNOW1) && - test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { rv = -ENXIO; goto exec_ic_exit; @@ -1302,7 +1300,7 @@ static int mtip_exec_internal_command(struct mtip_port *port, dev_err(&port->dd->pdev->dev, "Internal command did not complete [atomic]\n"); rv = -EAGAIN; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) { hba_reset_nosleep(port->dd); rv = -ENXIO; @@ -1316,7 +1314,7 @@ exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); - clear_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); return rv; @@ -1366,7 +1364,7 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer) int rv = 0; struct host_to_dev_fis fis; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &port->dd->dd_flag)) + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &port->dd->dd_flag)) return -EFAULT; /* Build the FIS. */ @@ -2398,10 +2396,10 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, * To prevent this command from being issued * if an internal command is in progress or error handling is active. */ - if (unlikely(test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) || - test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags))) { + if (unlikely(test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) || + test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))) { set_bit(tag, port->cmds_to_issue); - set_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); + set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); return; } @@ -2447,7 +2445,7 @@ static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, down(&dd->port->cmd_slot); *tag = get_slot(dd->port); - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { up(&dd->port->cmd_slot); return NULL; } @@ -2521,9 +2519,9 @@ static ssize_t mtip_hw_show_status(struct device *dev, struct driver_data *dd = dev_to_disk(dev)->private_data; int size = 0; - if (test_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag)) + if (test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag)) size += sprintf(buf, "%s", "thermal_shutdown\n"); - else if (test_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag)) + else if (test_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag)) size += sprintf(buf, "%s", "write_protect\n"); else size += sprintf(buf, "%s", "online\n"); @@ -2670,7 +2668,7 @@ static int mtip_ftl_rebuild_poll(struct driver_data *dd) timeout = jiffies + msecs_to_jiffies(MTIP_FTL_REBUILD_TIMEOUT_MS); do { - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -EFAULT; if (mtip_check_surprise_removal(dd->pdev)) @@ -2728,17 +2726,17 @@ static int mtip_service_thread(void *data) * is in progress nor error handling is active */ wait_event_interruptible(port->svc_wait, (port->flags) && - !test_bit(MTIP_FLAG_IC_ACTIVE_BIT, &port->flags) && - !test_bit(MTIP_FLAG_EH_ACTIVE_BIT, &port->flags)); + !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && + !test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)); if (kthread_should_stop()) break; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) break; - set_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags)) { + set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); + if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; /* used to restrict the loop to one iteration */ slot_start = num_cmd_slots; @@ -2766,16 +2764,16 @@ static int mtip_service_thread(void *data) clear_bit(slot, port->cmds_to_issue); } - clear_bit(MTIP_FLAG_ISSUE_CMDS_BIT, &port->flags); - } else if (test_bit(MTIP_FLAG_REBUILD_BIT, &port->flags)) { + clear_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); + } else if (test_bit(MTIP_PF_REBUILD_BIT, &port->flags)) { if (!mtip_ftl_rebuild_poll(dd)) - set_bit(MTIP_DD_FLAG_REBUILD_FAILED_BIT, + set_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag); - clear_bit(MTIP_FLAG_REBUILD_BIT, &port->flags); + clear_bit(MTIP_PF_REBUILD_BIT, &port->flags); } - clear_bit(MTIP_FLAG_SVC_THD_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + if (test_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &port->flags)) break; } return 0; @@ -2930,7 +2928,7 @@ static int mtip_hw_init(struct driver_data *dd) rv = -ENODEV; goto out2 ; } - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { timetaken = jiffies - timetaken; dev_warn(&dd->pdev->dev, "Removal detected at %u ms\n", @@ -2983,7 +2981,7 @@ static int mtip_hw_init(struct driver_data *dd) jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { rv = -EFAULT; goto out3; } @@ -2995,7 +2993,7 @@ static int mtip_hw_init(struct driver_data *dd) if (*(dd->port->identify + MTIP_FTL_REBUILD_OFFSET) == MTIP_FTL_REBUILD_MAGIC) { - set_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags); + set_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags); return MTIP_FTL_REBUILD_MAGIC; } mtip_dump_identify(dd->port); @@ -3013,12 +3011,12 @@ static int mtip_hw_init(struct driver_data *dd) if (buf[259] & 0x1) { dev_info(&dd->pdev->dev, "Write protect bit is set.\n"); - set_bit(MTIP_DD_FLAG_WRITE_PROTECT_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_WRITE_PROTECT_BIT, &dd->dd_flag); } if (buf[288] == 0xF7) { dev_info(&dd->pdev->dev, "Exceeded Tmax, drive in thermal shutdown.\n"); - set_bit(MTIP_DD_FLAG_OVER_TEMP_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag); } if (buf[288] == 0xBF) { dev_info(&dd->pdev->dev, @@ -3077,9 +3075,9 @@ static int mtip_hw_exit(struct driver_data *dd) * Send standby immediate (E0h) to the drive so that it * saves its state. */ - if (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { + if (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { - if (!test_bit(MTIP_FLAG_REBUILD_BIT, &dd->port->flags)) + if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags)) if (mtip_standby_immediate(dd->port)) dev_warn(&dd->pdev->dev, "STANDBY IMMEDIATE failed\n"); @@ -3260,7 +3258,7 @@ static int mtip_block_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -ENOTTY; switch (cmd) { @@ -3298,7 +3296,7 @@ static int mtip_block_compat_ioctl(struct block_device *dev, if (!dd) return -ENOTTY; - if (unlikely(test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag))) + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) return -ENOTTY; switch (cmd) { @@ -3423,7 +3421,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; - if (test_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag)) { + if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { bio_endio(bio, -ENXIO); return; } @@ -3590,7 +3588,7 @@ skip_create_disk: } if (dd->mtip_svc_handler) { - set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); return rv; /* service thread created for handling rebuild */ } @@ -3650,13 +3648,13 @@ static int mtip_block_remove(struct driver_data *dd) struct kobject *kobj; if (dd->mtip_svc_handler) { - set_bit(MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + set_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); wake_up_interruptible(&dd->port->svc_wait); kthread_stop(dd->mtip_svc_handler); } /* Clean up the sysfs attributes, if created */ - if (test_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag)) { + if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) { kobj = kobject_get(&disk_to_dev(dd->disk)->kobj); if (kobj) { mtip_hw_sysfs_exit(dd, kobj); @@ -3812,7 +3810,7 @@ static int mtip_pci_probe(struct pci_dev *pdev, */ instance++; if (rv != MTIP_FTL_REBUILD_MAGIC) - set_bit(MTIP_DD_FLAG_INIT_DONE_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag); goto done; block_initialize_err: @@ -3841,10 +3839,10 @@ static void mtip_pci_remove(struct pci_dev *pdev) struct driver_data *dd = pci_get_drvdata(pdev); int counter = 0; - set_bit(MTIP_DD_FLAG_REMOVE_PENDING_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag); if (mtip_check_surprise_removal(pdev)) { - while (!test_bit(MTIP_DD_FLAG_CLEANUP_BIT, &dd->dd_flag)) { + while (!test_bit(MTIP_DDF_CLEANUP_BIT, &dd->dd_flag)) { counter++; msleep(20); if (counter == 10) { @@ -3882,7 +3880,7 @@ static int mtip_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) return -EFAULT; } - set_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); + set_bit(MTIP_DDF_RESUME_BIT, &dd->dd_flag); /* Disable ports & interrupts then send standby immediate */ rv = mtip_block_suspend(dd); @@ -3948,7 +3946,7 @@ static int mtip_pci_resume(struct pci_dev *pdev) dev_err(&pdev->dev, "Unable to resume\n"); err: - clear_bit(MTIP_DD_FLAG_RESUME_BIT, &dd->dd_flag); + clear_bit(MTIP_DDF_RESUME_BIT, &dd->dd_flag); return rv; } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index ea5c7e7..5ad2d79 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -114,22 +114,22 @@ #define __force_bit2int (unsigned int __force) /* below are bit numbers in 'flags' defined in mtip_port */ -#define MTIP_FLAG_IC_ACTIVE_BIT 0 -#define MTIP_FLAG_EH_ACTIVE_BIT 1 -#define MTIP_FLAG_SVC_THD_ACTIVE_BIT 2 -#define MTIP_FLAG_ISSUE_CMDS_BIT 4 -#define MTIP_FLAG_REBUILD_BIT 5 -#define MTIP_FLAG_SVC_THD_SHOULD_STOP_BIT 8 +#define MTIP_PF_IC_ACTIVE_BIT 0 +#define MTIP_PF_EH_ACTIVE_BIT 1 +#define MTIP_PF_SVC_THD_ACTIVE_BIT 2 +#define MTIP_PF_ISSUE_CMDS_BIT 4 +#define MTIP_PF_REBUILD_BIT 5 +#define MTIP_PF_SVC_THD_SHOULD_STOP_BIT 8 /* below are bit numbers in 'dd_flag' defined in driver_data */ -#define MTIP_DD_FLAG_REMOVE_PENDING_BIT 1 -#define MTIP_DD_FLAG_RESUME_BIT 2 -#define MTIP_DD_FLAG_CLEANUP_BIT 3 -#define MTIP_DD_FLAG_INIT_DONE_BIT 4 - -#define MTIP_DD_FLAG_WRITE_PROTECT_BIT 5 -#define MTIP_DD_FLAG_OVER_TEMP_BIT 6 -#define MTIP_DD_FLAG_REBUILD_FAILED_BIT 7 +#define MTIP_DDF_REMOVE_PENDING_BIT 1 +#define MTIP_DDF_RESUME_BIT 2 +#define MTIP_DDF_CLEANUP_BIT 3 +#define MTIP_DDF_INIT_DONE_BIT 4 + +#define MTIP_DDF_WRITE_PROTECT_BIT 5 +#define MTIP_DDF_OVER_TEMP_BIT 6 +#define MTIP_DDF_REBUILD_FAILED_BIT 7 __packed struct smart_attr{ u8 attr_id; -- cgit v0.10.2 From c74b0f586fa3cbc92ca451836fd75ae7a3fa85ac Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:39 +0200 Subject: mtip32xx: fix handling of commands in various scenarios * If a ncq command time out and a non-ncq command is active, skip restart port * Queue(pause) ncq commands during operations spanning more than one non-ncq commands - secure erase, download microcode * When a non-ncq command is active, allow incoming non-ncq commands to wait instead of failing back * Changed timeout for download microcode and smart commands * If the device in write protect mode, fail all writes (do not send to device) * Set maximum retries to 2 Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index e57864a..47404ef 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -436,7 +436,8 @@ static void mtip_init_port(struct mtip_port *port) writel(0xFFFFFFFF, port->completed[i]); /* Clear any pending interrupts for this port */ - writel(readl(port->mmio + PORT_IRQ_STAT), port->mmio + PORT_IRQ_STAT); + writel(readl(port->dd->mmio + PORT_IRQ_STAT), + port->dd->mmio + PORT_IRQ_STAT); /* Clear any pending interrupts on the HBA. */ writel(readl(port->dd->mmio + HOST_IRQ_STAT), @@ -541,6 +542,7 @@ static void mtip_timeout_function(unsigned long int data) int tag, cmdto_cnt = 0; unsigned int bit, group; unsigned int num_command_slots = port->dd->slot_groups * 32; + unsigned long to; if (unlikely(!port)) return; @@ -605,7 +607,7 @@ static void mtip_timeout_function(unsigned long int data) } } - if (cmdto_cnt) { + if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { dev_warn(&port->dd->pdev->dev, "%d commands timed out: restarting port", cmdto_cnt); @@ -614,6 +616,21 @@ static void mtip_timeout_function(unsigned long int data) wake_up_interruptible(&port->svc_wait); } + if (port->ic_pause_timer) { + to = port->ic_pause_timer + msecs_to_jiffies(1000); + if (time_after(jiffies, to)) { + if (!test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { + port->ic_pause_timer = 0; + clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); + clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); + wake_up_interruptible(&port->svc_wait); + } + + + } + } + /* Restart the timer */ mod_timer(&port->cmd_timer, jiffies + msecs_to_jiffies(MTIP_TIMEOUT_CHECK_PERIOD)); @@ -1105,6 +1122,39 @@ static void mtip_issue_non_ncq_command(struct mtip_port *port, int tag) port->cmd_issue[MTIP_TAG_INDEX(tag)]); } +static bool mtip_pause_ncq(struct mtip_port *port, + struct host_to_dev_fis *fis) +{ + struct host_to_dev_fis *reply; + unsigned long task_file_data; + + reply = port->rxfis + RX_FIS_D2H_REG; + task_file_data = readl(port->mmio+PORT_TFDATA); + + if ((task_file_data & 1) || (fis->command == ATA_CMD_SEC_ERASE_UNIT)) + return false; + + if (fis->command == ATA_CMD_SEC_ERASE_PREP) { + set_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = jiffies; + return true; + } else if ((fis->command == ATA_CMD_DOWNLOAD_MICRO) && + (fis->features == 0x03)) { + set_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = jiffies; + return true; + } else if ((fis->command == ATA_CMD_SEC_ERASE_UNIT) || + ((fis->command == 0xFC) && + (fis->features == 0x27 || fis->features == 0x72 || + fis->features == 0x62 || fis->features == 0x26))) { + /* Com reset after secure erase or lowlevel format */ + mtip_restart_port(port); + return false; + } + + return false; +} + /* * Wait for port to quiesce * @@ -1176,8 +1226,9 @@ static int mtip_exec_internal_command(struct mtip_port *port, { struct mtip_cmd_sg *command_sg; DECLARE_COMPLETION_ONSTACK(wait); - int rv = 0; + int rv = 0, ready2go = 1; struct mtip_cmd *int_cmd = &port->commands[MTIP_TAG_INTERNAL]; + unsigned long to; /* Make sure the buffer is 8 byte aligned. This is asic specific. */ if (buffer & 0x00000007) { @@ -1186,13 +1237,26 @@ static int mtip_exec_internal_command(struct mtip_port *port, return -EFAULT; } - /* Only one internal command should be running at a time */ - if (test_and_set_bit(MTIP_TAG_INTERNAL, port->allocated)) { + to = jiffies + msecs_to_jiffies(timeout); + do { + ready2go = !test_and_set_bit(MTIP_TAG_INTERNAL, + port->allocated); + if (ready2go) + break; + mdelay(100); + } while (time_before(jiffies, to)); + if (!ready2go) { dev_warn(&port->dd->pdev->dev, - "Internal command already active\n"); + "Internal cmd active. new cmd [%02X]\n", fis->command); return -EBUSY; } set_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); + port->ic_pause_timer = 0; + + if (fis->command == ATA_CMD_SEC_ERASE_UNIT) + clear_bit(MTIP_PF_SE_ACTIVE_BIT, &port->flags); + else if (fis->command == ATA_CMD_DOWNLOAD_MICRO) + clear_bit(MTIP_PF_DM_ACTIVE_BIT, &port->flags); if (atomic == GFP_KERNEL) { if (fis->command != ATA_CMD_STANDBYNOW1) { @@ -1314,6 +1378,10 @@ exec_ic_exit: /* Clear the allocated and active bits for the internal command. */ atomic_set(&int_cmd->active, 0); release_slot(port, MTIP_TAG_INTERNAL); + if (rv >= 0 && mtip_pause_ncq(port, fis)) { + /* NCQ paused */ + return rv; + } clear_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); @@ -1767,8 +1835,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) fis.cyl_hi = command[5]; fis.device = command[6] & ~0x10; /* Clear the dev bit*/ - - dbg_printk(MTIP_DRV_NAME "%s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", + dbg_printk(MTIP_DRV_NAME " %s: User Command: cmd %x, feat %x, nsect %x, sect %x, lcyl %x, hcyl %x, sel %x\n", __func__, command[0], command[1], @@ -1795,7 +1862,7 @@ static int exec_drive_task(struct mtip_port *port, u8 *command) command[4] = reply->cyl_low; command[5] = reply->cyl_hi; - dbg_printk(MTIP_DRV_NAME "%s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", + dbg_printk(MTIP_DRV_NAME " %s: Completion Status: stat %x, err %x , cyl_lo %x cyl_hi %x\n", __func__, command[0], command[1], @@ -1838,7 +1905,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, } dbg_printk(MTIP_DRV_NAME - "%s: User Command: cmd %x, sect %x, " + " %s: User Command: cmd %x, sect %x, " "feat %x, sectcnt %x\n", __func__, command[0], @@ -1867,7 +1934,7 @@ static int exec_drive_command(struct mtip_port *port, u8 *command, command[2] = command[3]; dbg_printk(MTIP_DRV_NAME - "%s: Completion Status: stat %x, " + " %s: Completion Status: stat %x, " "err %x, cmd %x\n", __func__, command[0], @@ -2070,9 +2137,10 @@ static int exec_drive_taskfile(struct driver_data *dd, } dbg_printk(MTIP_DRV_NAME - "taskfile: cmd %x, feat %x, nsect %x," + " %s: cmd %x, feat %x, nsect %x," " sect/lbal %x, lcyl/lbam %x, hcyl/lbah %x," " head/dev %x\n", + __func__, fis.command, fis.features, fis.sect_count, @@ -2083,8 +2151,8 @@ static int exec_drive_taskfile(struct driver_data *dd, switch (fis.command) { case ATA_CMD_DOWNLOAD_MICRO: - /* Change timeout for Download Microcode to 60 seconds.*/ - timeout = 60000; + /* Change timeout for Download Microcode to 2 minutes */ + timeout = 120000; break; case ATA_CMD_SEC_ERASE_UNIT: /* Change timeout for Security Erase Unit to 4 minutes.*/ @@ -2100,8 +2168,8 @@ static int exec_drive_taskfile(struct driver_data *dd, timeout = 10000; break; case ATA_CMD_SMART: - /* Change timeout for vendor unique command to 10 secs */ - timeout = 10000; + /* Change timeout for vendor unique command to 15 secs */ + timeout = 15000; break; default: timeout = MTIP_IOCTL_COMMAND_TIMEOUT_MS; @@ -2163,18 +2231,8 @@ static int exec_drive_taskfile(struct driver_data *dd, req_task->hob_ports[1] = reply->features_ex; req_task->hob_ports[2] = reply->sect_cnt_ex; } - - /* Com rest after secure erase or lowlevel format */ - if (((fis.command == ATA_CMD_SEC_ERASE_UNIT) || - ((fis.command == 0xFC) && - (fis.features == 0x27 || fis.features == 0x72 || - fis.features == 0x62 || fis.features == 0x26))) && - !(reply->command & 1)) { - mtip_restart_port(dd->port); - } - dbg_printk(MTIP_DRV_NAME - "%s: Completion: stat %x," + " %s: Completion: stat %x," "err %x, sect_cnt %x, lbalo %x," "lbamid %x, lbahi %x, dev %x\n", __func__, @@ -2396,8 +2454,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, * To prevent this command from being issued * if an internal command is in progress or error handling is active. */ - if (unlikely(test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) || - test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags))) { + if (port->flags & MTIP_PF_PAUSE_IO) { set_bit(tag, port->cmds_to_issue); set_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags); return; @@ -2726,8 +2783,7 @@ static int mtip_service_thread(void *data) * is in progress nor error handling is active */ wait_event_interruptible(port->svc_wait, (port->flags) && - !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags) && - !test_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags)); + !(port->flags & MTIP_PF_PAUSE_IO)); if (kthread_should_stop()) break; @@ -2735,6 +2791,7 @@ static int mtip_service_thread(void *data) if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) break; + set_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); if (test_bit(MTIP_PF_ISSUE_CMDS_BIT, &port->flags)) { slot = 1; @@ -2773,7 +2830,7 @@ static int mtip_service_thread(void *data) } clear_bit(MTIP_PF_SVC_THD_ACTIVE_BIT, &port->flags); - if (test_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &port->flags)) + if (test_bit(MTIP_PF_SVC_THD_STOP_BIT, &port->flags)) break; } return 0; @@ -3421,9 +3478,22 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) int nents = 0; int tag = 0; - if (test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag)) { - bio_endio(bio, -ENXIO); - return; + if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { + if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, + &dd->dd_flag))) { + bio_endio(bio, -ENXIO); + return; + } + if (unlikely(test_bit(MTIP_DDF_OVER_TEMP_BIT, &dd->dd_flag))) { + bio_endio(bio, -ENODATA); + return; + } + if (unlikely(test_bit(MTIP_DDF_WRITE_PROTECT_BIT, + &dd->dd_flag) && + bio_data_dir(bio))) { + bio_endio(bio, -ENODATA); + return; + } } if (unlikely(!bio_has_data(bio))) { @@ -3599,7 +3669,7 @@ start_service_thread: dd, thd_name); if (IS_ERR(dd->mtip_svc_handler)) { - printk(KERN_ERR "mtip32xx: service thread failed to start\n"); + dev_err(&dd->pdev->dev, "service thread failed to start\n"); dd->mtip_svc_handler = NULL; rv = -EFAULT; goto kthread_run_error; @@ -3648,7 +3718,7 @@ static int mtip_block_remove(struct driver_data *dd) struct kobject *kobj; if (dd->mtip_svc_handler) { - set_bit(MTIP_PF_SVC_THD_SHOULD_STOP_BIT, &dd->port->flags); + set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags); wake_up_interruptible(&dd->port->svc_wait); kthread_stop(dd->mtip_svc_handler); } diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 5ad2d79..4ef5833 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -34,8 +34,8 @@ /* offset of Device Control register in PCIe extended capabilites space */ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 -/* # of times to retry timed out IOs */ -#define MTIP_MAX_RETRIES 5 +/* # of times to retry timed out/failed IOs */ +#define MTIP_MAX_RETRIES 2 /* Various timeout values in ms */ #define MTIP_NCQ_COMMAND_TIMEOUT_MS 5000 @@ -114,22 +114,32 @@ #define __force_bit2int (unsigned int __force) /* below are bit numbers in 'flags' defined in mtip_port */ -#define MTIP_PF_IC_ACTIVE_BIT 0 -#define MTIP_PF_EH_ACTIVE_BIT 1 -#define MTIP_PF_SVC_THD_ACTIVE_BIT 2 -#define MTIP_PF_ISSUE_CMDS_BIT 4 -#define MTIP_PF_REBUILD_BIT 5 -#define MTIP_PF_SVC_THD_SHOULD_STOP_BIT 8 +#define MTIP_PF_IC_ACTIVE_BIT 0 /* pio/ioctl */ +#define MTIP_PF_EH_ACTIVE_BIT 1 /* error handling */ +#define MTIP_PF_SE_ACTIVE_BIT 2 /* secure erase */ +#define MTIP_PF_DM_ACTIVE_BIT 3 /* download microcde */ +#define MTIP_PF_PAUSE_IO ((1 << MTIP_PF_IC_ACTIVE_BIT) | \ + (1 << MTIP_PF_EH_ACTIVE_BIT) | \ + (1 << MTIP_PF_SE_ACTIVE_BIT) | \ + (1 << MTIP_PF_DM_ACTIVE_BIT)) + +#define MTIP_PF_SVC_THD_ACTIVE_BIT 4 +#define MTIP_PF_ISSUE_CMDS_BIT 5 +#define MTIP_PF_REBUILD_BIT 6 +#define MTIP_PF_SVC_THD_STOP_BIT 8 /* below are bit numbers in 'dd_flag' defined in driver_data */ #define MTIP_DDF_REMOVE_PENDING_BIT 1 -#define MTIP_DDF_RESUME_BIT 2 -#define MTIP_DDF_CLEANUP_BIT 3 -#define MTIP_DDF_INIT_DONE_BIT 4 +#define MTIP_DDF_OVER_TEMP_BIT 2 +#define MTIP_DDF_WRITE_PROTECT_BIT 3 +#define MTIP_DDF_STOP_IO ((1 << MTIP_DDF_REMOVE_PENDING_BIT) | \ + (1 << MTIP_DDF_OVER_TEMP_BIT) | \ + (1 << MTIP_DDF_WRITE_PROTECT_BIT)) -#define MTIP_DDF_WRITE_PROTECT_BIT 5 -#define MTIP_DDF_OVER_TEMP_BIT 6 -#define MTIP_DDF_REBUILD_FAILED_BIT 7 +#define MTIP_DDF_CLEANUP_BIT 5 +#define MTIP_DDF_RESUME_BIT 6 +#define MTIP_DDF_INIT_DONE_BIT 7 +#define MTIP_DDF_REBUILD_FAILED_BIT 8 __packed struct smart_attr{ u8 attr_id; @@ -393,6 +403,7 @@ struct mtip_port { * Timer used to complete commands that have been active for too long. */ struct timer_list cmd_timer; + unsigned long ic_pause_timer; /* * Semaphore used to block threads if there are no * command slots available. -- cgit v0.10.2 From 95fea2f1d90626498e2495a81fe5aab7fba9fb3f Mon Sep 17 00:00:00 2001 From: Asai Thambi S P Date: Mon, 9 Apr 2012 08:35:39 +0200 Subject: mtip32xx: dump tagmap on failure Dump tagmap on failure, instead of individual tags. Signed-off-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 47404ef..00f9fc9 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -526,6 +526,25 @@ static void mtip_restart_port(struct mtip_port *port) } /* + * Helper function for tag logging + */ +static void print_tags(struct driver_data *dd, + char *msg, + unsigned long *tagbits, + int cnt) +{ + unsigned char tagmap[128]; + int group, tagmap_len = 0; + + memset(tagmap, 0, sizeof(tagmap)); + for (group = SLOTBITS_IN_LONGS; group > 0; group--) + tagmap_len = sprintf(tagmap + tagmap_len, "%016lX ", + tagbits[group-1]); + dev_warn(&dd->pdev->dev, + "%d command(s) %s: tagmap [%s]", cnt, msg, tagmap); +} + +/* * Called periodically to see if any read/write commands are * taking too long to complete. * @@ -542,7 +561,7 @@ static void mtip_timeout_function(unsigned long int data) int tag, cmdto_cnt = 0; unsigned int bit, group; unsigned int num_command_slots = port->dd->slot_groups * 32; - unsigned long to; + unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; if (unlikely(!port)) return; @@ -552,6 +571,8 @@ static void mtip_timeout_function(unsigned long int data) jiffies + msecs_to_jiffies(30000)); return; } + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); for (tag = 0; tag < num_command_slots; tag++) { /* @@ -569,9 +590,7 @@ static void mtip_timeout_function(unsigned long int data) command = &port->commands[tag]; fis = (struct host_to_dev_fis *) command->command; - dev_warn(&port->dd->pdev->dev, - "Timeout for command tag %d\n", tag); - + set_bit(tag, tagaccum); cmdto_cnt++; if (cmdto_cnt == 1) set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); @@ -608,9 +627,8 @@ static void mtip_timeout_function(unsigned long int data) } if (cmdto_cnt && !test_bit(MTIP_PF_IC_ACTIVE_BIT, &port->flags)) { - dev_warn(&port->dd->pdev->dev, - "%d commands timed out: restarting port", - cmdto_cnt); + print_tags(port->dd, "timed out", tagaccum, cmdto_cnt); + mtip_restart_port(port); clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); wake_up_interruptible(&port->svc_wait); @@ -733,23 +751,6 @@ static void mtip_null_completion(struct mtip_port *port, return; } -/* - * Helper function for tag logging - */ -static void print_tags(struct driver_data *dd, - char *msg, - unsigned long *tagbits) -{ - unsigned int tag, count = 0; - - for (tag = 0; tag < (dd->slot_groups) * 32; tag++) { - if (test_bit(tag, tagbits)) - count++; - } - if (count) - dev_info(&dd->pdev->dev, "%s [%i tags]\n", msg, count); -} - static int mtip_read_log_page(struct mtip_port *port, u8 page, u16 *buffer, dma_addr_t buffer_dma, unsigned int sectors); static int mtip_get_smart_attr(struct mtip_port *port, unsigned int id, @@ -770,6 +771,7 @@ static void mtip_handle_tfe(struct driver_data *dd) u32 completed; struct host_to_dev_fis *fis; unsigned long tagaccum[SLOTBITS_IN_LONGS]; + unsigned int cmd_cnt = 0; unsigned char *buf; char *fail_reason = NULL; int fail_all_ncq_write = 0, fail_all_ncq_cmds = 0; @@ -781,6 +783,9 @@ static void mtip_handle_tfe(struct driver_data *dd) /* Stop the timer to prevent command timeouts. */ del_timer(&port->cmd_timer); + /* clear the tag accumulator */ + memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + /* Set eh_active */ set_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); @@ -791,9 +796,6 @@ static void mtip_handle_tfe(struct driver_data *dd) /* clear completed status register in the hardware.*/ writel(completed, port->completed[group]); - /* clear the tag accumulator */ - memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); - /* Process successfully completed commands */ for (bit = 0; bit < 32 && completed; bit++) { if (!(completed & (1<commands[tag]; if (likely(cmd->comp_func)) { set_bit(tag, tagaccum); + cmd_cnt++; atomic_set(&cmd->active, 0); cmd->comp_func(port, tag, @@ -824,7 +827,8 @@ static void mtip_handle_tfe(struct driver_data *dd) } } } - print_tags(dd, "TFE tags completed:", tagaccum); + + print_tags(dd, "completed (TFE)", tagaccum, cmd_cnt); /* Restart the port */ mdelay(20); @@ -934,7 +938,7 @@ static void mtip_handle_tfe(struct driver_data *dd) tag); } } - print_tags(dd, "TFE tags reissued:", tagaccum); + print_tags(dd, "reissued (TFE)", tagaccum, cmd_cnt); /* clear eh_active */ clear_bit(MTIP_PF_EH_ACTIVE_BIT, &port->flags); -- cgit v0.10.2 From 556a0442e08a8bc8541587a349cbf26ed14ec6de Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Fri, 6 Apr 2012 18:38:18 -0300 Subject: [media] dvb_frontend: regression fix: userspace ABI broken for xine The commit e399ce77e6e has broken the DVB ABI for xine: The problem is that xine is expecting every event after a successful FE_SET_FRONTEND ioctl to have a non-zero frequency parameter, regardless of whether the tuning process has LOCKed yet. What used to happen is that the events inherited the initial tuning parameters from the FE_SET_FRONTEND call. However, the fepriv->parameters_out struct is now not initialised until the status contains the FE_HAS_LOCK bit. You might argue that this behaviour is intentional, except that if an application other than xine uses the DVB adapter and manages to set the parameters_out.frequency field to something other than zero, then xine no longer has any problems until either the adapter is replugged or the kernel modules reloaded. This can only mean that the fepriv->parameters_out struct still contains the (stale) tuning information from the previous application. Signed-off-by: Chris Rankin Cc: stable@kernel.org # for kernel version 3.3 Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 4555baa..e721975 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -143,6 +143,8 @@ struct dvb_frontend_private { static void dvb_frontend_wakeup(struct dvb_frontend *fe); static int dtv_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p_out); +static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p); static bool has_get_frontend(struct dvb_frontend *fe) { @@ -697,6 +699,7 @@ restart: fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; fepriv->delay = HZ / 2; } + dtv_property_legacy_params_sync(fe, &fepriv->parameters_out); fe->ops.read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); /* update event list */ @@ -1833,6 +1836,13 @@ static int dtv_set_frontend(struct dvb_frontend *fe) return -EINVAL; /* + * Initialize output parameters to match the values given by + * the user. FE_SET_FRONTEND triggers an initial frontend event + * with status = 0, which copies output parameters to userspace. + */ + dtv_property_legacy_params_sync(fe, &fepriv->parameters_out); + + /* * Be sure that the bandwidth will be filled for all * non-satellite systems, as tuners need to know what * low pass/Nyquist half filter should be applied, in -- cgit v0.10.2 From bc169e35e3a72c6888b7d12f50f2c4063436d834 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 31 Mar 2012 05:18:19 -0300 Subject: [media] ivtv: Fix AUDIO_(BILINGUAL_)CHANNEL_SELECT regression When I converted ivtv to the new decoder API I introduced a regression in the support of the old channel select API. Thanks to Martin Dauskardt for reporting this. Signed-off-by: Hans Verkuil Reviewed-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 5452bee..989e556 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1763,13 +1763,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n"); if (iarg > AUDIO_STEREO_SWAPPED) return -EINVAL; - return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg); + return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg + 1); case AUDIO_BILINGUAL_CHANNEL_SELECT: IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n"); if (iarg > AUDIO_STEREO_SWAPPED) return -EINVAL; - return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg); + return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg + 1); default: return -EINVAL; -- cgit v0.10.2 From 4da28766140449e04270246fae310c137180652d Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 25 Mar 2012 06:57:49 -0300 Subject: [media] it913x: fix firmware loading errors On some systems the device does not respond or give obscure values after cold, warm or firmware reboot. This patch retries to get chip version and type 5 times. If it fails it applies chip version 0x1 and type 0x9135. This patch does not fix warm cycle problems from other operating systems and indeed the reverse applies. Users should power off cold boot. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index 3b7b102..482d249 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c @@ -238,12 +238,27 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg) static u32 it913x_query(struct usb_device *udev, u8 pro) { - int ret; + int ret, i; u8 data[4]; - ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, - 0x1222, 0, &data[0], 3); + u8 ver; + + for (i = 0; i < 5; i++) { + ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, + 0x1222, 0, &data[0], 3); + ver = data[0]; + if (ver > 0 && ver < 3) + break; + msleep(100); + } - it913x_config.chip_ver = data[0]; + if (ver < 1 || ver > 2) { + info("Failed to identify chip version applying 1"); + it913x_config.chip_ver = 0x1; + it913x_config.chip_type = 0x9135; + return 0; + } + + it913x_config.chip_ver = ver; it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, @@ -660,30 +675,41 @@ static int it913x_download_firmware(struct usb_device *udev, if ((packet_size > min_pkt) || (i == fw->size)) { fw_data = (u8 *)(fw->data + pos); pos += packet_size; - if (packet_size > 0) - ret |= it913x_io(udev, WRITE_DATA, + if (packet_size > 0) { + ret = it913x_io(udev, WRITE_DATA, DEV_0, CMD_SCATTER_WRITE, 0, 0, fw_data, packet_size); + if (ret < 0) + break; + } udelay(1000); } } i++; } - ret |= it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); - - msleep(100); - if (ret < 0) - info("FRM Firmware Download Failed (%04x)" , ret); + info("FRM Firmware Download Failed (%d)" , ret); else info("FRM Firmware Download Completed - Resetting Device"); - ret |= it913x_return_status(udev); + msleep(30); + + ret = it913x_io(udev, WRITE_CMD, DEV_0, CMD_BOOT, 0, 0, NULL, 0); + if (ret < 0) + info("FRM Device not responding to reboot"); + + ret = it913x_return_status(udev); + if (ret == 0) { + info("FRM Failed to reboot device"); + return -ENODEV; + } msleep(30); - ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); + ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); + + msleep(30); /* Tuner function */ if (it913x_config.dual_mode) @@ -901,5 +927,5 @@ module_usb_driver(it913x_driver); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("it913x USB 2 Driver"); -MODULE_VERSION("1.27"); +MODULE_VERSION("1.28"); MODULE_LICENSE("GPL"); -- cgit v0.10.2 From c065f5b4ee4487bbd411049be6eea1b59a90db96 Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Tue, 27 Mar 2012 12:53:19 -0300 Subject: [media] dvb_frontend: fix compiler warning has_get_frontend() should return a boolean, not a pointer. Signed-off-by: Hans Petter Selasky Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index e721975..39696c6 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -148,7 +148,7 @@ static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, static bool has_get_frontend(struct dvb_frontend *fe) { - return fe->ops.get_frontend; + return fe->ops.get_frontend != NULL; } /* -- cgit v0.10.2 From d3a92d624806a7964ca3122f917ff2ba69e4cdd8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 1 Apr 2012 15:24:48 -0300 Subject: [media] Drivers/media/radio: Fix build error On Sunday, April 01, 2012 21:09:34 Tracey Dent wrote: > radio-maxiradio depends on SND_FM801_TEA575X_BOOL to build or will > result in an build error such as: > > Kernel: arch/x86/boot/bzImage is ready (#1) > ERROR: "snd_tea575x_init" [drivers/media/radio/radio-maxiradio.ko] undefined! > ERROR: "snd_tea575x_exit" [drivers/media/radio/radio-maxiradio.ko] undefined! > WARNING: modpost: Found 6 section mismatch(es). > To see full details build your kernel with: > 'make CONFIG_DEBUG_SECTION_MISMATCH=y' > make[1]: *** [__modpost] Error 1 > make: *** [modules] Error 2 > > Select CONFIG_SND_TEA575X to fixes problem and enable > the driver to be built as desired. > > v2: > instead of selecting CONFIG_SND_FM801_TEA575X_BOOL, select > CONFIG_SND_TEA575X, which in turns selects CONFIG_SND_FM801_TEA575X_BOOL > and any other dependencies for it to build. No, this is the correct patch: RADIO_MAXIRADIO should be treated just like RADIO_SF16FMR2, I just didn't realize at the time that it had to be added as a SND_TEA575X dependency. Signed-off-by: Hans Verkuil Tested-by: Shea Levy Acked-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 8816804..5ca0939 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -2,8 +2,8 @@ config SND_TEA575X tristate - depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2 - default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2 + depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2 || RADIO_MAXIRADIO + default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2 || RADIO_MAXIRADIO menuconfig SND_PCI bool "PCI sound devices" -- cgit v0.10.2 From ed0ee0ce0a3224dab5caa088a5f8b6df25924276 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 27 Mar 2012 05:51:00 -0300 Subject: [media] uvcvideo: Fix race-related crash in uvc_video_clock_update() The driver frees the clock samples buffer before stopping the video buffers queue. If a DQBUF call arrives in-between, uvc_video_clock_update() will be called with a NULL clock samples buffer, leading to a crash. This occurs very frequently when using the webcam with the flash browser plugin. Move clock initialization/cleanup to uvc_video_enable() in order to free the clock samples buffer after the queue is stopped. Make sure the clock is reset at resume time to avoid miscalculating timestamps. Signed-off-by: Laurent Pinchart Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 4a44f9a..b76b0ac 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -468,22 +468,30 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf, spin_unlock_irqrestore(&stream->clock.lock, flags); } -static int uvc_video_clock_init(struct uvc_streaming *stream) +static void uvc_video_clock_reset(struct uvc_streaming *stream) { struct uvc_clock *clock = &stream->clock; - spin_lock_init(&clock->lock); clock->head = 0; clock->count = 0; - clock->size = 32; clock->last_sof = -1; clock->sof_offset = -1; +} + +static int uvc_video_clock_init(struct uvc_streaming *stream) +{ + struct uvc_clock *clock = &stream->clock; + + spin_lock_init(&clock->lock); + clock->size = 32; clock->samples = kmalloc(clock->size * sizeof(*clock->samples), GFP_KERNEL); if (clock->samples == NULL) return -ENOMEM; + uvc_video_clock_reset(stream); + return 0; } @@ -1424,8 +1432,6 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) if (free_buffers) uvc_free_urb_buffers(stream); - - uvc_video_clock_cleanup(stream); } /* @@ -1555,10 +1561,6 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) uvc_video_stats_start(stream); - ret = uvc_video_clock_init(stream); - if (ret < 0) - return ret; - if (intf->num_altsetting > 1) { struct usb_host_endpoint *best_ep = NULL; unsigned int best_psize = 3 * 1024; @@ -1683,6 +1685,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) stream->frozen = 0; + uvc_video_clock_reset(stream); + ret = uvc_commit_video(stream, &stream->ctrl); if (ret < 0) { uvc_queue_enable(&stream->queue, 0); @@ -1819,25 +1823,35 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) uvc_uninit_video(stream, 1); usb_set_interface(stream->dev->udev, stream->intfnum, 0); uvc_queue_enable(&stream->queue, 0); + uvc_video_clock_cleanup(stream); return 0; } - ret = uvc_queue_enable(&stream->queue, 1); + ret = uvc_video_clock_init(stream); if (ret < 0) return ret; + ret = uvc_queue_enable(&stream->queue, 1); + if (ret < 0) + goto error_queue; + /* Commit the streaming parameters. */ ret = uvc_commit_video(stream, &stream->ctrl); - if (ret < 0) { - uvc_queue_enable(&stream->queue, 0); - return ret; - } + if (ret < 0) + goto error_commit; ret = uvc_init_video(stream, GFP_KERNEL); - if (ret < 0) { - usb_set_interface(stream->dev->udev, stream->intfnum, 0); - uvc_queue_enable(&stream->queue, 0); - } + if (ret < 0) + goto error_video; + + return 0; + +error_video: + usb_set_interface(stream->dev->udev, stream->intfnum, 0); +error_commit: + uvc_queue_enable(&stream->queue, 0); +error_queue: + uvc_video_clock_cleanup(stream); return ret; } -- cgit v0.10.2 From 6ee0b693bdb8ec56689e0d1cc533b16466fda048 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Sun, 1 Apr 2012 17:25:06 +0000 Subject: netfilter: nf_ct_tcp: don't scale the size of the window up twice For a picked up connection, the window win is scaled twice: one is by the initialization code, and the other is by the sender updating code. I use the temporary variable swin instead of modifying the variable win. Signed-off-by: Changli Gao Acked-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 361eade..0d07a1d 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -584,8 +584,8 @@ static bool tcp_in_window(const struct nf_conn *ct, * Let's try to use the data from the packet. */ sender->td_end = end; - win <<= sender->td_scale; - sender->td_maxwin = (win == 0 ? 1 : win); + swin = win << sender->td_scale; + sender->td_maxwin = (swin == 0 ? 1 : swin); sender->td_maxend = end + sender->td_maxwin; /* * We haven't seen traffic in the other direction yet -- cgit v0.10.2 From 95ad2f873d5d404dc9ebc2377de0b762346346c0 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 6 Apr 2012 18:12:54 +0200 Subject: netfilter: ip6_tables: ip6t_ext_hdr is now static inline We may hit this in xt_LOG: net/built-in.o:xt_LOG.c:function dump_ipv6_packet: error: undefined reference to 'ip6t_ext_hdr' happens with these config options: CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_IP6_NF_IPTABLES=m ip6t_ext_hdr is fairly small and it is called in the packet path. Make it static inline. Reported-by: Simon Kirby Signed-off-by: Pablo Neira Ayuso diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index f549adc..1bc898b 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -287,7 +287,17 @@ extern unsigned int ip6t_do_table(struct sk_buff *skb, struct xt_table *table); /* Check for an extension */ -extern int ip6t_ext_hdr(u8 nexthdr); +static inline int +ip6t_ext_hdr(u8 nexthdr) +{ return (nexthdr == IPPROTO_HOPOPTS) || + (nexthdr == IPPROTO_ROUTING) || + (nexthdr == IPPROTO_FRAGMENT) || + (nexthdr == IPPROTO_ESP) || + (nexthdr == IPPROTO_AH) || + (nexthdr == IPPROTO_NONE) || + (nexthdr == IPPROTO_DSTOPTS); +} + /* find specified header and get offset to it */ extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target, unsigned short *fragoff); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 94874b0..9d4e155 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -78,19 +78,6 @@ EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table); Hence the start of any table is given by get_table() below. */ -/* Check for an extension */ -int -ip6t_ext_hdr(u8 nexthdr) -{ - return (nexthdr == IPPROTO_HOPOPTS) || - (nexthdr == IPPROTO_ROUTING) || - (nexthdr == IPPROTO_FRAGMENT) || - (nexthdr == IPPROTO_ESP) || - (nexthdr == IPPROTO_AH) || - (nexthdr == IPPROTO_NONE) || - (nexthdr == IPPROTO_DSTOPTS); -} - /* Returns whether matches rule or not. */ /* Performance critical - called for every packet */ static inline bool @@ -2366,7 +2353,6 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); -EXPORT_SYMBOL(ip6t_ext_hdr); EXPORT_SYMBOL(ipv6_find_hdr); module_init(ip6_tables_init); -- cgit v0.10.2 From b78f29ca0516266431688c5eb42d39ce42ec039a Mon Sep 17 00:00:00 2001 From: Wang YanQing Date: Sun, 1 Apr 2012 08:54:02 +0800 Subject: video:uvesafb: Fix oops that uvesafb try to execute NX-protected page This patch fix the oops below that catched in my machine [ 81.560602] uvesafb: NVIDIA Corporation, GT216 Board - 0696a290, Chip Rev , OEM: NVIDIA, VBE v3.0 [ 81.609384] uvesafb: protected mode interface info at c000:d350 [ 81.609388] uvesafb: pmi: set display start = c00cd3b3, set palette = c00cd40e [ 81.609390] uvesafb: pmi: ports = 3b4 3b5 3ba 3c0 3c1 3c4 3c5 3c6 3c7 3c8 3c9 3cc 3ce 3cf 3d0 3d1 3d2 3d3 3d4 3d5 3da [ 81.614558] uvesafb: VBIOS/hardware doesn't support DDC transfers [ 81.614562] uvesafb: no monitor limits have been set, default refresh rate will be used [ 81.614994] uvesafb: scrolling: ypan using protected mode interface, yres_virtual=4915 [ 81.744147] kernel tried to execute NX-protected page - exploit attempt? (uid: 0) [ 81.744153] BUG: unable to handle kernel paging request at c00cd3b3 [ 81.744159] IP: [] 0xc00cd3b2 [ 81.744167] *pdpt = 00000000016d6001 *pde = 0000000001c7b067 *pte = 80000000000cd163 [ 81.744171] Oops: 0011 [#1] SMP [ 81.744174] Modules linked in: uvesafb(+) cfbcopyarea cfbimgblt cfbfillrect [ 81.744178] [ 81.744181] Pid: 3497, comm: modprobe Not tainted 3.3.0-rc4NX+ #71 Acer Aspire 4741 /Aspire 4741 [ 81.744185] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 [ 81.744187] EIP is at 0xc00cd3b3 [ 81.744189] EAX: 00004f07 EBX: 00000000 ECX: 00000000 EDX: 00000000 [ 81.744191] ESI: f763f000 EDI: f763f6e8 EBP: f57f3a0c ESP: f57f3a00 [ 81.744192] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 81.744195] Process modprobe (pid: 3497, ti=f57f2000 task=f748c600 task.ti=f57f2000) [ 81.744196] Stack: [ 81.744197] f82512c5 f759341c 00000000 f57f3a30 c124a9bc 00000001 00000001 000001e0 [ 81.744202] f8251280 f763f000 f7593400 00000000 f57f3a40 c12598dd f5c0c000 00000000 [ 81.744206] f57f3b10 c1255efe c125a21a 00000006 f763f09c 00000000 c1c6cb60 f7593400 [ 81.744210] Call Trace: [ 81.744215] [] ? uvesafb_pan_display+0x45/0x60 [uvesafb] [ 81.744222] [] fb_pan_display+0x10c/0x160 [ 81.744226] [] ? uvesafb_vbe_find_mode+0x180/0x180 [uvesafb] [ 81.744230] [] bit_update_start+0x1d/0x50 [ 81.744232] [] fbcon_switch+0x39e/0x550 [ 81.744235] [] ? bit_cursor+0x4ea/0x560 [ 81.744240] [] redraw_screen+0x12b/0x220 [ 81.744245] [] ? tty_do_resize+0x3b/0xc0 [ 81.744247] [] vc_do_resize+0x3d2/0x3e0 [ 81.744250] [] vc_resize+0x14/0x20 [ 81.744253] [] fbcon_init+0x29d/0x500 [ 81.744255] [] ? set_inverse_trans_unicode+0xe4/0x110 [ 81.744258] [] visual_init+0xb8/0x150 [ 81.744261] [] bind_con_driver+0x16c/0x360 [ 81.744264] [] ? register_con_driver+0x6e/0x190 [ 81.744267] [] take_over_console+0x41/0x50 [ 81.744269] [] fbcon_takeover+0x6a/0xd0 [ 81.744272] [] fbcon_event_notify+0x758/0x790 [ 81.744277] [] notifier_call_chain+0x42/0xb0 [ 81.744280] [] __blocking_notifier_call_chain+0x60/0x90 [ 81.744283] [] blocking_notifier_call_chain+0x1a/0x20 [ 81.744285] [] fb_notifier_call_chain+0x11/0x20 [ 81.744288] [] register_framebuffer+0x1d9/0x2b0 [ 81.744293] [] ? ioremap_wc+0x33/0x40 [ 81.744298] [] uvesafb_probe+0xaba/0xc40 [uvesafb] [ 81.744302] [] platform_drv_probe+0xf/0x20 [ 81.744306] [] driver_probe_device+0x68/0x170 [ 81.744309] [] __device_attach+0x41/0x50 [ 81.744313] [] bus_for_each_drv+0x48/0x70 [ 81.744316] [] device_attach+0x83/0xa0 [ 81.744319] [] ? __driver_attach+0x90/0x90 [ 81.744321] [] bus_probe_device+0x6f/0x90 [ 81.744324] [] device_add+0x5e5/0x680 [ 81.744329] [] ? kvasprintf+0x43/0x60 [ 81.744332] [] ? kobject_set_name_vargs+0x64/0x70 [ 81.744335] [] ? kobject_set_name_vargs+0x64/0x70 [ 81.744339] [] platform_device_add+0xff/0x1b0 [ 81.744343] [] uvesafb_init+0x50/0x9b [uvesafb] [ 81.744346] [] do_one_initcall+0x2f/0x170 [ 81.744350] [] ? uvesafb_is_valid_mode+0x66/0x66 [uvesafb] [ 81.744355] [] sys_init_module+0xf4/0x1410 [ 81.744359] [] ? vfsmount_lock_local_unlock_cpu+0x30/0x30 [ 81.744363] [] sysenter_do_call+0x12/0x36 [ 81.744365] Code: f5 00 00 00 32 f6 66 8b da 66 d1 e3 66 ba d4 03 8a e3 b0 1c 66 ef b0 1e 66 ef 8a e7 b0 1d 66 ef b0 1f 66 ef e8 fa 00 00 00 61 c3 <60> e8 c8 00 00 00 66 8b f3 66 8b da 66 ba d4 03 b0 0c 8a e5 66 [ 81.744388] EIP: [] 0xc00cd3b3 SS:ESP 0068:f57f3a00 [ 81.744391] CR2: 00000000c00cd3b3 [ 81.744393] ---[ end trace 18b2c87c925b54d6 ]--- Signed-off-by: Wang YanQing Cc: Michal Januszewski Cc: Alan Cox Signed-off-by: Florian Tobias Schandinat Cc: stable@vger.kernel.org diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 260cca7..26e83d7 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -815,8 +815,15 @@ static int __devinit uvesafb_vbe_init(struct fb_info *info) par->pmi_setpal = pmi_setpal; par->ypan = ypan; - if (par->pmi_setpal || par->ypan) - uvesafb_vbe_getpmi(task, par); + if (par->pmi_setpal || par->ypan) { + if (__supported_pte_mask & _PAGE_NX) { + par->pmi_setpal = par->ypan = 0; + printk(KERN_WARNING "uvesafb: NX protection is actively." + "We have better not to use the PMI.\n"); + } else { + uvesafb_vbe_getpmi(task, par); + } + } #else /* The protected mode interface is not available on non-x86. */ par->pmi_setpal = par->ypan = 0; -- cgit v0.10.2 From 388bc26226807fbcf4c626b81bb17a2e74aa4b1b Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 21 Mar 2012 17:22:22 +0530 Subject: omap-serial: Fix the error handling in the omap_serial probe The patch does the following - The pm_runtime_disable is called in the remove not in the error case of probe.The patch calls the pm_runtime_disable in the error case. - Calls pm_runtime_put in the error case. - The up is not freed in the error path. Fix the memory leak by using devm_* so that the memory need not be freed in the driver. - Also the iounmap is not called fix the same by calling using devm_ioremap. - Make the name of the error tags more meaningful. Cc: Mark Brown Cc: Govindraj.R Signed-off-by: Shubhrajyoti D Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 0121486..d00b38e 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1381,29 +1381,24 @@ static int serial_omap_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(mem->start, resource_size(mem), + if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), pdev->dev.driver->name)) { dev_err(&pdev->dev, "memory region already claimed\n"); return -EBUSY; } dma_rx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!dma_rx) { - ret = -EINVAL; - goto err; - } + if (!dma_rx) + return -ENXIO; dma_tx = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!dma_tx) { - ret = -EINVAL; - goto err; - } + if (!dma_tx) + return -ENXIO; + + up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL); + if (!up) + return -ENOMEM; - up = kzalloc(sizeof(*up), GFP_KERNEL); - if (up == NULL) { - ret = -ENOMEM; - goto do_release_region; - } up->pdev = pdev; up->port.dev = &pdev->dev; up->port.type = PORT_OMAP; @@ -1423,16 +1418,17 @@ static int serial_omap_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", up->port.line); ret = -ENODEV; - goto err; + goto err_port_line; } sprintf(up->name, "OMAP UART%d", up->port.line); up->port.mapbase = mem->start; - up->port.membase = ioremap(mem->start, resource_size(mem)); + up->port.membase = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); if (!up->port.membase) { dev_err(&pdev->dev, "can't ioremap UART\n"); ret = -ENOMEM; - goto err; + goto err_ioremap; } up->port.flags = omap_up_info->flags; @@ -1478,16 +1474,19 @@ static int serial_omap_probe(struct platform_device *pdev) ret = uart_add_one_port(&serial_omap_reg, &up->port); if (ret != 0) - goto do_release_region; + goto err_add_port; pm_runtime_put(&pdev->dev); platform_set_drvdata(pdev, up); return 0; -err: + +err_add_port: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); +err_ioremap: +err_port_line: dev_err(&pdev->dev, "[UART%d]: failure [%s]: %d\n", pdev->id, __func__, ret); -do_release_region: - release_mem_region(mem->start, resource_size(mem)); return ret; } @@ -1499,8 +1498,6 @@ static int serial_omap_remove(struct platform_device *dev) pm_runtime_disable(&up->pdev->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); - - kfree(up); } platform_set_drvdata(dev, NULL); -- cgit v0.10.2 From ef37ea34cac19ef46173b26ee47a102f3b987d1e Mon Sep 17 00:00:00 2001 From: Tilman Schmidt Date: Sun, 25 Mar 2012 19:12:37 +0200 Subject: isdn/gigaset: use gig_dbg() for debugging output The "TTY buffer in tty_port" patchset introduced an opencoded debug message in the Gigaset tty device if_close() function. Change it to use the gig_dbg() macro like everywhere else in the driver. Signed-off-by: Tilman Schmidt Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index b3d6ac1..a6d9fd2 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -176,7 +176,7 @@ static void if_close(struct tty_struct *tty, struct file *filp) struct cardstate *cs = tty->driver_data; if (!cs) { /* happens if we didn't find cs in open */ - printk(KERN_DEBUG "%s: no cardstate\n", __func__); + gig_dbg(DEBUG_IF, "%s: no cardstate", __func__); return; } -- cgit v0.10.2 From acede70d6561f2d042d9dbb153d9a3469479c0ed Mon Sep 17 00:00:00 2001 From: Yuriy Kozlov Date: Thu, 29 Mar 2012 09:55:27 +0200 Subject: tty: serial: altera_uart: Check for NULL platform_data in probe. Follow altera_jtag_uart. This fixes a crash if there is a mistake in the DTS. Signed-off-by: Yuriy Kozlov Signed-off-by: Tobias Klauser Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index e790375..1f03309 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -556,7 +556,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem) port->mapbase = res_mem->start; - else if (platp->mapbase) + else if (platp) port->mapbase = platp->mapbase; else return -EINVAL; @@ -564,7 +564,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res_irq) port->irq = res_irq->start; - else if (platp->irq) + else if (platp) port->irq = platp->irq; /* Check platform data first so we can override device node data */ -- cgit v0.10.2 From 57c3686842114de3b0c00633591e9605c46fb769 Mon Sep 17 00:00:00 2001 From: "Siftar, Gabe" Date: Thu, 29 Mar 2012 15:40:05 +0200 Subject: tty/serial: atmel_serial: fix RS485 half-duplex problem On our custom board, we are using RS485 in half-duplex mode on an AT91SAM9G45. SER_RS485_RX_DURING_TX is not set as we do not want to receive the data we transmit (our transceiver will receive transmitted data). Although the current driver attempts to disable and enable the receiver at the appropriate points, incoming data is still loaded into the receive register causing our code to receive the very last byte that was sent once the receiver is enabled. I ran this by Atmel support and they wrote: "The issue comes from the fact that you disable the PDC/DMA Reception and not the USART Reception channel. In your case, the[n] you will still receive data into the USART_RHR register, and maybe you [h]ave the overrun flag set. So please disable the USART reception channel." The following patch should force the driver to enable/disable the receiver via RXEN/RXDIS fields of the USART control register. It fixed the issue I was having. Signed-off-by: Gabe Siftar [nicolas.ferre@atmel.com: slightly modify commit message] Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index f9a6be7..3d7e1ee 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -389,6 +389,8 @@ static void atmel_start_rx(struct uart_port *port) { UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + UART_PUT_CR(port, ATMEL_US_RXEN); + if (atmel_use_dma_rx(port)) { /* enable PDC controller */ UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | @@ -404,6 +406,8 @@ static void atmel_start_rx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { + UART_PUT_CR(port, ATMEL_US_RXDIS); + if (atmel_use_dma_rx(port)) { /* disable PDC receive */ UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); -- cgit v0.10.2 From 5da527aafed2834852fc4fe21daeaeadf7c61af3 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 3 Apr 2012 03:18:23 +0200 Subject: printk(): add KERN_CONT where needed in hpet and vt code A prototype for kmsg records instead of a byte-stream buffer revealed a couple of missing printk(KERN_CONT ...) uses. Subsequent calls produce one record per printk() call, while all should have ended up in a single record. Instead of: ACPI: (supports S0 S5) ACPI: PCI Interrupt Link [LNKA] (IRQs 5 *10 11) hpet0: at MMIO 0xfed00000, IRQs 2 , 8 , 0 It prints: ACPI: (supports S0 S5 ) ACPI: PCI Interrupt Link [LNKA] (IRQs 5 *10 11 ) hpet0: at MMIO 0xfed00000, IRQs 2 , 8 , 0 Cc: Andrew Morton Cc: Len Brown Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 3845ab4..dfd7876 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -906,8 +906,8 @@ int hpet_alloc(struct hpet_data *hdp) hpetp->hp_which, hdp->hd_phys_address, hpetp->hp_ntimer > 1 ? "s" : ""); for (i = 0; i < hpetp->hp_ntimer; i++) - printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); - printk("\n"); + printk(KERN_CONT "%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); + printk(KERN_CONT "\n"); temp = hpetp->hp_tick_freq; remainder = do_div(temp, 1000000); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 3bdd4b1..2156188 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2932,11 +2932,10 @@ static int __init con_init(void) gotoxy(vc, vc->vc_x, vc->vc_y); csi_J(vc, 0); update_screen(vc); - pr_info("Console: %s %s %dx%d", + pr_info("Console: %s %s %dx%d\n", vc->vc_can_do_color ? "colour" : "mono", display_desc, vc->vc_cols, vc->vc_rows); printable = 1; - printk("\n"); console_unlock(); -- cgit v0.10.2 From 7b246a1d0dfe75346a22bf6589b858a0389e6df1 Mon Sep 17 00:00:00 2001 From: Kukjin Kim Date: Tue, 3 Apr 2012 18:14:24 -0700 Subject: serial: samsung: fix omission initialize ulcon in reset port fn() Fix omission initialize ulcon in s3c24xx_serial_resetport(), reset port function in drivers/tty/serial/samsung.c. It has been happened from commit 0dfb3b41("serial: samsung: merge all SoC specific port reset functions") Signed-off-by: Kukjin Kim Cc: stable [3.3] Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index de249d2..d8b0aee 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -982,6 +982,7 @@ static void s3c24xx_serial_resetport(struct uart_port *port, ucon &= ucon_mask; wr_regl(port, S3C2410_UCON, ucon | cfg->ucon); + wr_regl(port, S3C2410_ULCON, cfg->ulcon); /* reset both fifos */ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH); -- cgit v0.10.2 From d8c4019b41aaf4d6401a4ceb3819b8e1afe21595 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 2 Apr 2012 16:32:17 -0600 Subject: tty/serial/omap: console can only be built-in When the omap serial driver is built as a module, we must not allow the console driver to be selected, because consoles can not be loadable modules. Signed-off-by: Arnd Bergmann Signed-off-by: Mathieu Poirier Acked-by: Govindraj.R Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 665beb6..070b442 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1041,7 +1041,7 @@ config SERIAL_OMAP config SERIAL_OMAP_CONSOLE bool "Console on OMAP serial port" - depends on SERIAL_OMAP + depends on SERIAL_OMAP=y select SERIAL_CORE_CONSOLE help Select this option if you would like to use omap serial port as -- cgit v0.10.2 From 3579812373aba92b2f3b632bdf99329bc3c05d62 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2012 11:49:37 -0700 Subject: Revert "serial/8250_pci: init-quirk msi support for kt serial controller" This reverts commit e86ff4a63c9fdd875ba8492577cd1ad2252f525c. This tried to enforce the semantics of one interrupt per iir read of the THRE (transmit-hold empty) status, but events from other sources (particularly modem status) defeat this guarantee. This change also broke 8250_pci suspend/resume support as pciserial_resume_ports() re-runs .init() quirks, but does not run .exit() quirks in pciserial_suspend_ports() leading to reports like: sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:16.3/msi_irqs' ...and a subsequent crash. The mismatch of init/exit at suspend/resume seems like a bug in its own right. [stable: 3.3.x] Cc: stable Acked-by: Alan Cox Cc: Sudhakar Mamillapalli Reported-by: Nhan H Mai Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index da2b0b0..1d4ccf8 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1118,18 +1118,6 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -static int try_enable_msi(struct pci_dev *dev) -{ - /* use msi if available, but fallback to legacy otherwise */ - pci_enable_msi(dev); - return 0; -} - -static void disable_msi(struct pci_dev *dev) -{ - pci_disable_msi(dev); -} - #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1249,9 +1237,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .init = try_enable_msi, .setup = kt_serial_setup, - .exit = disable_msi, }, /* * ITE -- cgit v0.10.2 From 49b532f96fda23663f8be35593d1c1372c0f91e0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2012 11:49:44 -0700 Subject: Revert "serial/8250_pci: setup-quirk workaround for the kt serial controller" This reverts commit 448ac154c957c4580531fa0c8f2045816fe2f0e7. The semantic of UPF_IIR_ONCE is only guaranteed to workaround the race condition in the kt serial's iir register if the only source of interrupts is THRE (fifo-empty) events. An modem status event at the wrong time can again cause an iir read to drop the 'empty' status leading to a hang. So, revert this in preparation for using the existing "I don't trust my iir register" workaround in the 8250 core (UART_BUG_THRE). [stable: 3.3.x] Cc: stable Acked-by: Alan Cox Cc: Sudhakar Mamillapalli Reported-by: Nhan H Mai Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 5b149b4..56492d2 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -1572,13 +1572,11 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) do { struct uart_8250_port *up; struct uart_port *port; - bool skip; up = list_entry(l, struct uart_8250_port, list); port = &up->port; - skip = pass_counter && up->port.flags & UPF_IIR_ONCE; - if (!skip && port->handle_irq(port)) { + if (port->handle_irq(port)) { handled = 1; end = NULL; } else if (end == NULL) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 1d4ccf8..105dcfb 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1092,14 +1092,6 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -static int kt_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_port *port, int idx) -{ - port->flags |= UPF_IIR_ONCE; - return skip_tx_en_setup(priv, board, port, idx); -} - static int pci_eg20t_init(struct pci_dev *dev) { #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) @@ -1118,6 +1110,7 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +/* This should be in linux/pci_ids.h */ #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1147,7 +1140,6 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 -#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1232,13 +1224,6 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = ce4100_serial_setup, }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = kt_serial_setup, - }, /* * ITE */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index f51bf2e..882f1d6 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -357,7 +357,6 @@ struct uart_port { #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) #define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) -#define UPF_IIR_ONCE ((__force upf_t) (1 << 26)) /* The exact UART type is known and should not be probed. */ #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) -- cgit v0.10.2 From bc02d15a3452fdf9276e8fb89c5e504a88df888a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2012 11:49:50 -0700 Subject: serial/8250_pci: add a "force background timer" flag and use it for the "kt" serial port Workaround dropped notifications in the iir register. Register reads coincident with new interrupt notifications sometimes result in this device clearing the interrupt event without reporting it in the read data. The serial core already has a heuristic for determining when a device has an untrustworthy iir register. In this case when we apriori know that the iir is faulty use a flag (UPF_BUG_THRE) to bypass the test and force usage of the background timer. [stable: 3.3.x] Acked-by: Alan Cox Cc: stable Reported-by: Nhan H Mai Reported-by: Sudhakar Mamillapalli Tested-by: Nhan H Mai Tested-by: Sudhakar Mamillapalli Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 56492d2..5c27f7e 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -2035,10 +2035,12 @@ static int serial8250_startup(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); /* - * If the interrupt is not reasserted, setup a timer to - * kick the UART on a regular basis. + * If the interrupt is not reasserted, or we otherwise + * don't trust the iir, setup a timer to kick the UART + * on a regular basis. */ - if (!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) { + if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || + up->port.flags & UPF_BUG_THRE) { up->bugs |= UART_BUG_THRE; pr_debug("ttyS%d - using backup timer\n", serial_index(port)); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 105dcfb..858dca8 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1092,6 +1092,14 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static int kt_serial_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_port *port, int idx) +{ + port->flags |= UPF_BUG_THRE; + return skip_tx_en_setup(priv, board, port, idx); +} + static int pci_eg20t_init(struct pci_dev *dev) { #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) @@ -1110,7 +1118,6 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } -/* This should be in linux/pci_ids.h */ #define PCI_VENDOR_ID_SBSMODULARIO 0x124B #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B #define PCI_DEVICE_ID_OCTPRO 0x0001 @@ -1140,6 +1147,7 @@ pci_xr17c154_setup(struct serial_private *priv, #define PCI_DEVICE_ID_OXSEMI_16PCI958 0x9538 #define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001 +#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d /* Unknown vendors/cards - this should not be in linux/pci_ids.h */ #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584 @@ -1224,6 +1232,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = ce4100_serial_setup, }, + { + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_PATSBURG_KT, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = kt_serial_setup, + }, /* * ITE */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 882f1d6..2db407a 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -357,6 +357,7 @@ struct uart_port { #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) #define UPF_EXAR_EFR ((__force upf_t) (1 << 25)) +#define UPF_BUG_THRE ((__force upf_t) (1 << 26)) /* The exact UART type is known and should not be probed. */ #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) -- cgit v0.10.2 From 867c902e07d5677e2a5b54c0435e589513abde48 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Mon, 2 Apr 2012 14:36:22 +0900 Subject: pch_uart: Fix MSI setting issue The following patch (MSI setting) is not enough. commit e463595fd9c752fa4bf06b47df93ef9ade3c7cf0 Author: Alexander Stein Date: Mon Jul 4 08:58:31 2011 +0200 pch_uart: Add MSI support Signed-off-by: Alexander Stein Signed-off-by: Greg Kroah-Hartman To enable MSI mode, PCI bus-mastering must be enabled. This patch enables the setting. cc: Alexander Stein Signed-off-by: Tomoya MORINAGA Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index e825460..afa060f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1655,6 +1655,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, } pci_enable_msi(pdev); + pci_set_master(pdev); iobase = pci_resource_start(pdev, 0); mapbase = pci_resource_start(pdev, 1); -- cgit v0.10.2 From 11bbd5b6dae49fd7072ebf5eb63735827bd72f42 Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Fri, 23 Mar 2012 11:06:37 +0100 Subject: pch_uart: Add Kontron COMe-mTT10 uart clock quirk Add UART clock quirk for the Kontron COMe-mTT10 module. The board has previously been called nanoETXexpress-TT, therefore this is also checked. As suggested by Darren Hart the comparison in this patch version is placed after the FRI2 checks to ensure it will also work with possible upcoming changes to the FRI2 firmware. This patch follows the patchset submitted by Darren Hart at commit a46f5533ecfc7bbdd646d84fdab8656031a715c6. Signed-off-by: Michael Brunner Acked-by: Darren Hart Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index afa060f..8a18eb0 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -210,6 +210,7 @@ enum { #define CMITC_UARTCLK 192000000 /* 192.0000 MHz */ #define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */ #define FRI2_48_UARTCLK 48000000 /* 48.0000 MHz */ +#define NTC1_UARTCLK 64000000 /* 64.0000 MHz */ struct pch_uart_buffer { unsigned char *buf; @@ -388,6 +389,12 @@ static int pch_uart_get_uartclk(void) if (cmp && strstr(cmp, "Fish River Island II")) return FRI2_48_UARTCLK; + /* Kontron COMe-mTT10 (nanoETXexpress-TT) */ + cmp = dmi_get_system_info(DMI_BOARD_NAME); + if (cmp && (strstr(cmp, "COMe-mTT") || + strstr(cmp, "nanoETXexpress-TT"))) + return NTC1_UARTCLK; + return DEFAULT_UARTCLK; } -- cgit v0.10.2 From 3cb42092ff02edec34bf936b7400b1f1efc8ca43 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 9 Apr 2012 13:59:00 -0400 Subject: um: fix linker script generation while we can't just use -U$(SUBARCH), we still need to kill idiotic define (implicit -Di386=1), both for SUBARCH=i386 and SUBARCH=x86/CONFIG_64BIT=n builds. Signed-off-by: Al Viro diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 492bc4c..65a1c3d 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -3,9 +3,10 @@ # Licensed under the GPL # -CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \ - -DELF_ARCH=$(LDS_ELF_ARCH) \ - -DELF_FORMAT=$(LDS_ELF_FORMAT) +CPPFLAGS_vmlinux.lds := -DSTART=$(LDS_START) \ + -DELF_ARCH=$(LDS_ELF_ARCH) \ + -DELF_FORMAT=$(LDS_ELF_FORMAT) \ + $(LDS_EXTRA) extra-y := vmlinux.lds clean-files := diff --git a/arch/x86/Makefile.um b/arch/x86/Makefile.um index 4be406a..36b62bc 100644 --- a/arch/x86/Makefile.um +++ b/arch/x86/Makefile.um @@ -14,6 +14,9 @@ LINK-y += $(call cc-option,-m32) export LDFLAGS +LDS_EXTRA := -Ui386 +export LDS_EXTRA + # First of all, tune CFLAGS for the specific CPU. This actually sets cflags-y. include $(srctree)/arch/x86/Makefile_32.cpu -- cgit v0.10.2 From f21a7c195cb20cf613147839c4a2bc1fca8c7bd8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Apr 2012 20:31:22 -0400 Subject: um: several x86 hw-dependent crypto modules won't build on uml Signed-off-by: Al Viro diff --git a/crypto/Kconfig b/crypto/Kconfig index 21ff9d0..8e84225 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -627,7 +627,7 @@ config CRYPTO_BLOWFISH_COMMON config CRYPTO_BLOWFISH_X86_64 tristate "Blowfish cipher algorithm (x86_64)" - depends on (X86 || UML_X86) && 64BIT + depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_BLOWFISH_COMMON help @@ -657,7 +657,7 @@ config CRYPTO_CAMELLIA config CRYPTO_CAMELLIA_X86_64 tristate "Camellia cipher algorithm (x86_64)" - depends on (X86 || UML_X86) && 64BIT + depends on X86 && 64BIT depends on CRYPTO select CRYPTO_ALGAPI select CRYPTO_LRW @@ -893,7 +893,7 @@ config CRYPTO_TWOFISH_X86_64 config CRYPTO_TWOFISH_X86_64_3WAY tristate "Twofish cipher algorithm (x86_64, 3-way parallel)" - depends on (X86 || UML_X86) && 64BIT + depends on X86 && 64BIT select CRYPTO_ALGAPI select CRYPTO_TWOFISH_COMMON select CRYPTO_TWOFISH_X86_64 -- cgit v0.10.2 From d1640130cda146ed925f12434bfe579ee7d80a1c Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 22 Mar 2012 16:59:11 +0530 Subject: tile/CPU hotplug: Add missing call to notify_cpu_starting() The scheduler depends on receiving the CPU_STARTING notification, without which we end up into a lot of trouble. So add the missing call to notify_cpu_starting() in the bringup code. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c index b949edc..172aef7 100644 --- a/arch/tile/kernel/smpboot.c +++ b/arch/tile/kernel/smpboot.c @@ -196,6 +196,8 @@ void __cpuinit online_secondary(void) /* This must be done before setting cpu_online_mask */ wmb(); + notify_cpu_starting(smp_processor_id()); + /* * We need to hold call_lock, so there is no inconsistency * between the time smp_call_function() determines number of -- cgit v0.10.2 From 8528e07edfc6ac5a793509f305b9c3c4fb3672c0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 28 Mar 2012 08:35:26 -0700 Subject: hwmon: (smsc47b397) Fix compiler warning Some configurations produce the following compiler warning: drivers/hwmon/smsc47b397.c: In function 'smsc47b397_init': drivers/hwmon/smsc47b397.c:385: warning: 'address' may be used uninitialized in this function While this is a false positive, it can easily be fixed by overloading the return value from smsc47b397_find with both address and error return code (the address is an unsigned short and thus never negative). This also reduces module size by a few bytes (64 bytes for x86_64). Cc: Mark M. Hoffman Signed-off-by: Guenter Roeck Reviewed-by: Robert Coulson Acked-by: Jean Delvare diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index d3b778d..c5f6be4 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -343,10 +343,11 @@ exit: return err; } -static int __init smsc47b397_find(unsigned short *addr) +static int __init smsc47b397_find(void) { u8 id, rev; char *name; + unsigned short addr; superio_enter(); id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); @@ -370,14 +371,14 @@ static int __init smsc47b397_find(unsigned short *addr) rev = superio_inb(SUPERIO_REG_DEVREV); superio_select(SUPERIO_REG_LD8); - *addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) + addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8) | superio_inb(SUPERIO_REG_BASE_LSB); pr_info("found SMSC %s (base address 0x%04x, revision %u)\n", - name, *addr, rev); + name, addr, rev); superio_exit(); - return 0; + return addr; } static int __init smsc47b397_init(void) @@ -385,9 +386,10 @@ static int __init smsc47b397_init(void) unsigned short address; int ret; - ret = smsc47b397_find(&address); - if (ret) + ret = smsc47b397_find(); + if (ret < 0) return ret; + address = ret; ret = platform_driver_register(&smsc47b397_driver); if (ret) -- cgit v0.10.2 From 776cdc11b3b0fc21e34600e22abe1c8209d2f3f0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 28 Mar 2012 09:03:26 -0700 Subject: hwmon: (acpi_power_meter) Fix compiler warning seen in some configurations In some configurations, BUG() does not result in an endless loop but returns to the caller. This results in the following compiler warning: drivers/hwmon/acpi_power_meter.c: In function 'show_str': drivers/hwmon/acpi_power_meter.c:380: warning: 'val' may be used uninitialized in this function Fix the warning by setting val to an empty string after BUG(). Signed-off-by: Guenter Roeck Reviewed-by: Robert Coulson diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 145f135..9140236 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -391,6 +391,7 @@ static ssize_t show_str(struct device *dev, break; default: BUG(); + val = ""; } return sprintf(buf, "%s\n", val); -- cgit v0.10.2 From 1d0045ee4a220872b65147b5b290e4a4852386d9 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 28 Mar 2012 08:55:12 -0700 Subject: hwmon: (smsc47m1) Fix compiler warning Some configurations produce the following compiler warning: drivers/hwmon/smsc47m1.c: In function 'sm_smsc47m1_init': drivers/hwmon/smsc47m1.c:938: warning: 'address' may be used uninitialized in this function While this is a false positive, it can easily be fixed by overloading the return value from smsc47m1_find with both address and error return code (the address is an unsigned short and thus never negative). This also reduces module size by a few bytes (46 bytes for x86_64). Signed-off-by: Guenter Roeck Reviewed-by: Robert Coulson diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index c590c14..b5aa38d 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -491,10 +491,10 @@ static const struct attribute_group smsc47m1_group = { .attrs = smsc47m1_attributes, }; -static int __init smsc47m1_find(unsigned short *addr, - struct smsc47m1_sio_data *sio_data) +static int __init smsc47m1_find(struct smsc47m1_sio_data *sio_data) { u8 val; + unsigned short addr; superio_enter(); val = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID); @@ -546,9 +546,9 @@ static int __init smsc47m1_find(unsigned short *addr, } superio_select(); - *addr = (superio_inb(SUPERIO_REG_BASE) << 8) + addr = (superio_inb(SUPERIO_REG_BASE) << 8) | superio_inb(SUPERIO_REG_BASE + 1); - if (*addr == 0) { + if (addr == 0) { pr_info("Device address not set, will not use\n"); superio_exit(); return -ENODEV; @@ -565,7 +565,7 @@ static int __init smsc47m1_find(unsigned short *addr, } superio_exit(); - return 0; + return addr; } /* Restore device to its initial state */ @@ -938,13 +938,15 @@ static int __init sm_smsc47m1_init(void) unsigned short address; struct smsc47m1_sio_data sio_data; - if (smsc47m1_find(&address, &sio_data)) - return -ENODEV; + err = smsc47m1_find(&sio_data); + if (err < 0) + return err; + address = err; /* Sets global pdev as a side effect */ err = smsc47m1_device_add(address, &sio_data); if (err) - goto exit; + return err; err = platform_driver_probe(&smsc47m1_driver, smsc47m1_probe); if (err) @@ -955,7 +957,6 @@ static int __init sm_smsc47m1_init(void) exit_device: platform_device_unregister(pdev); smsc47m1_restore(&sio_data); -exit: return err; } -- cgit v0.10.2 From d7ee11157f1fce02632e2f3a56b99b2afd9e5f93 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 28 Mar 2012 09:14:03 -0700 Subject: hwmon: (pmbus_core) Fix compiler warning Some configurations produce the following compiler warning: drivers/hwmon/pmbus/pmbus_core.c: In function 'pmbus_show_boolean': drivers/hwmon/pmbus/pmbus_core.c:752: warning: 'val' may be used uninitialized in this function While this is a false positive, it can easily be fixed by overloading the return value from pmbus_get_boolean with both val and error return code (val is a boolean and thus never negative). Signed-off-by: Guenter Roeck Reviewed-by: Robert Coulson diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index be51037..29b319d 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -710,13 +710,13 @@ static u16 pmbus_data2reg(struct pmbus_data *data, * If a negative value is stored in any of the referenced registers, this value * reflects an error code which will be returned. */ -static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) +static int pmbus_get_boolean(struct pmbus_data *data, int index) { u8 s1 = (index >> 24) & 0xff; u8 s2 = (index >> 16) & 0xff; u8 reg = (index >> 8) & 0xff; u8 mask = index & 0xff; - int status; + int ret, status; u8 regval; status = data->status[reg]; @@ -725,7 +725,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) regval = status & mask; if (!s1 && !s2) - *val = !!regval; + ret = !!regval; else { long v1, v2; struct pmbus_sensor *sensor1, *sensor2; @@ -739,9 +739,9 @@ static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) v1 = pmbus_reg2data(data, sensor1); v2 = pmbus_reg2data(data, sensor2); - *val = !!(regval && v1 >= v2); + ret = !!(regval && v1 >= v2); } - return 0; + return ret; } static ssize_t pmbus_show_boolean(struct device *dev, @@ -750,11 +750,10 @@ static ssize_t pmbus_show_boolean(struct device *dev, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct pmbus_data *data = pmbus_update_device(dev); int val; - int err; - err = pmbus_get_boolean(data, attr->index, &val); - if (err) - return err; + val = pmbus_get_boolean(data, attr->index); + if (val < 0) + return val; return snprintf(buf, PAGE_SIZE, "%d\n", val); } -- cgit v0.10.2 From b2a71642b8bfa1965700ba248a99016e4d6b685d Mon Sep 17 00:00:00 2001 From: acreese Date: Wed, 4 Apr 2012 16:22:32 -0700 Subject: drm/i915: Removed IVB forced enable of sprite dest key. The destination color key is always enabled for IVB. Removed the line that does this. Signed-off-by: Armin Reese Acked-by: Jesse Barnes Cc: stable@kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index a464771..e90dfb6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -95,7 +95,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, /* must disable */ sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_ENABLE; - sprctl |= SPRITE_DEST_KEY; /* Sizes are 0 based */ src_w--; -- cgit v0.10.2 From 14667a4bde4361b7ac420d68a2e9e9b9b2df5231 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 3 Apr 2012 17:58:35 +0100 Subject: drm/i915: Finish any pending operations on the framebuffer before disabling Similar to the case where we are changing from one framebuffer to another, we need to be sure that there are no pending WAIT_FOR_EVENTs on the pipe for the current framebuffer before switching. If we disable the pipe, and then try to execute a WAIT_FOR_EVENT it will block indefinitely and cause a GPU hang. We attempted to fix this in commit 85345517fe6d4de27b0d6ca19fef9d28ac947c4a (drm/i915: Retire any pending operations on the old scanout when switching) for the case of mode switching, but this leaves the condition where we are switching off the pipe vulnerable. There still remains the race condition were a display may be unplugged, switched off by the core, a uevent sent to notify the DDX and the DDX may issue a WAIT_FOR_EVENT before it processes the uevent. This window does not exist if the pipe is only switched off in response to the uevent. Time to make sure that is so... Reported-by: Francis Leblanc Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36515 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=45413 Signed-off-by: Chris Wilson Reviewed-by: Eugeni Dodonov [danvet: fixup spelling in comment, noticed by Eugeni.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 91b35fd..f446e66 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2245,6 +2245,33 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, } static int +intel_finish_fb(struct drm_framebuffer *old_fb) +{ + struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + bool was_interruptible = dev_priv->mm.interruptible; + int ret; + + wait_event(dev_priv->pending_flip_queue, + atomic_read(&dev_priv->mm.wedged) || + atomic_read(&obj->pending_flip) == 0); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. + */ + dev_priv->mm.interruptible = false; + ret = i915_gem_object_finish_gpu(obj); + dev_priv->mm.interruptible = was_interruptible; + + return ret; +} + +static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -2282,25 +2309,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (old_fb) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; - - wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->mm.wedged) || - atomic_read(&obj->pending_flip) == 0); - - /* Big Hammer, we also need to ensure that any pending - * MI_WAIT_FOR_EVENT inside a user batch buffer on the - * current scanout is retired before unpinning the old - * framebuffer. - * - * This should only fail upon a hung GPU, in which case we - * can safely continue. - */ - ret = i915_gem_object_finish_gpu(obj); - (void) ret; - } + if (old_fb) + intel_finish_fb(old_fb); ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, LEAVE_ATOMIC_MODE_SET); @@ -3371,6 +3381,23 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_device *dev = crtc->dev; + /* Flush any pending WAITs before we disable the pipe. Note that + * we need to drop the struct_mutex in order to acquire it again + * during the lowlevel dpms routines around a couple of the + * operations. It does not look trivial nor desirable to move + * that locking higher. So instead we leave a window for the + * submission of further commands on the fb before we can actually + * disable it. This race with userspace exists anyway, and we can + * only rely on the pipe being disabled by userspace after it + * receives the hotplug notification and has flushed any pending + * batches. + */ + if (crtc->fb) { + mutex_lock(&dev->struct_mutex); + intel_finish_fb(crtc->fb); + mutex_unlock(&dev->struct_mutex); + } + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); -- cgit v0.10.2 From 3f9768a5d262d01d317b2a03933db3d5082fcb68 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Mar 2012 21:02:46 +0200 Subject: mac80211: fix association beacon wait timeout The TU_TO_EXP_TIME() macro already includes the "jiffies +" piece of the calculation, so don't add jiffies again. Reported-by: Oliver Hartkopp Signed-off-by: Johannes Berg Tested-by: Oliver Hartkopp Signed-off-by: John W. Linville diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 576fb25..f76da5b 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3387,8 +3387,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, */ printk(KERN_DEBUG "%s: waiting for beacon from %pM\n", sdata->name, ifmgd->bssid); - assoc_data->timeout = jiffies + - TU_TO_EXP_TIME(req->bss->beacon_interval); + assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); } else { assoc_data->have_beacon = true; assoc_data->sent_assoc = false; -- cgit v0.10.2 From 2b5f8b0b44e17e625cfba1e7b88db44f4dcc0441 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 2 Apr 2012 10:51:55 +0200 Subject: nl80211: ensure interface is up in various APIs The nl80211 handling code should ensure as much as it can that the interface is in a valid state, it can certainly ensure the interface is running. Not doing so can cause calls through mac80211 into the driver that result in warnings and unspecified behaviour in the driver. Cc: stable@vger.kernel.org Reported-by: Ben Greear Signed-off-by: Johannes Berg Signed-off-by: John W. Linville diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e49da27..f432c57 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1294,6 +1294,11 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) goto bad_res; } + if (!netif_running(netdev)) { + result = -ENETDOWN; + goto bad_res; + } + nla_for_each_nested(nl_txq_params, info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], rem_txq_params) { @@ -6384,7 +6389,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_get_key, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6416,7 +6421,7 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_set_beacon, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6424,7 +6429,7 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_start_ap, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6432,7 +6437,7 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, .doit = nl80211_stop_ap, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6448,7 +6453,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6464,7 +6469,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6497,7 +6502,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_mpath, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6505,7 +6510,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_set_bss, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6531,7 +6536,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_get_mesh_config, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6664,7 +6669,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6672,7 +6677,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_setdel_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6680,7 +6685,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_flush_pmksa, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6840,7 +6845,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_probe_client, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, { -- cgit v0.10.2 From 0298dc9f2273fb2d596ae10d7700f054bfce601d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 3 Apr 2012 15:31:41 -0500 Subject: rtlwifi: rtl8192de: Fix firmware initialization Before the switch to asynchronous firmware loading (mainline commit b0302ab), it was necessary to load firmware when initializing the first of the units in a dual-mac system. After the change, it is necessary to load firmware in both units. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 4898c50..480862c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -91,7 +91,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) u8 tid; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - static int header_print; rtlpriv->dm.dm_initialgain_enable = true; rtlpriv->dm.dm_flag = 0; @@ -171,10 +170,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) for (tid = 0; tid < 8; tid++) skb_queue_head_init(&rtlpriv->mac80211.skb_waitq[tid]); - /* Only load firmware for first MAC */ - if (header_print) - return 0; - /* for firmware buf */ rtlpriv->rtlhal.pfirmware = vzalloc(0x8000); if (!rtlpriv->rtlhal.pfirmware) { @@ -186,7 +181,6 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->max_fw_size = 0x8000; pr_info("Driver for Realtek RTL8192DE WLAN interface\n"); pr_info("Loading firmware file %s\n", rtlpriv->cfg->fw_name); - header_print++; /* request fw */ err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name, -- cgit v0.10.2 From aa331df0e5e6ebac086ed80b4fbbfd912fe6b32a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 6 Apr 2012 16:35:53 -0500 Subject: mac80211: Convert WARN_ON to WARN_ON_ONCE When the control-rate tables are not set up correctly, it makes little sense to spam the logs, thus change the WARN_ON to WARN_ON_ONCE. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 87d203f..9210bdc 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1327,7 +1327,7 @@ static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) { - if (WARN_ON(c->control.rates[0].idx < 0)) + if (WARN_ON_ONCE(c->control.rates[0].idx < 0)) return NULL; return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; } -- cgit v0.10.2 From e89f7690a3adbde0af7c294f83c242ba6a367ef0 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 6 Apr 2012 16:54:17 -0500 Subject: rtlwifi: Fix oops on rate-control failure When the rate-control indexing is incorrectly set up, mac80211 issues a warning and returns NULL from the call to ieee80211_get_tx_rate(). When this happens, avoid a NULL pointer dereference. Signed-off-by: Larry Finger Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 5100235..e54488d 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -838,7 +838,10 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, __le16 fc = hdr->frame_control; txrate = ieee80211_get_tx_rate(hw, info); - tcb_desc->hw_rate = txrate->hw_value; + if (txrate) + tcb_desc->hw_rate = txrate->hw_value; + else + tcb_desc->hw_rate = 0; if (ieee80211_is_data(fc)) { /* -- cgit v0.10.2 From 7ab2485b69571a3beb0313c591486626c3374c85 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 9 Apr 2012 11:01:09 +0200 Subject: net/wireless/wext-core.c: add missing kfree Free extra as done in the error-handling code just above. Signed-off-by: Julia Lawall Signed-off-by: John W. Linville diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 0af7f54..af648e0 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -780,8 +780,10 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, if (cmd == SIOCSIWENCODEEXT) { struct iw_encode_ext *ee = (void *) extra; - if (iwp->length < sizeof(*ee) + ee->key_len) - return -EFAULT; + if (iwp->length < sizeof(*ee) + ee->key_len) { + err = -EFAULT; + goto out; + } } } -- cgit v0.10.2 From 33cb4f345687a27e3fece0a7fcf78ac2e7b0a7d6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 20 Mar 2012 16:32:39 +0800 Subject: drivers/base: Remove unneeded spin_lock_init call for soc_lock soc_lock is already initialized by DEFINE_SPINLOCK. Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 05f1503..f49346b 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -168,8 +168,6 @@ void soc_device_unregister(struct soc_device *soc_dev) static int __init soc_bus_register(void) { - spin_lock_init(&soc_lock); - return bus_register(&soc_bus_type); } core_initcall(soc_bus_register); -- cgit v0.10.2 From 3a4ffe930a2d2dad07604fe74d21b878decc6461 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Sat, 17 Mar 2012 09:17:49 +0000 Subject: drivers/base: fix compiler warning in SoC export driver - idr should be ida MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes: note: expected ‘struct ida *’ but argument is of type ‘struct idr *’ warning: passing argument 1 of ‘ida_pre_get’ from incompatible pointer type Reported-by: Arnd Bergman Cc: Greg Kroah-Hartman Signed-off-by: Lee Jones Signed-off-by: Axel Lin Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/base/soc.c b/drivers/base/soc.c index f49346b..ba29b2e 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -15,7 +15,7 @@ #include #include -static DEFINE_IDR(soc_ida); +static DEFINE_IDA(soc_ida); static DEFINE_SPINLOCK(soc_lock); static ssize_t soc_info_get(struct device *dev, -- cgit v0.10.2 From d824d06328904f610b47652dcd488392f2fc62b6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 5 Apr 2012 23:35:03 -0400 Subject: um: switch cow_user.h to htobe{32,64}/betoh{32,64} ... rather than open-coding the 64bit versions. endian.h has those guys. Signed-off-by: Al Viro Signed-off-by: Richard Weinberger diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index dc36b22..6673508 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -3,41 +3,6 @@ #include -#if defined(__KERNEL__) - -# include - -# if defined(__BIG_ENDIAN) -# define ntohll(x) (x) -# define htonll(x) (x) -# elif defined(__LITTLE_ENDIAN) -# define ntohll(x) be64_to_cpu(x) -# define htonll(x) cpu_to_be64(x) -# else -# error "Could not determine byte order" -# endif - -#else -/* For the definition of ntohl, htonl and __BYTE_ORDER */ -#include -#include -#if defined(__BYTE_ORDER) - -# if __BYTE_ORDER == __BIG_ENDIAN -# define ntohll(x) (x) -# define htonll(x) (x) -# elif __BYTE_ORDER == __LITTLE_ENDIAN -# define ntohll(x) bswap_64(x) -# define htonll(x) bswap_64(x) -# else -# error "Could not determine byte order: __BYTE_ORDER uncorrectly defined" -# endif - -#else /* ! defined(__BYTE_ORDER) */ -# error "Could not determine byte order: __BYTE_ORDER not defined" -#endif -#endif /* ! defined(__KERNEL__) */ - extern int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, int alignment, int *bitmap_offset_out, unsigned long *bitmap_len_out, int *data_offset_out); diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 9cbb426..0ee9cc6 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -8,11 +8,10 @@ * that. */ #include -#include #include #include #include -#include +#include #include "cow.h" #include "cow_sys.h" @@ -214,8 +213,8 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, "header\n"); goto out; } - header->magic = htonl(COW_MAGIC); - header->version = htonl(COW_VERSION); + header->magic = htobe32(COW_MAGIC); + header->version = htobe32(COW_VERSION); err = -EINVAL; if (strlen(backing_file) > sizeof(header->backing_file) - 1) { @@ -246,10 +245,10 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, goto out_free; } - header->mtime = htonl(modtime); - header->size = htonll(*size); - header->sectorsize = htonl(sectorsize); - header->alignment = htonl(alignment); + header->mtime = htobe32(modtime); + header->size = htobe64(*size); + header->sectorsize = htobe32(sectorsize); + header->alignment = htobe32(alignment); header->cow_format = COW_BITMAP; err = cow_write_file(fd, header, sizeof(*header)); @@ -301,8 +300,8 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, magic = header->v1.magic; if (magic == COW_MAGIC) version = header->v1.version; - else if (magic == ntohl(COW_MAGIC)) - version = ntohl(header->v1.version); + else if (magic == be32toh(COW_MAGIC)) + version = be32toh(header->v1.version); /* No error printed because the non-COW case comes through here */ else goto out; @@ -327,9 +326,9 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, "header\n"); goto out; } - *mtime_out = ntohl(header->v2.mtime); - *size_out = ntohll(header->v2.size); - *sectorsize_out = ntohl(header->v2.sectorsize); + *mtime_out = be32toh(header->v2.mtime); + *size_out = be64toh(header->v2.size); + *sectorsize_out = be32toh(header->v2.sectorsize); *bitmap_offset_out = sizeof(header->v2); *align_out = *sectorsize_out; file = header->v2.backing_file; @@ -341,10 +340,10 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, "header\n"); goto out; } - *mtime_out = ntohl(header->v3.mtime); - *size_out = ntohll(header->v3.size); - *sectorsize_out = ntohl(header->v3.sectorsize); - *align_out = ntohl(header->v3.alignment); + *mtime_out = be32toh(header->v3.mtime); + *size_out = be64toh(header->v3.size); + *sectorsize_out = be32toh(header->v3.sectorsize); + *align_out = be32toh(header->v3.alignment); if (*align_out == 0) { cow_printf("read_cow_header - invalid COW header, " "align == 0\n"); @@ -366,16 +365,16 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, * this was used until Dec2005 - 64bits are needed to represent * 2038+. I.e. we can safely do this truncating cast. * - * Additionally, we must use ntohl() instead of ntohll(), since + * Additionally, we must use be32toh() instead of be64toh(), since * the program used to use the former (tested - I got mtime * mismatch "0 vs whatever"). * * Ever heard about bug-to-bug-compatibility ? ;-) */ - *mtime_out = (time32_t) ntohl(header->v3_b.mtime); + *mtime_out = (time32_t) be32toh(header->v3_b.mtime); - *size_out = ntohll(header->v3_b.size); - *sectorsize_out = ntohl(header->v3_b.sectorsize); - *align_out = ntohl(header->v3_b.alignment); + *size_out = be64toh(header->v3_b.size); + *sectorsize_out = be32toh(header->v3_b.sectorsize); + *align_out = be32toh(header->v3_b.alignment); if (*align_out == 0) { cow_printf("read_cow_header - invalid COW header, " "align == 0\n"); -- cgit v0.10.2 From a3a85a763c399c0bf483a30d82d2d613e6f94cd3 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 29 Mar 2012 18:47:46 +0200 Subject: um: Disintegrate asm/system.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Weinberger Reported-by: Toralf Förster CC: dhowells@redhat.com diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index e672bd6..43b39d6 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "init.h" #include "irq_kern.h" diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index 8419f5c..bb5d6e6 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -1,3 +1,3 @@ generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h -generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h +generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h diff --git a/arch/x86/um/asm/barrier.h b/arch/x86/um/asm/barrier.h new file mode 100644 index 0000000..7d01b8c --- /dev/null +++ b/arch/x86/um/asm/barrier.h @@ -0,0 +1,75 @@ +#ifndef _ASM_UM_BARRIER_H_ +#define _ASM_UM_BARRIER_H_ + +#include +#include +#include +#include +#include + +#include +#include + +/* + * Force strict CPU ordering. + * And yes, this is required on UP too when we're talking + * to devices. + */ +#ifdef CONFIG_X86_32 + +#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) +#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) +#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) + +#else /* CONFIG_X86_32 */ + +#define mb() asm volatile("mfence" : : : "memory") +#define rmb() asm volatile("lfence" : : : "memory") +#define wmb() asm volatile("sfence" : : : "memory") + +#endif /* CONFIG_X86_32 */ + +#define read_barrier_depends() do { } while (0) + +#ifdef CONFIG_SMP + +#define smp_mb() mb() +#ifdef CONFIG_X86_PPRO_FENCE +#define smp_rmb() rmb() +#else /* CONFIG_X86_PPRO_FENCE */ +#define smp_rmb() barrier() +#endif /* CONFIG_X86_PPRO_FENCE */ + +#ifdef CONFIG_X86_OOSTORE +#define smp_wmb() wmb() +#else /* CONFIG_X86_OOSTORE */ +#define smp_wmb() barrier() +#endif /* CONFIG_X86_OOSTORE */ + +#define smp_read_barrier_depends() read_barrier_depends() +#define set_mb(var, value) do { (void)xchg(&var, value); } while (0) + +#else /* CONFIG_SMP */ + +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while (0) +#define set_mb(var, value) do { var = value; barrier(); } while (0) + +#endif /* CONFIG_SMP */ + +/* + * Stop RDTSC speculation. This is needed when you need to use RDTSC + * (or get_cycles or vread that possibly accesses the TSC) in a defined + * code region. + * + * (Could use an alternative three way for this if there was one.) + */ +static inline void rdtsc_barrier(void) +{ + alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC); + alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC); +} + +#endif diff --git a/arch/x86/um/asm/switch_to.h b/arch/x86/um/asm/switch_to.h new file mode 100644 index 0000000..cf97d20 --- /dev/null +++ b/arch/x86/um/asm/switch_to.h @@ -0,0 +1,7 @@ +#ifndef _ASM_UM_SWITCH_TO_H_ +#define _ASM_UM_SWITCH_TO_H_ + +extern void *_switch_to(void *prev, void *next, void *last); +#define switch_to(prev, next, last) prev = _switch_to(prev, next, last) + +#endif diff --git a/arch/x86/um/asm/system.h b/arch/x86/um/asm/system.h deleted file mode 100644 index a459fd9..0000000 --- a/arch/x86/um/asm/system.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef _ASM_X86_SYSTEM_H_ -#define _ASM_X86_SYSTEM_H_ - -#include -#include -#include -#include -#include - -#include -#include - -/* entries in ARCH_DLINFO: */ -#ifdef CONFIG_IA32_EMULATION -# define AT_VECTOR_SIZE_ARCH 2 -#else -# define AT_VECTOR_SIZE_ARCH 1 -#endif - -extern unsigned long arch_align_stack(unsigned long sp); - -void default_idle(void); - -/* - * Force strict CPU ordering. - * And yes, this is required on UP too when we're talking - * to devices. - */ -#ifdef CONFIG_X86_32 -/* - * Some non-Intel clones support out of order store. wmb() ceases to be a - * nop for these. - */ -#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2) -#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2) -#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM) -#else -#define mb() asm volatile("mfence":::"memory") -#define rmb() asm volatile("lfence":::"memory") -#define wmb() asm volatile("sfence" ::: "memory") -#endif - -/** - * read_barrier_depends - Flush all pending reads that subsequents reads - * depend on. - * - * No data-dependent reads from memory-like regions are ever reordered - * over this barrier. All reads preceding this primitive are guaranteed - * to access memory (but not necessarily other CPUs' caches) before any - * reads following this primitive that depend on the data return by - * any of the preceding reads. This primitive is much lighter weight than - * rmb() on most CPUs, and is never heavier weight than is - * rmb(). - * - * These ordering constraints are respected by both the local CPU - * and the compiler. - * - * Ordering is not guaranteed by anything other than these primitives, - * not even by data dependencies. See the documentation for - * memory_barrier() for examples and URLs to more information. - * - * For example, the following code would force ordering (the initial - * value of "a" is zero, "b" is one, and "p" is "&a"): - * - * - * CPU 0 CPU 1 - * - * b = 2; - * memory_barrier(); - * p = &b; q = p; - * read_barrier_depends(); - * d = *q; - * - * - * because the read of "*q" depends on the read of "p" and these - * two reads are separated by a read_barrier_depends(). However, - * the following code, with the same initial values for "a" and "b": - * - * - * CPU 0 CPU 1 - * - * a = 2; - * memory_barrier(); - * b = 3; y = b; - * read_barrier_depends(); - * x = a; - * - * - * does not enforce ordering, since there is no data dependency between - * the read of "a" and the read of "b". Therefore, on some CPUs, such - * as Alpha, "y" could be set to 3 and "x" to 0. Use rmb() - * in cases like this where there are no data dependencies. - **/ - -#define read_barrier_depends() do { } while (0) - -#ifdef CONFIG_SMP -#define smp_mb() mb() -#ifdef CONFIG_X86_PPRO_FENCE -# define smp_rmb() rmb() -#else -# define smp_rmb() barrier() -#endif -#ifdef CONFIG_X86_OOSTORE -# define smp_wmb() wmb() -#else -# define smp_wmb() barrier() -#endif -#define smp_read_barrier_depends() read_barrier_depends() -#define set_mb(var, value) do { (void)xchg(&var, value); } while (0) -#else -#define smp_mb() barrier() -#define smp_rmb() barrier() -#define smp_wmb() barrier() -#define smp_read_barrier_depends() do { } while (0) -#define set_mb(var, value) do { var = value; barrier(); } while (0) -#endif - -/* - * Stop RDTSC speculation. This is needed when you need to use RDTSC - * (or get_cycles or vread that possibly accesses the TSC) in a defined - * code region. - * - * (Could use an alternative three way for this if there was one.) - */ -static inline void rdtsc_barrier(void) -{ - alternative(ASM_NOP3, "mfence", X86_FEATURE_MFENCE_RDTSC); - alternative(ASM_NOP3, "lfence", X86_FEATURE_LFENCE_RDTSC); -} - -extern void *_switch_to(void *prev, void *next, void *last); -#define switch_to(prev, next, last) prev = _switch_to(prev, next, last) - -#endif -- cgit v0.10.2 From 76b278edd99fb55525fcf2706095e388bd3d122c Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Thu, 29 Mar 2012 19:10:42 +0200 Subject: um: Use asm-generic/switch_to.h Signed-off-by: Richard Weinberger diff --git a/arch/um/include/asm/Kbuild b/arch/um/include/asm/Kbuild index bb5d6e6..fff2435 100644 --- a/arch/um/include/asm/Kbuild +++ b/arch/um/include/asm/Kbuild @@ -1,3 +1,4 @@ generic-y += bug.h cputime.h device.h emergency-restart.h futex.h hardirq.h generic-y += hw_irq.h irq_regs.h kdebug.h percpu.h sections.h topology.h xor.h generic-y += ftrace.h pci.h io.h param.h delay.h mutex.h current.h exec.h +generic-y += switch_to.h diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index f386d04..2b73ded 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -88,11 +88,8 @@ static inline void set_current(struct task_struct *task) extern void arch_switch_to(struct task_struct *to); -void *_switch_to(void *prev, void *next, void *last) +void *__switch_to(struct task_struct *from, struct task_struct *to) { - struct task_struct *from = prev; - struct task_struct *to = next; - to->thread.prev_sched = from; set_current(to); @@ -111,7 +108,6 @@ void *_switch_to(void *prev, void *next, void *last) } while (current->thread.saved_task); return current->thread.prev_sched; - } void interrupt_end(void) diff --git a/arch/x86/um/asm/switch_to.h b/arch/x86/um/asm/switch_to.h deleted file mode 100644 index cf97d20..0000000 --- a/arch/x86/um/asm/switch_to.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ASM_UM_SWITCH_TO_H_ -#define _ASM_UM_SWITCH_TO_H_ - -extern void *_switch_to(void *prev, void *next, void *last); -#define switch_to(prev, next, last) prev = _switch_to(prev, next, last) - -#endif -- cgit v0.10.2 From 657b12d3a1508a3f06f7afe21d5dda7252279520 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Mon, 26 Mar 2012 19:18:22 -0700 Subject: um: uml_setup_stubs': warning: unused variable 'pages' Fix the following gcc complain arch/um/kernel/skas/mmu.c: In function 'uml_setup_stubs': arch/um/kernel/skas/mmu.c:106:16: warning: unused variable 'pages' [-Wunused-variable] Signed-Signed-off-by: Boaz Harrosh Signed-off-by: Richard Weinberger diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 4947b31..0a49ef0 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -103,7 +103,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) void uml_setup_stubs(struct mm_struct *mm) { - struct page **pages; int err, ret; if (!skas_needs_stub) -- cgit v0.10.2 From 70fa4a62e913dde2d100e0be2711562742f58bee Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Wed, 4 Apr 2012 12:06:20 -0700 Subject: sysfs: Update the name hash for an entry after changing the namespace This is needed to allow renaming network devices that have been moved to another network namespace. Signed-off-by: Tom Goff Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2a7a3f5..8ddc102 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -878,7 +878,6 @@ int sysfs_rename(struct sysfs_dirent *sd, dup_name = sd->s_name; sd->s_name = new_name; - sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); } /* Move to the appropriate place in the appropriate directories rbtree. */ @@ -886,6 +885,7 @@ int sysfs_rename(struct sysfs_dirent *sd, sysfs_get(new_parent_sd); sysfs_put(sd->s_parent); sd->s_ns = new_ns; + sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); sd->s_parent = new_parent_sd; sysfs_link_sibling(sd); -- cgit v0.10.2 From ce5c9851855bab190c9a142761d54ba583ab094c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 23 Mar 2012 15:23:18 +0100 Subject: USB: pl2303: fix DTR/RTS being raised on baud rate change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DTR/RTS should only be raised when changing baudrate from B0 and not on any baud rate change (> B0). Reported-by: Søren Holm Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ff4a174..a1a9062 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -420,7 +420,7 @@ static void pl2303_set_termios(struct tty_struct *tty, control = priv->line_control; if ((cflag & CBAUD) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - else + else if ((old_termios->c_cflag & CBAUD) == B0) priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; -- cgit v0.10.2 From 9ac2feb22b5b821d81463bef92698ef7682a3145 Mon Sep 17 00:00:00 2001 From: Santiago Garcia Mantinan Date: Mon, 19 Mar 2012 18:17:00 +0100 Subject: USB: option: re-add NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED to option_id array Re-add NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED to option_id array Signed-off-by: Santiago Garcia Mantinan Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 836cfa9..f4465cc 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -708,6 +708,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) }, + { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) }, -- cgit v0.10.2 From 3a450850e2bb0f92cacb12da90fe98eccd105468 Mon Sep 17 00:00:00 2001 From: Aleksey Babahin Date: Tue, 20 Mar 2012 00:46:31 +0400 Subject: USB: serial: metro-usb: Fix idProduct for Uni-Directional mode. The right idProduct for Metrologic Bar Code Scanner in Uni-Directional Serial Emulation mode is 0x0700. Also rename idProduct for Bi-Directional mode to be a bit more informative. Signed-off-by: Aleksey Babahin Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 6e1622f..08d16e8 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -27,8 +27,8 @@ /* Product information. */ #define FOCUS_VENDOR_ID 0x0C2E -#define FOCUS_PRODUCT_ID 0x0720 -#define FOCUS_PRODUCT_ID_UNI 0x0710 +#define FOCUS_PRODUCT_ID_BI 0x0720 +#define FOCUS_PRODUCT_ID_UNI 0x0700 #define METROUSB_SET_REQUEST_TYPE 0x40 #define METROUSB_SET_MODEM_CTRL_REQUEST 10 @@ -47,7 +47,7 @@ struct metrousb_private { /* Device table list. */ static struct usb_device_id id_table[] = { - { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID) }, + { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) }, { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) }, { }, /* Terminating entry. */ }; -- cgit v0.10.2 From 891a3b1fddb24b4b53426685bd0390bb74c9b5b3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 28 Mar 2012 16:10:49 -0400 Subject: USB: fix bug in serial driver unregistration This patch (as1536) fixes a bug in the USB serial core. Unloading and reloading a serial driver while a serial device is plugged in causes errors because of the code in usb_serial_disconnect() that tries to make sure the port_remove method is called. With the new order of driver registration introduced in the 3.4 kernel, this is definitely not the right thing to do (if indeed it ever was). The patch removes that whole section code, along with the mechanism for keeping track of each port's registration state, which is no longer needed. The driver core can handle all that stuff for us. Note: This has been tested only with one or two USB serial drivers. In theory, other drivers might still run into trouble. But if they do, it will be the fault of the drivers, not of this patch -- that is, the drivers will need to be fixed. Signed-off-by: Alan Stern Reported-and-tested-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 7f547dc..ed8adb0 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -60,8 +60,6 @@ static int usb_serial_device_probe(struct device *dev) retval = -ENODEV; goto exit; } - if (port->dev_state != PORT_REGISTERING) - goto exit; driver = port->serial->type; if (driver->port_probe) { @@ -98,9 +96,6 @@ static int usb_serial_device_remove(struct device *dev) if (!port) return -ENODEV; - if (port->dev_state != PORT_UNREGISTERING) - return retval; - device_remove_file(&port->dev, &dev_attr_port_number); driver = port->serial->type; diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 69230f0..5413bd5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1070,17 +1070,12 @@ int usb_serial_probe(struct usb_interface *interface, port = serial->port[i]; dev_set_name(&port->dev, "ttyUSB%d", port->number); dbg ("%s - registering %s", __func__, dev_name(&port->dev)); - port->dev_state = PORT_REGISTERING; device_enable_async_suspend(&port->dev); retval = device_add(&port->dev); - if (retval) { + if (retval) dev_err(&port->dev, "Error registering port device, " "continuing\n"); - port->dev_state = PORT_UNREGISTERED; - } else { - port->dev_state = PORT_REGISTERED; - } } usb_serial_console_init(debug, minor); @@ -1124,22 +1119,8 @@ void usb_serial_disconnect(struct usb_interface *interface) } kill_traffic(port); cancel_work_sync(&port->work); - if (port->dev_state == PORT_REGISTERED) { - - /* Make sure the port is bound so that the - * driver's port_remove method is called. - */ - if (!port->dev.driver) { - int rc; - - port->dev.driver = - &serial->type->driver; - rc = device_bind_driver(&port->dev); - } - port->dev_state = PORT_UNREGISTERING; + if (device_is_registered(&port->dev)) device_del(&port->dev); - port->dev_state = PORT_UNREGISTERED; - } } } serial->type->disconnect(serial); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index fbb666b..4742838 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -28,13 +28,6 @@ /* parity check flag */ #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) -enum port_dev_state { - PORT_UNREGISTERED, - PORT_REGISTERING, - PORT_REGISTERED, - PORT_UNREGISTERING, -}; - /* USB serial flags */ #define USB_SERIAL_WRITE_BUSY 0 @@ -124,7 +117,6 @@ struct usb_serial_port { char throttle_req; unsigned long sysrq; /* sysrq timeout */ struct device dev; - enum port_dev_state dev_state; }; #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev) -- cgit v0.10.2 From cd4376e23a59a2adf3084cb5f4a523e6d5fd4e49 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 28 Mar 2012 15:56:17 -0400 Subject: USB: don't ignore suspend errors for root hubs This patch (as1532) fixes a mistake in the USB suspend code. When the system is going to sleep, we should ignore errors in powering down USB devices, because they don't really matter. The devices will go to low power anyway when the entire USB bus gets suspended (except for SuperSpeed devices; maybe they will need special treatment later). However we should not ignore errors in suspending root hubs, especially if the error indicates that the suspend raced with a wakeup request. Doing so might leave the bus powered on while the system was supposed to be asleep, or it might cause the suspend of the root hub's parent controller device to fail, or it might cause a wakeup request to be ignored. The patch fixes the problem by ignoring errors only when the device in question is not a root hub. Signed-off-by: Alan Stern Reported-by: Chen Peter CC: Tested-by: Chen Peter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f8e2d6d..9a56635 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1189,8 +1189,13 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) if (status == 0) { status = usb_suspend_device(udev, msg); - /* Again, ignore errors during system sleep transitions */ - if (!PMSG_IS_AUTO(msg)) + /* + * Ignore errors from non-root-hub devices during + * system sleep transitions. For the most part, + * these devices should go to low power anyway when + * the entire bus is suspended. + */ + if (udev->parent && !PMSG_IS_AUTO(msg)) status = 0; } -- cgit v0.10.2 From 8430eac2f6a3c2adce22d490e2ab8bb50d59077a Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Mon, 9 Apr 2012 16:32:16 +0200 Subject: netfilter: nf_ct_ipv4: handle invalid IPv4 and IPv6 packets consistently IPv6 conntrack marked invalid packets as INVALID and let the user drop those by an explicit rule, while IPv4 conntrack dropped such packets itself. IPv4 conntrack is changed so that it marks INVALID packets and let the user to drop them. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index de9da21..750b06a 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -74,12 +74,12 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph); if (iph == NULL) - return -NF_DROP; + return -NF_ACCEPT; /* Conntrack defragments packets, we might still see fragments * inside ICMP packets though. */ if (iph->frag_off & htons(IP_OFFSET)) - return -NF_DROP; + return -NF_ACCEPT; *dataoff = nhoff + (iph->ihl << 2); *protonum = iph->protocol; -- cgit v0.10.2 From fca5430d48d53eaf103498c33fd0d1984b9f448b Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Mon, 26 Mar 2012 21:19:40 +0100 Subject: USB: ftdi_sio: fix status line change handling for TIOCMIWAIT and TIOCGICOUNT Handling of TIOCMIWAIT was changed by commit 1d749f9afa657f6ee9336b2bc1fcd750a647d157 USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers FTDI_STATUS_B0_MASK does not indicate the changed modem status lines, it indicates the value of the current modem status lines. An xor is still required to determine which lines have changed. The count was only being incremented if the line was high. The only reason TIOCMIWAIT still worked was because the status packet is repeated every 1ms, so the count was always changing. The wakeup itself still ran based on the status lines changing. This change fixes handling of updates to the modem status lines and allows multiple processes to use TIOCMIWAIT concurrently. Tested with two processes waiting on different status lines being toggled independently. Signed-off-by: Simon Arlott Cc: Uwe Bonnes Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ff8605b..c02e460 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -75,7 +75,7 @@ struct ftdi_private { unsigned long last_dtr_rts; /* saved modem control outputs */ struct async_icount icount; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status, diff_status; /* Used for TIOCMIWAIT */ + char prev_status; /* Used for TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ struct usb_serial_port *port; __u16 interface; /* FT2232C, FT2232H or FT4232H port interface @@ -1982,17 +1982,19 @@ static int ftdi_process_packet(struct tty_struct *tty, N.B. packet may be processed more than once, but differences are only processed once. */ status = packet[0] & FTDI_STATUS_B0_MASK; - if (status & FTDI_RS0_CTS) - priv->icount.cts++; - if (status & FTDI_RS0_DSR) - priv->icount.dsr++; - if (status & FTDI_RS0_RI) - priv->icount.rng++; - if (status & FTDI_RS0_RLSD) - priv->icount.dcd++; if (status != priv->prev_status) { - priv->diff_status |= status ^ priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); + char diff_status = status ^ priv->prev_status; + + if (diff_status & FTDI_RS0_CTS) + priv->icount.cts++; + if (diff_status & FTDI_RS0_DSR) + priv->icount.dsr++; + if (diff_status & FTDI_RS0_RI) + priv->icount.rng++; + if (diff_status & FTDI_RS0_RLSD) + priv->icount.dcd++; + + wake_up_interruptible_all(&priv->delta_msr_wait); priv->prev_status = status; } -- cgit v0.10.2 From 876ae50d94b02f3f523aa451b45ec5fb9c25d221 Mon Sep 17 00:00:00 2001 From: Simon Arlott Date: Mon, 26 Mar 2012 23:27:59 +0100 Subject: USB: ftdi_sio: fix race condition in TIOCMIWAIT, and abort of TIOCMIWAIT when the device is removed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two issues here, one is that the device is generating spurious very fast modem status line changes somewhere: CTS becomes high then low 18µs later: [121226.924373] ftdi_process_packet: prev rng=0 dsr=10 dcd=0 cts=6 [121226.924378] ftdi_process_packet: status=10 prev=00 diff=10 [121226.924382] ftdi_process_packet: now rng=0 dsr=10 dcd=0 cts=7 (wake_up_interruptible is called) [121226.924391] ftdi_process_packet: prev rng=0 dsr=10 dcd=0 cts=7 [121226.924394] ftdi_process_packet: status=00 prev=10 diff=10 [121226.924397] ftdi_process_packet: now rng=0 dsr=10 dcd=0 cts=8 (wake_up_interruptible is called) This wakes up the task in TIOCMIWAIT: [121226.924405] ftdi_ioctl: 19451 rng=0->0 dsr=10->10 dcd=0->0 cts=6->8 (wait from 20:51:46 returns and observes both changes) Which then calls TIOCMIWAIT again: 20:51:46.400239 ioctl(3, TIOCMIWAIT, 0x20) = 0 22:11:09.441818 ioctl(3, TIOCMGET, [TIOCM_DTR|TIOCM_RTS]) = 0 22:11:09.442812 ioctl(3, TIOCMIWAIT, 0x20) = -1 EIO (Input/output error) (the second wake_up_interruptible takes effect and an I/O error occurs) The other issue is that TIOCMIWAIT will wait forever (unless the task is interrupted) if the device is removed. This change removes the -EIO return that occurs if the counts don't appear to have changed. Multiple counts may have been processed as one or the waiting task may have started waiting after recording the current count. It adds a bool to indicate that the device has been removed so that TIOCMIWAIT doesn't wait forever, and wakes up any tasks so that they can return -EIO. Signed-off-by: Simon Arlott Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index c02e460..02e7f2d 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -76,6 +76,7 @@ struct ftdi_private { struct async_icount icount; wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ char prev_status; /* Used for TIOCMIWAIT */ + bool dev_gone; /* Used to abort TIOCMIWAIT */ char transmit_empty; /* If transmitter is empty or not */ struct usb_serial_port *port; __u16 interface; /* FT2232C, FT2232H or FT4232H port interface @@ -1681,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) init_waitqueue_head(&priv->delta_msr_wait); priv->flags = ASYNC_LOW_LATENCY; + priv->dev_gone = false; if (quirk && quirk->port_probe) quirk->port_probe(priv); @@ -1839,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) dbg("%s", __func__); + priv->dev_gone = true; + wake_up_interruptible_all(&priv->delta_msr_wait); + remove_sysfs_attrs(port); kref_put(&priv->kref, ftdi_sio_priv_release); @@ -2397,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty, */ case TIOCMIWAIT: cprev = priv->icount; - while (1) { + while (!priv->dev_gone) { interruptible_sleep_on(&priv->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; cnow = priv->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || @@ -2414,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty, } cprev = cnow; } - /* not reached */ + return -EIO; break; case TIOCSERGETLSR: return get_lsr_info(port, (struct serial_struct __user *)arg); -- cgit v0.10.2 From c5d703dcc776cb542b41665f2b7e2ba054efb4a7 Mon Sep 17 00:00:00 2001 From: Anton Samokhvalov Date: Wed, 4 Apr 2012 22:26:01 +0400 Subject: USB: sierra: add support for Sierra Wireless MC7710 Just add new device id. 3G works fine, LTE not tested. Signed-off-by: Anton Samokhvalov Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index f14465a..fdd5aa2 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -289,6 +289,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */ { USB_DEVICE(0x1199, 0x6859) }, /* Sierra Wireless AirCard 885 E */ { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */ + { USB_DEVICE(0x1199, 0x68A2) }, /* Sierra Wireless MC7710 */ /* Sierra Wireless C885 */ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)}, /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */ -- cgit v0.10.2 From 879d38e6bc36d73b0ac40ec9b0d839fda9fa8b1a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 Apr 2012 15:24:18 -0400 Subject: USB: fix race between root-hub suspend and remote wakeup This patch (as1533) fixes a race between root-hub suspend and remote wakeup. If a wakeup event occurs while a root hub is suspending, it might not cause the suspend to fail. Although the host controller drivers check for pending wakeup events at the start of their bus_suspend routines, they generally do not check for wakeup events while the routines are running. In addition, if a wakeup event occurs any time after khubd is frozen and before the root hub is fully suspended, it might not cause a system sleep transition to fail. For example, the host controller drivers do not fail root-hub suspends when a connect-change event is pending. To fix both these issues, this patch causes hcd_bus_suspend() to query the controller driver's hub_status_data method after a root hub is suspended, if the root hub is enabled for wakeup. Any pending status changes will count as wakeup events, causing the root hub to be resumed and the overall suspend to fail with -EBUSY. A significant point is that not all events are reflected immediately in the status bits. Both EHCI and UHCI controllers notify the CPU when remote wakeup begins on a port, but the port's suspend-change status bit doesn't get set until after the port has completed the transition out of the suspend state, some 25 milliseconds later. Consequently, the patch will interpret any nonzero return value from hub_status_data as indicating a pending event, even if none of the status bits are set in the data buffer. Follow-up patches make the necessary changes to ehci-hcd and uhci-hcd. Signed-off-by: Alan Stern CC: Sarah Sharp CC: Chen Peter-B29397 Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 9d7fc9a..140d3e1 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1978,6 +1978,18 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) if (status == 0) { usb_set_device_state(rhdev, USB_STATE_SUSPENDED); hcd->state = HC_STATE_SUSPENDED; + + /* Did we race with a root-hub wakeup event? */ + if (rhdev->do_remote_wakeup) { + char buffer[6]; + + status = hcd->driver->hub_status_data(hcd, buffer); + if (status != 0) { + dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n"); + hcd_bus_resume(rhdev, PMSG_AUTO_RESUME); + status = -EBUSY; + } + } } else { spin_lock_irq(&hcd_root_hub_lock); if (!HCD_DEAD(hcd)) { -- cgit v0.10.2 From a448e4dc25303fe551e4dafe16c8c7c34f1b9d82 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 Apr 2012 15:24:30 -0400 Subject: EHCI: keep track of ports being resumed and indicate in hub_status_data This patch (as1537) adds a bit-array to ehci-hcd for keeping track of which ports are undergoing a resume transition. If any of the bits are set when ehci_hub_status_data() is called, the routine will return a nonzero value even if no ports have any status changes pending. This will allow usbcore to handle races between root-hub suspend and port wakeup. Signed-off-by: Alan Stern CC: Sarah Sharp CC: Chen Peter-B29397 Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 057cdda..806cc95 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -347,6 +347,8 @@ static int ehci_reset (struct ehci_hcd *ehci) if (ehci->debug) dbgp_external_startup(); + ehci->port_c_suspend = ehci->suspended_ports = + ehci->resuming_ports = 0; return retval; } @@ -939,6 +941,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) * like usb_port_resume() does. */ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); + set_bit(i, &ehci->resuming_ports); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 256fbd4..38fe076 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -223,15 +223,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) * remote wakeup, we must fail the suspend. */ if (hcd->self.root_hub->do_remote_wakeup) { - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - if (ehci->reset_done[port] != 0) { - spin_unlock_irq(&ehci->lock); - ehci_dbg(ehci, "suspend failed because " - "port %d is resuming\n", - port + 1); - return -EBUSY; - } + if (ehci->resuming_ports) { + spin_unlock_irq(&ehci->lock); + ehci_dbg(ehci, "suspend failed because a port is resuming\n"); + return -EBUSY; } } @@ -554,16 +549,12 @@ static int ehci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp, status = 0; + u32 temp, status; u32 mask; int ports, i, retval = 1; unsigned long flags; u32 ppcd = 0; - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ - if (ehci->rh_state != EHCI_RH_RUNNING) - return 0; - /* init status to no-changes */ buf [0] = 0; ports = HCS_N_PORTS (ehci->hcs_params); @@ -572,6 +563,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) retval++; } + /* Inform the core about resumes-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = ehci->resuming_ports; + /* Some boards (mostly VIA?) report bogus overcurrent indications, * causing massive log spam unless we completely ignore them. It * may be relevant that VIA VT8235 controllers, where PORT_POWER is @@ -846,6 +842,7 @@ static int ehci_hub_control ( ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESUME), status_reg); + clear_bit(wIndex, &ehci->resuming_ports); retval = handshake(ehci, status_reg, PORT_RESUME, 0, 2000 /* 2msec */); if (retval != 0) { @@ -864,6 +861,7 @@ static int ehci_hub_control ( ehci->reset_done[wIndex])) { status |= USB_PORT_STAT_C_RESET << 16; ehci->reset_done [wIndex] = 0; + clear_bit(wIndex, &ehci->resuming_ports); /* force reset to complete */ ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), @@ -884,8 +882,10 @@ static int ehci_hub_control ( ehci_readl(ehci, status_reg)); } - if (!(temp & (PORT_RESUME|PORT_RESET))) + if (!(temp & (PORT_RESUME|PORT_RESET))) { ehci->reset_done[wIndex] = 0; + clear_bit(wIndex, &ehci->resuming_ports); + } /* transfer dedicated ports to the companion hc */ if ((temp & PORT_CONNECT) && @@ -920,6 +920,7 @@ static int ehci_hub_control ( status |= USB_PORT_STAT_SUSPEND; } else if (test_bit(wIndex, &ehci->suspended_ports)) { clear_bit(wIndex, &ehci->suspended_ports); + clear_bit(wIndex, &ehci->resuming_ports); ehci->reset_done[wIndex] = 0; if (temp & PORT_PE) set_bit(wIndex, &ehci->port_c_suspend); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 3de48a2..73544bd 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -224,6 +224,7 @@ static int tegra_ehci_hub_control( temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); /* start resume signalling */ ehci_writel(ehci, temp | PORT_RESUME, status_reg); + set_bit(wIndex-1, &ehci->resuming_ports); spin_unlock_irqrestore(&ehci->lock, flags); msleep(20); @@ -236,6 +237,7 @@ static int tegra_ehci_hub_control( pr_err("%s: timeout waiting for SUSPEND\n", __func__); ehci->reset_done[wIndex-1] = 0; + clear_bit(wIndex-1, &ehci->resuming_ports); tegra->port_resuming = 1; goto done; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 8f9acbc..2694ed6 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -117,6 +117,8 @@ struct ehci_hcd { /* one per controller */ the change-suspend feature turned on */ unsigned long suspended_ports; /* which ports are suspended */ + unsigned long resuming_ports; /* which ports have + started to resume */ /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ -- cgit v0.10.2 From b446b96fd11b69b7c4ecd47d869cff9094fd8802 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 3 Apr 2012 15:24:43 -0400 Subject: UHCI: hub_status_data should indicate if ports are resuming This patch (as1538) causes uhci_hub_status_data() to return a nonzero value when any port is undergoing a resume transition while the root hub is suspended. This will allow usbcore to handle races between root-hub suspend and port wakeup. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 045cde4..768d542 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -196,11 +196,12 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) status = get_hub_status_data(uhci, buf); switch (uhci->rh_state) { - case UHCI_RH_SUSPENDING: case UHCI_RH_SUSPENDED: /* if port change, ask to be resumed */ - if (status || uhci->resuming_ports) + if (status || uhci->resuming_ports) { + status = 1; usb_hcd_resume_root_hub(hcd); + } break; case UHCI_RH_AUTO_STOPPED: -- cgit v0.10.2 From 83dbbdbb38666e20a75fad2294cf1df77c52f121 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 9 Apr 2012 16:56:18 -0700 Subject: android, lowmemorykiller: remove task handoff notifier The task handoff notifier leaks task_struct since it never gets freed after the callback returns NOTIFY_OK, which means it is responsible for doing so. It turns out the lowmemorykiller actually doesn't need this notifier at all. It's used to prevent unnecessary killing by waiting for a thread to exit as a result of lowmem_shrink(), however, it's possible to do this in the same way the kernel oom killer works by setting TIF_MEMDIE and avoid killing if we're still waiting for it to exit. The kernel oom killer will already automatically set TIF_MEMDIE for threads that are attempting to allocate memory that have a fatal signal. The thread selected by lowmem_shrink() will have such a signal after the lowmemorykiller sends it a SIGKILL, so this won't result in an unnecessary use of memory reserves for the thread to exit. This has the added benefit that we don't have to rely on CONFIG_PROFILING to prevent needlessly killing tasks. Reported-by: Werner Landgraf Cc: stable@vger.kernel.org Signed-off-by: David Rientjes Acked-by: Colin Cross Signed-off-by: Linus Torvalds diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 052b43e..b91e4bc 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -55,7 +55,6 @@ static int lowmem_minfree[6] = { }; static int lowmem_minfree_size = 4; -static struct task_struct *lowmem_deathpending; static unsigned long lowmem_deathpending_timeout; #define lowmem_print(level, x...) \ @@ -64,24 +63,6 @@ static unsigned long lowmem_deathpending_timeout; printk(x); \ } while (0) -static int -task_notify_func(struct notifier_block *self, unsigned long val, void *data); - -static struct notifier_block task_nb = { - .notifier_call = task_notify_func, -}; - -static int -task_notify_func(struct notifier_block *self, unsigned long val, void *data) -{ - struct task_struct *task = data; - - if (task == lowmem_deathpending) - lowmem_deathpending = NULL; - - return NOTIFY_OK; -} - static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) { struct task_struct *tsk; @@ -97,19 +78,6 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) int other_file = global_page_state(NR_FILE_PAGES) - global_page_state(NR_SHMEM); - /* - * If we already have a death outstanding, then - * bail out right away; indicating to vmscan - * that we have nothing further to offer on - * this pass. - * - * Note: Currently you need CONFIG_PROFILING - * for this to work correctly. - */ - if (lowmem_deathpending && - time_before_eq(jiffies, lowmem_deathpending_timeout)) - return 0; - if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) @@ -148,6 +116,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) if (!p) continue; + if (test_tsk_thread_flag(p, TIF_MEMDIE) && + time_before_eq(jiffies, lowmem_deathpending_timeout)) { + task_unlock(p); + rcu_read_unlock(); + return 0; + } oom_score_adj = p->signal->oom_score_adj; if (oom_score_adj < min_score_adj) { task_unlock(p); @@ -174,15 +148,9 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", selected->pid, selected->comm, selected_oom_score_adj, selected_tasksize); - /* - * If CONFIG_PROFILING is off, then we don't want to stall - * the killer by setting lowmem_deathpending. - */ -#ifdef CONFIG_PROFILING - lowmem_deathpending = selected; lowmem_deathpending_timeout = jiffies + HZ; -#endif send_sig(SIGKILL, selected, 0); + set_tsk_thread_flag(selected, TIF_MEMDIE); rem -= selected_tasksize; } lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", @@ -198,7 +166,6 @@ static struct shrinker lowmem_shrinker = { static int __init lowmem_init(void) { - task_handoff_register(&task_nb); register_shrinker(&lowmem_shrinker); return 0; } @@ -206,7 +173,6 @@ static int __init lowmem_init(void) static void __exit lowmem_exit(void) { unregister_shrinker(&lowmem_shrinker); - task_handoff_unregister(&task_nb); } module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); -- cgit v0.10.2 From 258f742635360175564e9470eb060ff4d4b984e7 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Mon, 9 Apr 2012 17:59:03 -0700 Subject: modpost: Fix modpost license checking of vmlinux.o Commit f02e8a6596b7 ("module: Sort exported symbols") sorts symbols placing each of them in its own elf section. This sorting and merging into the canonical sections are done by the linker. Unfortunately modpost to generate Module.symvers file parses vmlinux.o (which is not linked yet) and all modules object files (which aren't linked yet). These aren't sanitized by the linker yet. That breaks modpost that can't detect license properly for modules. This patch makes modpost aware of the new exported symbols structure. [ This above is a slightly corrected version of the explanation of the problem, copied from commit 62a2635610db ("modpost: Fix modpost's license checking V3"). That commit fixed the problem for module object files, but not for vmlinux.o. This patch fixes modpost for vmlinux.o. ] Signed-off-by: Frank Rowand Signed-off-by: Alessio Igor Bogani Signed-off-by: Linus Torvalds diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3f01fd9..c4e7d15 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -132,8 +132,10 @@ static struct module *new_module(char *modname) /* strip trailing .o */ s = strrchr(p, '.'); if (s != NULL) - if (strcmp(s, ".o") == 0) + if (strcmp(s, ".o") == 0) { *s = '\0'; + mod->is_dot_o = 1; + } /* add to list */ mod->name = p; @@ -587,7 +589,8 @@ static void handle_modversions(struct module *mod, struct elf_info *info, unsigned int crc; enum export export; - if (!is_vmlinux(mod->name) && strncmp(symname, "__ksymtab", 9) == 0) + if ((!is_vmlinux(mod->name) || mod->is_dot_o) && + strncmp(symname, "__ksymtab", 9) == 0) export = export_from_secname(info, get_secindex(info, sym)); else export = export_from_sec(info, get_secindex(info, sym)); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 2031119..51207e4 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -113,6 +113,7 @@ struct module { int has_cleanup; struct buffer dev_table_buf; char srcversion[25]; + int is_dot_o; }; struct elf_info { -- cgit v0.10.2 From 156d14da4cfc4fe01b705d6e2d22e44c0a2dbecd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 9 Apr 2012 10:16:32 +0200 Subject: sound: sound/oss/msnd_pinnacle.c: add vfrees At the point of this error-handling code, HAVE_DSPCODEH may be undefined, so free INITCODE and PERMCODE as done elsewhere. A jump and label are introduced to avoid code duplication. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index 2c79d60..536c4c0 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -1294,6 +1294,8 @@ static int __init calibrate_adc(WORD srate) static int upload_dsp_code(void) { + int ret = 0; + msnd_outb(HPBLKSEL_0, dev.io + HP_BLKS); #ifndef HAVE_DSPCODEH INITCODESIZE = mod_firmware_load(INITCODEFILE, &INITCODE); @@ -1312,7 +1314,8 @@ static int upload_dsp_code(void) memcpy_toio(dev.base, PERMCODE, PERMCODESIZE); if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) { printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); - return -ENODEV; + ret = -ENODEV; + goto out; } #ifdef HAVE_DSPCODEH printk(KERN_INFO LOGNAME ": DSP firmware uploaded (resident)\n"); @@ -1320,12 +1323,13 @@ static int upload_dsp_code(void) printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n"); #endif +out: #ifndef HAVE_DSPCODEH vfree(INITCODE); vfree(PERMCODE); #endif - return 0; + return ret; } #ifdef MSND_CLASSIC -- cgit v0.10.2 From 38be95dd3d314bd393a26f6e441ae2c57ef7f064 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 9 Apr 2012 10:16:35 +0200 Subject: ALSA: sound/isa/sscape.c: add missing resource-release code At the point of this error-handling code, both regions and the dma have been allocated, so free it as done in previous and subsequent error-handling code. Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index b4a6aa9..8490f59 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1019,13 +1019,15 @@ static int __devinit create_sscape(int dev, struct snd_card *card) irq_cfg = get_irq_config(sscape->type, irq[dev]); if (irq_cfg == INVALID_IRQ) { snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); - return -ENXIO; + err = -ENXIO; + goto _release_dma; } mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); if (mpu_irq_cfg == INVALID_IRQ) { snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); - return -ENXIO; + err = -ENXIO; + goto _release_dma; } /* -- cgit v0.10.2 From 08f1ec8a594c60bf3856e3c45b6d15fd691d90bb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 10 Apr 2012 17:21:35 +1000 Subject: powerpc: Fix page fault with lockdep regression commit a546498f3bf9aac311c66f965186373aee2ca0b0 introduced a regression on 32-bit when irq tracing is enabled by exposing an old bug in our irq tracing code for exception entry. The code would save and restore some GPRs around the calls to the C lockdep code, however, it tries to be too smart for its own good and restores some of the GPRs from the exception frame (as saved there on exception entry). However, for page faults, we do replace those GPRs with arguments to do_page_fault before we call transfer_to_handler and so restoring from the exception frame is plain wrong in this case. This was fine as long as we didn't touch the interrupt state when taking page fault, but when I started doing it, it would trigger the lockdep calls and the bug. This fixes it by cleaning up that code a bit. It did create a small stack frame for the sake of backtraces, so let's make it a bit bigger and use it to save and restore the stuff we care about. Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 3e57a00..ba3aeb4 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -206,40 +206,43 @@ reenable_mmu: /* re-enable mmu so we can */ andi. r10,r10,MSR_EE /* Did EE change? */ beq 1f - /* Save handler and return address into the 2 unused words - * of the STACK_FRAME_OVERHEAD (sneak sneak sneak). Everything - * else can be recovered from the pt_regs except r3 which for - * normal interrupts has been set to pt_regs and for syscalls - * is an argument, so we temporarily use ORIG_GPR3 to save it - */ - stw r9,8(r1) - stw r11,12(r1) - stw r3,ORIG_GPR3(r1) /* * The trace_hardirqs_off will use CALLER_ADDR0 and CALLER_ADDR1. * If from user mode there is only one stack frame on the stack, and * accessing CALLER_ADDR1 will cause oops. So we need create a dummy * stack frame to make trace_hardirqs_off happy. + * + * This is handy because we also need to save a bunch of GPRs, + * r3 can be different from GPR3(r1) at this point, r9 and r11 + * contains the old MSR and handler address respectively, + * r4 & r5 can contain page fault arguments that need to be passed + * along as well. r12, CCR, CTR, XER etc... are left clobbered as + * they aren't useful past this point (aren't syscall arguments), + * the rest is restored from the exception frame. */ + stwu r1,-32(r1) + stw r9,8(r1) + stw r11,12(r1) + stw r3,16(r1) + stw r4,20(r1) + stw r5,24(r1) andi. r12,r12,MSR_PR - beq 11f - stwu r1,-16(r1) + b 11f bl trace_hardirqs_off - addi r1,r1,16 b 12f - 11: bl trace_hardirqs_off 12: + lwz r5,24(r1) + lwz r4,20(r1) + lwz r3,16(r1) + lwz r11,12(r1) + lwz r9,8(r1) + addi r1,r1,32 lwz r0,GPR0(r1) - lwz r3,ORIG_GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) lwz r6,GPR6(r1) lwz r7,GPR7(r1) lwz r8,GPR8(r1) - lwz r9,8(r1) - lwz r11,12(r1) 1: mtctr r11 mtlr r9 bctr /* jump to handler */ -- cgit v0.10.2 From a67ada7a7239b78250c1594b0e02ca68eae848dc Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Tue, 10 Apr 2012 00:29:12 -0700 Subject: Input: elantech - reset touchpad before configuring it Acer VH40 has a Fn key toggling the touchpad on and off, but it's implemented in system firmware, and the EC chip has to receive reset command to activate this function. Also when this machine wakes up after resume, psmouse_reset is necessary to bring the touchpad back on. Signed-off-by: JJ Ding Reviewed-by: Chase Douglas Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index d2c0db1..21c68a8 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1245,6 +1245,8 @@ static void elantech_disconnect(struct psmouse *psmouse) */ static int elantech_reconnect(struct psmouse *psmouse) { + psmouse_reset(psmouse); + if (elantech_detect(psmouse, 0)) return -1; @@ -1324,6 +1326,8 @@ int elantech_init(struct psmouse *psmouse) if (!etd) return -ENOMEM; + psmouse_reset(psmouse); + etd->parity[0] = 1; for (i = 1; i < 256; i++) etd->parity[i] = etd->parity[i & (i - 1)] ^ 1; -- cgit v0.10.2 From e3dde4fba94e0ba5e1fd79ea9e5389eea1f0cfec Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Tue, 10 Apr 2012 00:30:12 -0700 Subject: Input: elantech - v4 is a clickpad, with only one button Add pointer and buttonpad properties for v4 hardware. Also, Jachiet reported that on Asus UX31, right button has no effect. It turns out v4 has only one button, the right-button effect is implemented with software when Windows driver is installed, or in firmware when touchpad is in relative mode. So remove BTN_RIGHT while at it. Reported-by: Jachiet Louis Signed-off-by: JJ Ding Reviewed-by: Chase Douglas Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 21c68a8..4790110 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -486,7 +486,6 @@ static void elantech_input_sync_v4(struct psmouse *psmouse) unsigned char *packet = psmouse->packet; input_report_key(dev, BTN_LEFT, packet[0] & 0x01); - input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); input_mt_report_pointer_emulation(dev, true); input_sync(dev); } @@ -967,6 +966,7 @@ static int elantech_set_input_params(struct psmouse *psmouse) if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width)) return -1; + __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_KEY, dev->evbit); __set_bit(EV_ABS, dev->evbit); __clear_bit(EV_REL, dev->evbit); @@ -1017,7 +1017,9 @@ static int elantech_set_input_params(struct psmouse *psmouse) */ psmouse_warn(psmouse, "couldn't query resolution data.\n"); } - + /* v4 is clickpad, with only one button. */ + __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); + __clear_bit(BTN_RIGHT, dev->keybit); __set_bit(BTN_TOOL_QUADTAP, dev->keybit); /* For X to recognize me as touchpad. */ input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0); -- cgit v0.10.2 From fb16395ee65d22882a0af30850cbf5c9b9a2962c Mon Sep 17 00:00:00 2001 From: JJ Ding Date: Tue, 10 Apr 2012 00:25:01 -0700 Subject: Input: trackpoint - use psmouse_fmt() for messages Use psmouse_*() macros introduced in commit b5d21704361ee. Signed-off-by: JJ Ding Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 22b2180..f310249 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -304,7 +304,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) return 0; if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { - printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); + psmouse_warn(psmouse, "failed to get extended button data\n"); button_info = 0; } @@ -326,16 +326,18 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); if (error) { - printk(KERN_ERR - "trackpoint.c: failed to create sysfs attributes, error: %d\n", - error); + psmouse_err(psmouse, + "failed to create sysfs attributes, error: %d\n", + error); kfree(psmouse->private); psmouse->private = NULL; return -1; } - printk(KERN_INFO "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", - firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); + psmouse_info(psmouse, + "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", + firmware_id, + (button_info & 0xf0) >> 4, button_info & 0x0f); return 0; } -- cgit v0.10.2 From dff2aa7af8c96a11f75d858859f0e0c78b193d12 Mon Sep 17 00:00:00 2001 From: Kautuk Consul Date: Mon, 2 Apr 2012 18:19:49 +0100 Subject: ARM: 7368/1: fault.c: correct how the tsk->[maj|min]_flt gets incremented commit 8878a539ff19a43cf3729e7562cd528f490246ae was done by me to make the page fault handler retryable as well as interruptible. Due to this commit, there is a mistake in the way in which tsk->[maj|min]_flt counter gets incremented for VM_FAULT_ERROR: If VM_FAULT_ERROR is returned in the fault flags by handle_mm_fault, then either maj_flt or min_flt will get incremented. This is wrong as in the case of a VM_FAULT_ERROR we need to be skip ahead to the error handling code in do_page_fault. Added a check after the call to __do_page_fault() to check for (fault & VM_FAULT_ERROR). Signed-off-by: Kautuk Consul Signed-off-by: Russell King diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 9055b5a..f074675 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -320,7 +320,7 @@ retry: */ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); - if (flags & FAULT_FLAG_ALLOW_RETRY) { + if (!(fault & VM_FAULT_ERROR) && flags & FAULT_FLAG_ALLOW_RETRY) { if (fault & VM_FAULT_MAJOR) { tsk->maj_flt++; perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, -- cgit v0.10.2 From 34af657916332e89564566bc8d35e3e06cc0c236 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 5 Apr 2012 19:42:10 +0100 Subject: ARM: 7377/1: vic: re-read status register before dispatching each IRQ handler handle_IRQ may briefly cause interrupts to be re-enabled during soft IRQ processing on the exit path, leading to nested handling of VIC interrupts. Since the current code does not re-read the VIC_IRQ_STATUS register, this can lead to multiple invocations of the same interrupt handler and spurious interrupts to be reported. This patch changes the VIC interrupt dispatching code to re-read the status register each time, avoiding duplicate invocations of the same handler. Acked-and-Tested-by: H Hartley Sweeten Reviewed-by: Jamie Iles Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 7a66311..7e288f9 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -427,19 +427,18 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) /* * Handle each interrupt in a single VIC. Returns non-zero if we've - * handled at least one interrupt. This does a single read of the - * status register and handles all interrupts in order from LSB first. + * handled at least one interrupt. This reads the status register + * before handling each interrupt, which is necessary given that + * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. */ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) { u32 stat, irq; int handled = 0; - stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); - while (stat) { + while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { irq = ffs(stat) - 1; handle_IRQ(irq_find_mapping(vic->domain, irq), regs); - stat &= ~(1 << irq); handled = 1; } -- cgit v0.10.2 From 9886f444129171569461d8c39983e16f4871e3b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 10 Apr 2012 10:50:55 +0200 Subject: itimer: Use printk_once instead of WARN_ONCE David pointed out, that WARN_ONCE() to report usage of an deprecated misfeature make folks unhappy. Use printk_once() instead. Andrew told me to stop grumbling and to remove the silly typecast while touching the file. Reported-by: David Rientjes Cc: Andrew Morton Signed-off-by: Thomas Gleixner diff --git a/kernel/itimer.c b/kernel/itimer.c index c70369a..8d262b4 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -285,9 +285,10 @@ SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, if(copy_from_user(&set_buffer, value, sizeof(set_buffer))) return -EFAULT; } else { - memset((char *) &set_buffer, 0, sizeof(set_buffer)); - WARN_ONCE(1, "setitimer: new_value pointer is NULL." - " Misfeature support will be removed\n"); + memset(&set_buffer, 0, sizeof(set_buffer)); + printk_once(KERN_WARNING "%s calls setitimer() with new_value NULL pointer." + " Misfeature support will be removed\n", + current->comm); } error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL); -- cgit v0.10.2 From 4de833c337509916b7931982734d858191cf0700 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 5 Apr 2012 12:58:22 -0600 Subject: drm/radeon: replace udelay with mdelay for long timeouts Some architectures require that delays longer than a few miliseconds are called through mdelay. This was triggered on ARM randconfig builds. Signed-off-by: Arnd Bergmann Signed-off-by: Mathieu Poirier Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 81801c1..fe33d35 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2553,7 +2553,7 @@ static void r100_pll_errata_after_data(struct radeon_device *rdev) * or the chip could hang on a subsequent access */ if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) { - udelay(5000); + mdelay(5); } /* This function is required to workaround a hardware bug in some (all?) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 391bd26..de71243 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2839,7 +2839,7 @@ void r600_rlc_stop(struct radeon_device *rdev) /* r7xx asics need to soft reset RLC before halting */ WREG32(SRBM_SOFT_RESET, SOFT_RESET_RLC); RREG32(SRBM_SOFT_RESET); - udelay(15000); + mdelay(15); WREG32(SRBM_SOFT_RESET, 0); RREG32(SRBM_SOFT_RESET); } diff --git a/drivers/gpu/drm/radeon/r600_cp.c b/drivers/gpu/drm/radeon/r600_cp.c index 84c5462..75ed17c 100644 --- a/drivers/gpu/drm/radeon/r600_cp.c +++ b/drivers/gpu/drm/radeon/r600_cp.c @@ -407,7 +407,7 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_UDELAY(15000); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); fw_data = (const __be32 *)dev_priv->me_fw->data; @@ -500,7 +500,7 @@ static void r700_cp_load_microcode(drm_radeon_private_t *dev_priv) RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_UDELAY(15000); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); fw_data = (const __be32 *)dev_priv->pfp_fw->data; @@ -1797,7 +1797,7 @@ static void r600_cp_init_ring_buffer(struct drm_device *dev, RADEON_WRITE(R600_GRBM_SOFT_RESET, R600_SOFT_RESET_CP); RADEON_READ(R600_GRBM_SOFT_RESET); - DRM_UDELAY(15000); + mdelay(15); RADEON_WRITE(R600_GRBM_SOFT_RESET, 0); diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c index 6ae0c75..9c6b29a 100644 --- a/drivers/gpu/drm/radeon/radeon_clocks.c +++ b/drivers/gpu/drm/radeon/radeon_clocks.c @@ -633,7 +633,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp &= ~(R300_SCLK_FORCE_VAP); tmp |= RADEON_SCLK_FORCE_CP; WREG32_PLL(RADEON_SCLK_CNTL, tmp); - udelay(15000); + mdelay(15); tmp = RREG32_PLL(R300_SCLK_CNTL2); tmp &= ~(R300_SCLK_FORCE_TCL | @@ -651,12 +651,12 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= (RADEON_ENGIN_DYNCLK_MODE | (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT)); WREG32_PLL(RADEON_CLK_PWRMGT_CNTL, tmp); - udelay(15000); + mdelay(15); tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL); tmp |= RADEON_SCLK_DYN_START_CNTL; WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp); - udelay(15000); + mdelay(15); /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200 to lockup randomly, leave them as set by BIOS. @@ -696,7 +696,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= RADEON_SCLK_MORE_FORCEON; } WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); - udelay(15000); + mdelay(15); } /* RV200::A11 A12, RV250::A11 A12 */ @@ -709,7 +709,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp |= RADEON_TCL_BYPASS_DISABLE; WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp); } - udelay(15000); + mdelay(15); /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK) */ tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); @@ -722,14 +722,14 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) RADEON_PIXCLK_TMDS_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - udelay(15000); + mdelay(15); tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); tmp |= (RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp); - udelay(15000); + mdelay(15); } } else { /* Turn everything OFF (ForceON to everything) */ @@ -861,7 +861,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) } WREG32_PLL(RADEON_SCLK_CNTL, tmp); - udelay(16000); + mdelay(16); if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) { @@ -870,7 +870,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) R300_SCLK_FORCE_GA | R300_SCLK_FORCE_CBA); WREG32_PLL(R300_SCLK_CNTL2, tmp); - udelay(16000); + mdelay(16); } if (rdev->flags & RADEON_IS_IGP) { @@ -878,7 +878,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp &= ~(RADEON_FORCEON_MCLKA | RADEON_FORCEON_YCLKA); WREG32_PLL(RADEON_MCLK_CNTL, tmp); - udelay(16000); + mdelay(16); } if ((rdev->family == CHIP_RV200) || @@ -887,7 +887,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL); tmp |= RADEON_SCLK_MORE_FORCEON; WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp); - udelay(16000); + mdelay(16); } tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL); @@ -900,7 +900,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable) RADEON_PIXCLK_TMDS_ALWAYS_ONb); WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp); - udelay(16000); + mdelay(16); tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL); tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb | diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 81fc100..2cad9fd 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2845,7 +2845,7 @@ bool radeon_combios_external_tmds_setup(struct drm_encoder *encoder) case 4: val = RBIOS16(index); index += 2; - udelay(val * 1000); + mdelay(val); break; case 6: slave_addr = id & 0xff; @@ -3044,7 +3044,7 @@ static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) udelay(150); break; case 2: - udelay(1000); + mdelay(1); break; case 3: while (tmp--) { @@ -3075,13 +3075,13 @@ static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset) /*mclk_cntl |= 0x00001111;*//* ??? */ WREG32_PLL(RADEON_MCLK_CNTL, mclk_cntl); - udelay(10000); + mdelay(10); #endif WREG32_PLL (RADEON_CLK_PWRMGT_CNTL, tmp & ~RADEON_CG_NO1_DEBUG_0); - udelay(10000); + mdelay(10); } break; default: diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 2f46e0c..42db254 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -88,7 +88,7 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl |= RADEON_LVDS_PLL_EN; WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); - udelay(1000); + mdelay(1); lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; @@ -101,7 +101,7 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT)); if (is_mac) lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; - udelay(panel_pwr_delay * 1000); + mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); break; case DRM_MODE_DPMS_STANDBY: @@ -118,10 +118,10 @@ static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON); } - udelay(panel_pwr_delay * 1000); + mdelay(panel_pwr_delay); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl); - udelay(panel_pwr_delay * 1000); + mdelay(panel_pwr_delay); break; } @@ -656,7 +656,7 @@ static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_enc WREG32(RADEON_DAC_MACRO_CNTL, tmp); - udelay(2000); + mdelay(2); if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT) found = connector_status_connected; @@ -1499,7 +1499,7 @@ static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN; WREG32(RADEON_DAC_CNTL2, tmp); - udelay(10000); + mdelay(10); if (ASIC_IS_R300(rdev)) { if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B) -- cgit v0.10.2 From 6587eb82617f7913c13e750e73e13fa9c829863c Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Fri, 6 Apr 2012 17:38:24 -0400 Subject: drm/savage: fix integer overflows in savage_bci_cmdbuf() Since cmdbuf->size and cmdbuf->nbox are from userspace, a large value would overflow the allocation size, leading to out-of-bounds access. Signed-off-by: Xi Wang Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index 031aaaf..b6d8608 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -988,7 +988,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ * for locking on FreeBSD. */ if (cmdbuf->size) { - kcmd_addr = kmalloc(cmdbuf->size * 8, GFP_KERNEL); + kcmd_addr = kmalloc_array(cmdbuf->size, 8, GFP_KERNEL); if (kcmd_addr == NULL) return -ENOMEM; @@ -1015,8 +1015,8 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ cmdbuf->vb_addr = kvb_addr; } if (cmdbuf->nbox) { - kbox_addr = kmalloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), - GFP_KERNEL); + kbox_addr = kmalloc_array(cmdbuf->nbox, sizeof(struct drm_clip_rect), + GFP_KERNEL); if (kbox_addr == NULL) { ret = -ENOMEM; goto done; -- cgit v0.10.2 From afceb9319f21b18ee3bc15ee9a5f92e18ef8a8c9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Apr 2012 17:05:41 -0400 Subject: drm/radeon/kms: fix DVO setup on some r4xx chips Some r4xx chips have the wrong frev in the DVOEncoderControl table. It should always be 1 on r4xx. Fixes modesetting on DVO on r4xx chips with the bad frev. Reported by twied on #radeon. Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index e607c4d..2d39f99 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -230,6 +230,10 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action) if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; + /* some R4xx chips have the wrong frev */ + if (rdev->family <= CHIP_RV410) + frev = 1; + switch (frev) { case 1: switch (crev) { -- cgit v0.10.2 From fa4da365bc7772c2cd6d5405bdf151612455f957 Mon Sep 17 00:00:00 2001 From: Suresh Siddha Date: Mon, 9 Apr 2012 15:41:44 -0700 Subject: clockevents: tTack broadcast device mode change in tick_broadcast_switch_to_oneshot() In the commit 77b0d60c5adf39c74039e2142a1d3cd1e4d53799, "clockevents: Leave the broadcast device in shutdown mode when not needed", we were bailing out too quickly in tick_broadcast_switch_to_oneshot(), with out tracking the broadcast device mode change to 'TICKDEV_MODE_ONESHOT'. This breaks the platforms which need broadcast device oneshot services during deep idle states. tick_broadcast_oneshot_control() thinks that it is in periodic mode and fails to take proper decisions based on the CLOCK_EVT_NOTIFY_BROADCAST_[ENTER, EXIT] notifications during deep idle entry/exit. Fix this by tracking the broadcast device mode as 'TICKDEV_MODE_ONESHOT', before leaving the broadcast HW device in shutdown mode if there are no active requests for the moment. Reported-and-tested-by: Santosh Shilimkar Signed-off-by: Suresh Siddha Cc: johnstul@us.ibm.com Link: http://lkml.kernel.org/r/1334011304.12400.81.camel@sbsiddha-desk.sc.intel.com Signed-off-by: Thomas Gleixner diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index e883f57..bf57abd 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -575,10 +575,12 @@ void tick_broadcast_switch_to_oneshot(void) unsigned long flags; raw_spin_lock_irqsave(&tick_broadcast_lock, flags); + + tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT; + if (cpumask_empty(tick_get_broadcast_mask())) goto end; - tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT; bc = tick_broadcast_device.evtdev; if (bc) tick_broadcast_setup_oneshot(bc); -- cgit v0.10.2 From 07153c6ec074257ade76a461429b567cff2b3a1e Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 3 Apr 2012 22:02:01 +0200 Subject: netfilter: nf_ct_ipv4: packets with wrong ihl are invalid It was reported that the Linux kernel sometimes logs: klogd: [2629147.402413] kernel BUG at net / netfilter / nf_conntrack_proto_tcp.c: 447! klogd: [1072212.887368] kernel BUG at net / netfilter / nf_conntrack_proto_tcp.c: 392 ipv4_get_l4proto() in nf_conntrack_l3proto_ipv4.c and tcp_error() in nf_conntrack_proto_tcp.c should catch malformed packets, so the errors at the indicated lines - TCP options parsing - should not happen. However, tcp_error() relies on the "dataoff" offset to the TCP header, calculated by ipv4_get_l4proto(). But ipv4_get_l4proto() does not check bogus ihl values in IPv4 packets, which then can slip through tcp_error() and get caught at the TCP options parsing routines. The patch fixes ipv4_get_l4proto() by invalidating packets with bogus ihl value. The patch closes netfilter bugzilla id 771. Signed-off-by: Jozsef Kadlecsik Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 750b06a..cf73cc7 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -84,6 +84,14 @@ static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, *dataoff = nhoff + (iph->ihl << 2); *protonum = iph->protocol; + /* Check bogus IP headers */ + if (*dataoff > skb->len) { + pr_debug("nf_conntrack_ipv4: bogus IPv4 packet: " + "nhoff %u, ihl %u, skblen %u\n", + nhoff, iph->ihl << 2, skb->len); + return -NF_ACCEPT; + } + return NF_ACCEPT; } -- cgit v0.10.2 From 6ba900676bec8baaf61aa2f85b7345c0e65774d9 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Sat, 7 Apr 2012 16:08:28 +0000 Subject: netfilter: nf_conntrack: fix incorrect logic in nf_conntrack_init_net in function nf_conntrack_init_net,when nf_conntrack_timeout_init falied, we should call nf_conntrack_ecache_fini to do rollback. but the current code calls nf_conntrack_timeout_fini. Signed-off-by: Gao feng Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3cc4487..729f157 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1592,7 +1592,7 @@ static int nf_conntrack_init_net(struct net *net) return 0; err_timeout: - nf_conntrack_timeout_fini(net); + nf_conntrack_ecache_fini(net); err_ecache: nf_conntrack_tstamp_fini(net); err_tstamp: -- cgit v0.10.2 From ca9248d8337d525c2d2b26a1d8314478d15707fb Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Tue, 10 Apr 2012 08:56:04 -0400 Subject: GFS2: Allow caching of rindex glock This patch allows caching of the rindex glock. We were previously setting the GL_NOCACHE bit when the glock was released. That forced the rindex inode to be invalidated, which caused us to re-read rindex at the next access. However, it caused the glock to be unnecessarily bounced around the cluster. This patch allows the glock to remain cached, but it still causes the rindex to be re-read once it has been written to by gfs2_grow. Ben and I have tested single-node gfs2_grow cases and I've tested clustered gfs2_grow cases on my four-node cluster. Signed-off-by: Bob Peterson Signed-off-by: Steven Whitehouse diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 38b7a74..9b2ff0e 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -807,7 +807,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, if (inode == sdp->sd_rindex) { adjust_fs_space(inode); - ip->i_gh.gh_flags |= GL_NOCACHE; + sdp->sd_rindex_uptodate = 0; } brelse(dibh); @@ -873,7 +873,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, if (inode == sdp->sd_rindex) { adjust_fs_space(inode); - ip->i_gh.gh_flags |= GL_NOCACHE; + sdp->sd_rindex_uptodate = 0; } brelse(dibh); -- cgit v0.10.2 From fae3d88a5c56c3f836e95c4516da883a48612437 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Tue, 10 Apr 2012 17:00:35 +0800 Subject: ALSA: hda - hide HDMI/ELD printks unless snd.debug=2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove two warnings when CONFIG_SND_DEBUG is not set: sound/pci/hda/patch_hdmi.c: In function ‘hdmi_intrinsic_event’: sound/pci/hda/patch_hdmi.c:761:6: warning: unused variable ‘eldv’ [-Wunused-variable] sound/pci/hda/patch_hdmi.c:760:6: warning: unused variable ‘pd’ [-Wunused-variable] Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index b6e0f57..bc05668 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -325,6 +325,13 @@ void release_and_free_resource(struct resource *res); /* --- */ +/* sound printk debug levels */ +enum { + SND_PR_ALWAYS, + SND_PR_DEBUG, + SND_PR_VERBOSE, +}; + #if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK) __printf(4, 5) void __snd_printk(unsigned int level, const char *file, int line, @@ -354,6 +361,8 @@ void __snd_printk(unsigned int level, const char *file, int line, */ #define snd_printd(fmt, args...) \ __snd_printk(1, __FILE__, __LINE__, fmt, ##args) +#define _snd_printd(level, fmt, args...) \ + __snd_printk(level, __FILE__, __LINE__, fmt, ##args) /** * snd_BUG - give a BUG warning message and stack trace @@ -383,6 +392,7 @@ void __snd_printk(unsigned int level, const char *file, int line, #else /* !CONFIG_SND_DEBUG */ #define snd_printd(fmt, args...) do { } while (0) +#define _snd_printd(level, fmt, args...) do { } while (0) #define snd_BUG() do { } while (0) static inline int __snd_bug_on(int cond) { diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index b58b4b1..4c054f4 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -418,7 +418,7 @@ static void hdmi_show_short_audio_desc(struct cea_sad *a) else buf2[0] = '\0'; - printk(KERN_INFO "HDMI: supports coding type %s:" + _snd_printd(SND_PR_VERBOSE, "HDMI: supports coding type %s:" " channels = %d, rates =%s%s\n", cea_audio_coding_type_names[a->format], a->channels, @@ -442,14 +442,14 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) { int i; - printk(KERN_INFO "HDMI: detected monitor %s at connection type %s\n", + _snd_printd(SND_PR_VERBOSE, "HDMI: detected monitor %s at connection type %s\n", e->monitor_name, eld_connection_type_names[e->conn_type]); if (e->spk_alloc) { char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; snd_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - printk(KERN_INFO "HDMI: available speakers:%s\n", buf); + _snd_printd(SND_PR_VERBOSE, "HDMI: available speakers:%s\n", buf); } for (i = 0; i < e->sad_count; i++) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 540cd13..83f345f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -757,8 +757,6 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) struct hdmi_spec *spec = codec->spec; int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int pin_nid; - int pd = !!(res & AC_UNSOL_RES_PD); - int eldv = !!(res & AC_UNSOL_RES_ELDV); int pin_idx; struct hda_jack_tbl *jack; @@ -768,9 +766,10 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) pin_nid = jack->nid; jack->jack_dirty = 1; - printk(KERN_INFO + _snd_printd(SND_PR_VERBOSE, "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, pd, eldv); + codec->addr, pin_nid, + !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); pin_idx = pin_nid_to_pin_index(spec, pin_nid); if (pin_idx < 0) @@ -992,7 +991,7 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) if (eld->monitor_present) eld_valid = !!(present & AC_PINSENSE_ELDV); - printk(KERN_INFO + _snd_printd(SND_PR_VERBOSE, "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", codec->addr, pin_nid, eld->monitor_present, eld_valid); -- cgit v0.10.2 From 3a48d1c08fe0db79b8647b7042e6a077588b374a Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 10 Apr 2012 14:15:41 +0100 Subject: i2c: prevent spurious interrupt on Designware controllers Don't call i2c_enable on resume because it causes a spurious interrupt. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Kirill A. Shutemov Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 37f4211..00e8f21 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -182,7 +182,6 @@ static int i2c_dw_pci_resume(struct device *dev) pci_restore_state(pdev); i2c_dw_init(i2c); - i2c_dw_enable(i2c); return 0; } -- cgit v0.10.2 From 6e7beb7ec8b8c3a1927d4d02c33a0e2a8e72eec3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 10 Apr 2012 08:31:48 -0700 Subject: ARM: S5PV210: Fix compiler warning in dma.c file Fixes the following warning: warning: 'dma_dmamask' defined but not used [-Wunused-variable] Signed-off-by: Sachin Kamat Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-s5pv210/dma.c b/arch/arm/mach-s5pv210/dma.c index 86ce62f..b8337e2 100644 --- a/arch/arm/mach-s5pv210/dma.c +++ b/arch/arm/mach-s5pv210/dma.c @@ -33,8 +33,6 @@ #include #include -static u64 dma_dmamask = DMA_BIT_MASK(32); - static u8 pdma0_peri[] = { DMACH_UART0_RX, DMACH_UART0_TX, -- cgit v0.10.2 From 60806225cdad7f582fcf5e2d7a089486f9718f2f Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Tue, 10 Apr 2012 08:37:59 -0700 Subject: ARM: EXYNOS: Add PDMA and MDMA physical base address defines Add PDMA and MDMA physical base address macros which is require for EXYNOS5 of_dev_auxdata setup. Signed-off-by: Thomas Abraham [kgene.kim@samsung.com: changed dma channel fo mdma1] Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 024d38f..6e6d11f 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -89,6 +89,10 @@ #define EXYNOS4_PA_MDMA1 0x12840000 #define EXYNOS4_PA_PDMA0 0x12680000 #define EXYNOS4_PA_PDMA1 0x12690000 +#define EXYNOS5_PA_MDMA0 0x10800000 +#define EXYNOS5_PA_MDMA1 0x11C10000 +#define EXYNOS5_PA_PDMA0 0x121A0000 +#define EXYNOS5_PA_PDMA1 0x121B0000 #define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000 #define EXYNOS4_PA_SYSMMU_SSS 0x10A50000 diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 0d26f50..4711c89 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c @@ -45,7 +45,7 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = { "exynos4210-uart.3", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL), OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL), - OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.2", NULL), + OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL), {}, }; -- cgit v0.10.2 From 55158c886a0c43765140673d2343d3119d34a25a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 10 Apr 2012 09:03:03 -0700 Subject: Input: gpio_mouse - use linux/gpio.h rather than asm/gpio.h Direct usage of the asm include has long been deprecated by the introduction of gpiolib. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c index a9ad8e1..39fe9b7 100644 --- a/drivers/input/mouse/gpio_mouse.c +++ b/drivers/input/mouse/gpio_mouse.c @@ -12,9 +12,9 @@ #include #include #include +#include #include -#include /* * Timer function which is run every scan_ms ms when the device is opened. -- cgit v0.10.2 From fcff311c938c95c90573c060d37648df00e45017 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 21 Mar 2012 12:32:32 +0000 Subject: staging: sep: Fix sign of error One of our errors wasn't negative as intended. Fix this. (Found by Hillf Danton) While we are at it turn user causable messages down to dev_dbg level in the ioctl paths. Signed-off-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c index ad54c2e..f1701bc 100644 --- a/drivers/staging/sep/sep_main.c +++ b/drivers/staging/sep/sep_main.c @@ -3114,7 +3114,7 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) current->pid); if (1 == test_bit(SEP_LEGACY_SENDMSG_DONE_OFFSET, &call_status->status)) { - dev_warn(&sep->pdev->dev, + dev_dbg(&sep->pdev->dev, "[PID%d] dcb prep needed before send msg\n", current->pid); error = -EPROTO; @@ -3122,9 +3122,9 @@ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } if (!arg) { - dev_warn(&sep->pdev->dev, + dev_dbg(&sep->pdev->dev, "[PID%d] dcb null arg\n", current->pid); - error = EINVAL; + error = -EINVAL; goto end_function; } -- cgit v0.10.2 From eaa004a4ba3264d17d7e6882948a7980e14e9d20 Mon Sep 17 00:00:00 2001 From: Gerard Snitselaar Date: Fri, 23 Mar 2012 03:21:05 -0700 Subject: staging/vme: Fix module parameters loopback should be declared bool, and variant probably shouldn't be const. Signed-off-by: Gerard Snitselaar Acked-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c index 9fedc44..573c800 100644 --- a/drivers/staging/vme/devices/vme_pio2_core.c +++ b/drivers/staging/vme/devices/vme_pio2_core.c @@ -35,10 +35,10 @@ static int vector[PIO2_CARDS_MAX]; static int vector_num; static int level[PIO2_CARDS_MAX]; static int level_num; -static const char *variant[PIO2_CARDS_MAX]; +static char *variant[PIO2_CARDS_MAX]; static int variant_num; -static int loopback; +static bool loopback; static int pio2_match(struct vme_dev *); static int __devinit pio2_probe(struct vme_dev *); -- cgit v0.10.2 From 50637f050e88fb175135de62a53be33c374a5349 Mon Sep 17 00:00:00 2001 From: Dan Magenheimer Date: Fri, 23 Mar 2012 09:40:15 -0700 Subject: staging: ramster: unbreak my heart The just-merged ramster staging driver was dependent on a cleanup patch in cleancache, so was marked CONFIG_BROKEN until that patch could be merged. That cleancache patch is now merged (and the correct SHA of the cleancache patch is 3167760f83899ccda312b9ad9306ec9e5dda06d4 rather than the one shown in the comment removed in the patch below). So remove the CONFIG_BROKEN now and the comment that is no longer true... Signed-off-by: Dan Magenheimer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig index 8b57b87..4af1f8d 100644 --- a/drivers/staging/ramster/Kconfig +++ b/drivers/staging/ramster/Kconfig @@ -1,10 +1,6 @@ -# Dependency on CONFIG_BROKEN is because there is a commit dependency -# on a cleancache naming change to be submitted by Konrad Wilk -# a39c00ded70339603ffe1b0ffdf3ade85bcf009a "Merge branch 'stable/cleancache.v13' -# into linux-next. Once this commit is present, BROKEN can be removed config RAMSTER bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem" - depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && BROKEN + depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM select LZO_COMPRESS select LZO_DECOMPRESS default n -- cgit v0.10.2 From 218f4d437d69b4621f36affd52dcd6343597149a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Sat, 24 Mar 2012 07:19:25 +0100 Subject: staging:iio:core add missing increment of loop index in iio_map_array_unregister() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit staging:iio:core add missing increment of loop index in iio_map_array_unregister() Signed-off-by: Lothar Waßmann Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/iio/inkern.c b/drivers/staging/iio/inkern.c index de2c8ea..ef07a02 100644 --- a/drivers/staging/iio/inkern.c +++ b/drivers/staging/iio/inkern.c @@ -82,6 +82,7 @@ int iio_map_array_unregister(struct iio_dev *indio_dev, ret = -ENODEV; goto error_ret; } + i++; } error_ret: mutex_unlock(&iio_map_list_lock); -- cgit v0.10.2 From 401c90e56c48b1c642507a8bec91b7ae21f1156e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sat, 24 Mar 2012 23:39:18 +0100 Subject: staging/media/as102: Don't call release_firmware() on uninitialized variable If, in drivers/staging/media/as102/as102_fw.c::as102_fw_upload(), the call cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); should fail and return NULL so that we jump to the 'error:' label, then we'll end up calling 'release_firmware(firmware);' with 'firmware' still uninitialized - not good. The easy fix is to just initialize 'firmware' to NULL when we declare it, since release_firmware() deals gracefully with being passed NULL pointers. Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c index 43ebc43..1075fb1 100644 --- a/drivers/staging/media/as102/as102_fw.c +++ b/drivers/staging/media/as102/as102_fw.c @@ -165,7 +165,7 @@ error: int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap) { int errno = -EFAULT; - const struct firmware *firmware; + const struct firmware *firmware = NULL; unsigned char *cmd_buf = NULL; char *fw1, *fw2; struct usb_device *dev = bus_adap->usb_dev; -- cgit v0.10.2 From 4ca5218e3939685c2325fc0a0a1ac8150272c93f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Mar 2012 09:43:54 +0300 Subject: Staging: vt6655-6: check keysize before memcpy() We need to check the we don't copy too much memory. This comes from a copy_from_user() in the ioctl. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c index 0ff8d7b..774b0d4 100644 --- a/drivers/staging/vt6655/key.c +++ b/drivers/staging/vt6655/key.c @@ -655,6 +655,9 @@ bool KeybSetDefaultKey ( return (false); } + if (uKeyLength > MAX_KEY_LEN) + return false; + pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = true; for(ii=0;iiKeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF; diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index 27bb523..ee62a06 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -684,6 +684,9 @@ BOOL KeybSetDefaultKey( return (FALSE); } + if (uKeyLength > MAX_KEY_LEN) + return false; + pTable->KeyTable[MAX_KEY_TABLE-1].bInUse = TRUE; for (ii = 0; ii < ETH_ALEN; ii++) pTable->KeyTable[MAX_KEY_TABLE-1].abyBSSID[ii] = 0xFF; -- cgit v0.10.2 From 0d05568ac79bfc595f1eadc3e0fd7a20a45f7b69 Mon Sep 17 00:00:00 2001 From: wwang Date: Tue, 27 Mar 2012 16:43:11 +0800 Subject: staging:rts_pstor:Fix possible panic by NULL pointer dereference rtsx_transport.c (rtsx_transfer_sglist_adma_partial): pointer struct scatterlist *sg, which is mapped in dma_map_sg, is used as an iterator in later transfer operation. It is corrupted and passed to dma_unmap_sg, thus causing fatal unmap of some erroneous address. Fix it by duplicating *sg_ptr for iterating. Signed-off-by: wwang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c index 4e3d2c1..9b2e5c9 100644 --- a/drivers/staging/rts_pstor/rtsx_transport.c +++ b/drivers/staging/rts_pstor/rtsx_transport.c @@ -335,6 +335,7 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, int sg_cnt, i, resid; int err = 0; long timeleft; + struct scatterlist *sg_ptr; u32 val = TRIG_DMA; if ((sg == NULL) || (num_sg <= 0) || !offset || !index) @@ -371,7 +372,7 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, sg_cnt = dma_map_sg(&(rtsx->pci->dev), sg, num_sg, dma_dir); resid = size; - + sg_ptr = sg; chip->sgi = 0; /* Usually the next entry will be @sg@ + 1, but if this sg element * is part of a chained scatterlist, it could jump to the start of @@ -379,14 +380,14 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, * the proper sg */ for (i = 0; i < *index; i++) - sg = sg_next(sg); + sg_ptr = sg_next(sg_ptr); for (i = *index; i < sg_cnt; i++) { dma_addr_t addr; unsigned int len; u8 option; - addr = sg_dma_address(sg); - len = sg_dma_len(sg); + addr = sg_dma_address(sg_ptr); + len = sg_dma_len(sg_ptr); RTSX_DEBUGP("DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len); @@ -415,7 +416,7 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, if (!resid) break; - sg = sg_next(sg); + sg_ptr = sg_next(sg_ptr); } RTSX_DEBUGP("SG table count = %d\n", chip->sgi); -- cgit v0.10.2 From b5bd70a162492a76ee49065605ca15d484bb623a Mon Sep 17 00:00:00 2001 From: wwang Date: Tue, 27 Mar 2012 16:43:20 +0800 Subject: staging:rts_pstor:Avoid "Bad target number" message when probing driver Avoid "Bad LUN" and "Bad target number" message by setting the supported max_lun and max_id for the scsi host Signed-off-by: wwang Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c index a7feb3e..1dccd93 100644 --- a/drivers/staging/rts_pstor/rtsx.c +++ b/drivers/staging/rts_pstor/rtsx.c @@ -1000,6 +1000,11 @@ static int __devinit rtsx_probe(struct pci_dev *pci, rtsx_init_chip(dev->chip); + /* set the supported max_lun and max_id for the scsi host + * NOTE: the minimal value of max_id is 1 */ + host->max_id = 1; + host->max_lun = dev->chip->max_lun; + /* Start up our control thread */ th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME); if (IS_ERR(th)) { -- cgit v0.10.2 From 678b7c17073a9e383f204c3e8e0000821afb6103 Mon Sep 17 00:00:00 2001 From: Chris Kelly Date: Thu, 29 Mar 2012 12:09:45 +0000 Subject: staging: ozwpan: Added new maintainer for ozwpan Added Rupesh Gujare to MAINTAINERS file and contact in TODO file for ozwpan driver. Signed-off-by: Chris Kelly Signed-off-by: Greg Kroah-Hartman diff --git a/MAINTAINERS b/MAINTAINERS index 2dcfca8..d87ad18 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6466,6 +6466,7 @@ S: Odd Fixes F: drivers/staging/olpc_dcon/ STAGING - OZMO DEVICES USB OVER WIFI DRIVER +M: Rupesh Gujare M: Chris Kelly S: Maintained F: drivers/staging/ozwpan/ diff --git a/drivers/staging/ozwpan/TODO b/drivers/staging/ozwpan/TODO index f7a9c12..c2d30a7 100644 --- a/drivers/staging/ozwpan/TODO +++ b/drivers/staging/ozwpan/TODO @@ -8,5 +8,7 @@ TODO: - code review by USB developer community. - testing with as many devices as possible. -Please send any patches for this driver to Chris Kelly +Please send any patches for this driver to +Rupesh Gujare +Chris Kelly and Greg Kroah-Hartman . -- cgit v0.10.2 From 3fd654c22c7b002e8681accaed50a6d46656d815 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 29 Mar 2012 21:52:57 +0300 Subject: Staging: rts_pstor: off by one in for loop I already fixed the other similar for loop in this file. I'm not sure how I missed this one. We use seg_no+1 inside the loop so we can't go right up to the end of the loop. Also if we don't break out of the loop then we end up past the end of the array, but with this fix we end up on the last element. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c index 66341df..f9a4498 100644 --- a/drivers/staging/rts_pstor/ms.c +++ b/drivers/staging/rts_pstor/ms.c @@ -3498,7 +3498,8 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 log_blk++; - for (seg_no = 0; seg_no < sizeof(ms_start_idx)/2; seg_no++) { + for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; + seg_no++) { if (log_blk < ms_start_idx[seg_no+1]) break; } -- cgit v0.10.2 From f4477e90b3ea4c40466e8f418cf41a17aef09192 Mon Sep 17 00:00:00 2001 From: Nitin Gupta Date: Mon, 2 Apr 2012 09:13:56 -0500 Subject: staging: zsmalloc: fix memory leak This patch fixes a memory leak in zsmalloc where the first subpage of each zspage is leaked when the zspage is freed. Signed-off-by: Nitin Gupta Acked-by: Seth Jennings Acked-by: Dan Magenheimer Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c index 09caa4f..917461c 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/drivers/staging/zsmalloc/zsmalloc-main.c @@ -267,33 +267,39 @@ static unsigned long obj_idx_to_offset(struct page *page, return off + obj_idx * class_size; } +static void reset_page(struct page *page) +{ + clear_bit(PG_private, &page->flags); + clear_bit(PG_private_2, &page->flags); + set_page_private(page, 0); + page->mapping = NULL; + page->freelist = NULL; + reset_page_mapcount(page); +} + static void free_zspage(struct page *first_page) { - struct page *nextp, *tmp; + struct page *nextp, *tmp, *head_extra; BUG_ON(!is_first_page(first_page)); BUG_ON(first_page->inuse); - nextp = (struct page *)page_private(first_page); + head_extra = (struct page *)page_private(first_page); - clear_bit(PG_private, &first_page->flags); - clear_bit(PG_private_2, &first_page->flags); - set_page_private(first_page, 0); - first_page->mapping = NULL; - first_page->freelist = NULL; - reset_page_mapcount(first_page); + reset_page(first_page); __free_page(first_page); /* zspage with only 1 system page */ - if (!nextp) + if (!head_extra) return; - list_for_each_entry_safe(nextp, tmp, &nextp->lru, lru) { + list_for_each_entry_safe(nextp, tmp, &head_extra->lru, lru) { list_del(&nextp->lru); - clear_bit(PG_private_2, &nextp->flags); - nextp->index = 0; + reset_page(nextp); __free_page(nextp); } + reset_page(head_extra); + __free_page(head_extra); } /* Initialize a newly allocated zspage */ -- cgit v0.10.2 From be0775ac140dd80a1d60fb7e71ec60e649c14ff8 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 5 Apr 2012 10:34:56 -0500 Subject: staging: drm/omap: move where DMM driver is registered Not sure what triggered the change in behavior, but seems to result in recursively acquiring a mutex and hanging on boot. But omap_drm_init() seems a much more sane place to register the driver for the DMM sub-device. Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 3df5b4c..620b8d5 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -803,9 +803,6 @@ static void pdev_shutdown(struct platform_device *device) static int pdev_probe(struct platform_device *device) { DBG("%s", device->name); - if (platform_driver_register(&omap_dmm_driver)) - dev_err(&device->dev, "DMM registration failed\n"); - return drm_platform_init(&omap_drm_driver, device); } @@ -833,6 +830,10 @@ struct platform_driver pdev = { static int __init omap_drm_init(void) { DBG("init"); + if (platform_driver_register(&omap_dmm_driver)) { + /* we can continue on without DMM.. so not fatal */ + dev_err(NULL, "DMM registration failed\n"); + } return platform_driver_register(&pdev); } -- cgit v0.10.2 From 40f32d9345bee0b24d3317b498e79b02e4be27f4 Mon Sep 17 00:00:00 2001 From: Preetham Chandru Date: Mon, 9 Apr 2012 18:05:01 +0530 Subject: staging: iio: ak8975: Remove i2c client data corruption i2c client data set is of type struct indio_dev pointer and hence the pointer returned from i2c_get_clientdata() should be assigned to an object of type struct indio_dev and not to an object of type struct ak8975_data. Also in ak8975_probe() client data should be set first before calling ak8975_setup() as it references the client data. Signed-off-by: Preetham Chandru R CC: Laxman Dewangan Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c index d5ddac3..ebc2d08 100644 --- a/drivers/staging/iio/magnetometer/ak8975.c +++ b/drivers/staging/iio/magnetometer/ak8975.c @@ -108,7 +108,8 @@ static const int ak8975_index_to_reg[] = { static int ak8975_write_data(struct i2c_client *client, u8 reg, u8 val, u8 mask, u8 shift) { - struct ak8975_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak8975_data *data = iio_priv(indio_dev); u8 regval; int ret; @@ -159,7 +160,8 @@ static int ak8975_read_data(struct i2c_client *client, */ static int ak8975_setup(struct i2c_client *client) { - struct ak8975_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak8975_data *data = iio_priv(indio_dev); u8 device_id; int ret; @@ -509,6 +511,7 @@ static int ak8975_probe(struct i2c_client *client, goto exit_gpio; } data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); /* Perform some basic start-of-day setup of the device. */ err = ak8975_setup(client); if (err < 0) { @@ -516,7 +519,6 @@ static int ak8975_probe(struct i2c_client *client, goto exit_free_iio; } - i2c_set_clientdata(client, indio_dev); data->client = client; mutex_init(&data->lock); data->eoc_irq = client->irq; -- cgit v0.10.2 From 099f5d01a6f73712e17552679aa724e021809a6e Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 21 Mar 2012 10:18:33 -0700 Subject: android: make persistent_ram based drivers depend on HAVE_MEMBLOCK m68k doesn't have memblock_reserve, which causes a build failure with allmodconfig. Make PERSISTENT_RAM and RAM_CONSOLE depend on HAVE_MEMBLOCK. Reported-by: Geert Uytterhoeven Reported-by: Paul Gortmaker Signed-off-by: Colin Cross Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 08a3b11..eb1dee2 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -27,13 +27,14 @@ config ANDROID_LOGGER config ANDROID_PERSISTENT_RAM bool + depends on HAVE_MEMBLOCK select REED_SOLOMON select REED_SOLOMON_ENC8 select REED_SOLOMON_DEC8 config ANDROID_RAM_CONSOLE bool "Android RAM buffer console" - depends on !S390 && !UML + depends on !S390 && !UML && HAVE_MEMBLOCK select ANDROID_PERSISTENT_RAM default n -- cgit v0.10.2 From 5d92f71e687e4e1a0bed489707d1ec58fe1100de Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 21 Mar 2012 09:24:57 +0800 Subject: Staging: android: timed_gpio: Fix resource leak in timed_gpio_probe error paths If gpio_request fails, we need to free all allocated resources. Current code uses wrong array index to access gpio_data array. So current code actually frees gpio_data[i].gpio by j times. This patch moves the error handling code to err_out and thus improves readability. Signed-off-by: Axel Lin Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index bc723ef..45c522c 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -85,7 +85,7 @@ static int timed_gpio_probe(struct platform_device *pdev) struct timed_gpio_platform_data *pdata = pdev->dev.platform_data; struct timed_gpio *cur_gpio; struct timed_gpio_data *gpio_data, *gpio_dat; - int i, j, ret = 0; + int i, ret; if (!pdata) return -EBUSY; @@ -108,18 +108,12 @@ static int timed_gpio_probe(struct platform_device *pdev) gpio_dat->dev.get_time = gpio_get_time; gpio_dat->dev.enable = gpio_enable; ret = gpio_request(cur_gpio->gpio, cur_gpio->name); - if (ret >= 0) { - ret = timed_output_dev_register(&gpio_dat->dev); - if (ret < 0) - gpio_free(cur_gpio->gpio); - } + if (ret < 0) + goto err_out; + ret = timed_output_dev_register(&gpio_dat->dev); if (ret < 0) { - for (j = 0; j < i; j++) { - timed_output_dev_unregister(&gpio_data[i].dev); - gpio_free(gpio_data[i].gpio); - } - kfree(gpio_data); - return ret; + gpio_free(cur_gpio->gpio); + goto err_out; } gpio_dat->gpio = cur_gpio->gpio; @@ -131,6 +125,15 @@ static int timed_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_data); return 0; + +err_out: + while (--i >= 0) { + timed_output_dev_unregister(&gpio_data[i].dev); + gpio_free(gpio_data[i].gpio); + } + kfree(gpio_data); + + return ret; } static int timed_gpio_remove(struct platform_device *pdev) -- cgit v0.10.2 From 6490311f423b0d77969d6fa2ab6354b87e373bf9 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 19 Mar 2012 21:50:09 +0400 Subject: staging/xgifb: fix display on XGI Volari Z11m cards Image on Z11m cards was totally garbled due to wrong memory being selected. Add a special handling for Z11m cards. Tested on PCIe Z11 and Z11m cards. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c index 94d5c35..3650bbf 100644 --- a/drivers/staging/xgifb/vb_init.c +++ b/drivers/staging/xgifb/vb_init.c @@ -61,7 +61,7 @@ XGINew_GetXG20DRAMType(struct xgi_hw_device_info *HwDeviceExtension, } temp = xgifb_reg_get(pVBInfo->P3c4, 0x3B); /* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */ - if ((temp & 0x88) == 0x80) + if (((temp & 0x88) == 0x80) || ((temp & 0x88) == 0x08)) data = 0; /* DDR */ else data = 1; /* DDRII */ diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 2919924..60d4adf 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -152,6 +152,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) pVBInfo->pXGINew_CR97 = &XG20_CR97; if (ChipType == XG27) { + unsigned char temp; pVBInfo->MCLKData = (struct SiS_MCLKData *) XGI27New_MCLKData; pVBInfo->CR40 = XGI27_cr41; @@ -162,7 +163,13 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) pVBInfo->pCRDE = XG27_CRDE; pVBInfo->pSR40 = &XG27_SR40; pVBInfo->pSR41 = &XG27_SR41; + pVBInfo->SR15 = XG27_SR13; + /*Z11m DDR*/ + temp = xgifb_reg_get(pVBInfo->P3c4, 0x3B); + /* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */ + if (((temp & 0x88) == 0x80) || ((temp & 0x88) == 0x08)) + pVBInfo->pXGINew_CR97 = &Z11m_CR97; } if (ChipType >= XG20) { diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h index dddf261..e8d6f67 100644 --- a/drivers/staging/xgifb/vb_table.h +++ b/drivers/staging/xgifb/vb_table.h @@ -33,6 +33,13 @@ static struct XGI_ECLKDataStruct XGI340_ECLKData[] = { {0x5c, 0x23, 0x01, 166} }; +static unsigned char XG27_SR13[4][8] = { + {0x35, 0x45, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SR13 */ + {0x41, 0x51, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SR14 */ + {0x32, 0x32, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SR18 */ + {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00} /* SR1B */ +}; + static unsigned char XGI340_SR13[4][8] = { {0x35, 0x45, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SR13 */ {0x41, 0x51, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00}, /* SR14 */ @@ -71,7 +78,7 @@ static unsigned char XGI27_cr41[24][8] = { {0x20, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 0 CR41 */ {0xC4, 0x40, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 1 CR8A */ {0xC4, 0x40, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 2 CR8B */ - {0xB5, 0x13, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 3 CR40[7], + {0xB3, 0x13, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 3 CR40[7], CR99[2:0], CR45[3:0]*/ {0xf0, 0xf5, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00}, /* 4 CR59 */ @@ -2803,6 +2810,8 @@ static unsigned char XG27_CRDE[2]; static unsigned char XG27_SR40 = 0x04 ; static unsigned char XG27_SR41 = 0x00 ; +static unsigned char Z11m_CR97 = 0x80 ; + static struct XGI330_VCLKDataStruct XGI_VCLKData[] = { /* SR2B,SR2C,SR2D */ {0x1B, 0xE1, 25}, /* 00 (25.175MHz) */ -- cgit v0.10.2 From c4867936474183332db4c19791a65fdad6474fd5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Apr 2012 10:42:36 +0200 Subject: drm/i915: properly compute dp dithering for user-created modes We've only computed whether we need to fall back to 6bpc due to dp link bandwidth constrains in mode_valid, but not mode_fixup. Under various circumstances X likes to create new modes which then lack proper 6bpc flags (if required), resulting in mode_fixup failures and ultimately black screens. Chris Wilson pointed out that we still get things wrong for bpp > 24, but that should be fixed in another patch (and it'll be easier because this patch consolidates the logic). The likely culprit for this regression is commit 3d794f87238f74d80e78a7611c7fbde8a54c85c2 Author: Keith Packard Date: Wed Jan 25 08:16:25 2012 -0800 drm/i915: Force explicit bpp selection for intel_dp_link_required v2: Fix indentation and tune down the too bold claim that this should fix the world. Both noticed by Chris Wilson. v3: Try to really git add things. Reported-and-tested-by: Brice Goglin Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48170 Cc: stable@kernel.org Reviewed-by: Adam Jackson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 110552f..4b63791 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -219,14 +219,38 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes) return (max_link_clock * max_lanes * 8) / 10; } +static bool +intel_dp_adjust_dithering(struct intel_dp *intel_dp, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); + int max_lanes = intel_dp_max_lane_count(intel_dp); + int max_rate, mode_rate; + + mode_rate = intel_dp_link_required(mode->clock, 24); + max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + + if (mode_rate > max_rate) { + mode_rate = intel_dp_link_required(mode->clock, 18); + if (mode_rate > max_rate) + return false; + + if (adjusted_mode) + adjusted_mode->private_flags + |= INTEL_MODE_DP_FORCE_6BPC; + + return true; + } + + return true; +} + static int intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_dp *intel_dp = intel_attached_dp(connector); - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); - int max_lanes = intel_dp_max_lane_count(intel_dp); - int max_rate, mode_rate; if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) @@ -236,16 +260,8 @@ intel_dp_mode_valid(struct drm_connector *connector, return MODE_PANEL; } - mode_rate = intel_dp_link_required(mode->clock, 24); - max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); - - if (mode_rate > max_rate) { - mode_rate = intel_dp_link_required(mode->clock, 18); - if (mode_rate > max_rate) - return MODE_CLOCK_HIGH; - else - mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC; - } + if (!intel_dp_adjust_dithering(intel_dp, mode, NULL)) + return MODE_CLOCK_HIGH; if (mode->clock < 10000) return MODE_CLOCK_LOW; @@ -672,7 +688,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, int lane_count, clock; int max_lane_count = intel_dp_max_lane_count(intel_dp); int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; - int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + int bpp; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { @@ -686,6 +702,11 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, mode->clock = intel_dp->panel_fixed_mode->clock; } + if (!intel_dp_adjust_dithering(intel_dp, mode, adjusted_mode)) + return false; + + bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); -- cgit v0.10.2 From 58f743ee06d400a887a3e30353c69c3151eb64df Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 25 Mar 2012 20:02:55 -0400 Subject: bcma: fix build error on MIPS; implicit pcibios_enable_device The following is seen during allmodconfig builds for MIPS: drivers/bcma/driver_pci_host.c:518:2: error: implicit declaration of function 'pcibios_enable_device' [-Werror=implicit-function-declaration] cc1: some warnings being treated as errors make[3]: *** [drivers/bcma/driver_pci_host.o] Error 1 Most likey introduced by commit 49dc9577155576b10ff79f0c1486c816b01f58bf "bcma: add PCIe host controller" Add the header instead of implicitly assuming it will be present. Sounds like a good idea, but that alone doesn't fix anything. The real problem is that the Kconfig has settings related to whether PCI is possible, i.e. config BCMA_HOST_PCI_POSSIBLE bool depends on BCMA && PCI = y default y config BCMA_HOST_PCI bool "Support for BCMA on PCI-host bus" depends on BCMA_HOST_PCI_POSSIBLE ...but what is missing is that BCMA_DRIVER_PCI_HOSTMODE doesn't have any dependencies on the above. Add one. CC: Hauke Mehrtens CC: John W. Linville Signed-off-by: Paul Gortmaker Acked-by: Hauke Mehrtens Signed-off-by: John W. Linville diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index c1172da..fb7c80f 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -29,7 +29,7 @@ config BCMA_HOST_PCI config BCMA_DRIVER_PCI_HOSTMODE bool "Driver for PCI core working in hostmode" - depends on BCMA && MIPS + depends on BCMA && MIPS && BCMA_HOST_PCI help PCI core hostmode operation (external PCI bus). diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index 4e20bcf..d2097a1 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -10,6 +10,7 @@ */ #include "bcma_private.h" +#include #include #include #include -- cgit v0.10.2 From e2bc7c5f3cb8756865aa0ab140d2288f61599dda Mon Sep 17 00:00:00 2001 From: "Chen, Chien-Chia" Date: Thu, 29 Mar 2012 18:21:47 +0800 Subject: rt2x00: Fix rfkill_polling register function. Move rt2x00rfkill_register(rt2x00dev) to rt2x00lib_probe_dev function. It fixes of starting rfkill_poll function at the right time if sets hard rfkill block and reboot. rt2x00mac_rfkill_poll should be starting before bringing up the wireless interface. Signed-off-by: Chen, Chien-Chia Acked-by: Helmut Schaa CC: Kevin Chou Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index fc9901e..90cc5e7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1062,11 +1062,6 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) set_bit(DEVICE_STATE_INITIALIZED, &rt2x00dev->flags); - /* - * Register the extra components. - */ - rt2x00rfkill_register(rt2x00dev); - return 0; } @@ -1210,6 +1205,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) rt2x00link_register(rt2x00dev); rt2x00leds_register(rt2x00dev); rt2x00debug_register(rt2x00dev); + rt2x00rfkill_register(rt2x00dev); return 0; -- cgit v0.10.2 From 011afa1ed8c408d694957d2474d89dc81a60b70c Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Tue, 10 Apr 2012 12:26:11 +0530 Subject: Revert "ath9k: fix going to full-sleep on PS idle" This reverts commit c1afdaff90538ef085b756454f12b29575411214. Users have reported connection failures in 3.3.1 and suspend/resume failures in 3.4-rcX. Revert this commit for now - PS IDLE can be fixed in a clean manner later on. Cc: stable@vger.kernel.org Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 215eb25..2504ab0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -118,15 +118,13 @@ void ath9k_ps_restore(struct ath_softc *sc) if (--sc->ps_usecount != 0) goto unlock; - if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) - goto unlock; - - if (sc->ps_idle) + if (sc->ps_idle && (sc->ps_flags & PS_WAIT_FOR_TX_ACK)) mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA))) + PS_WAIT_FOR_PSPOLL_DATA | + PS_WAIT_FOR_TX_ACK))) mode = ATH9K_PM_NETWORK_SLEEP; else goto unlock; -- cgit v0.10.2 From 5fb84b1428b271f8767e0eb3fcd7231896edfaa4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 10 Apr 2012 00:56:42 +0000 Subject: tcp: restore correct limit Commit c43b874d5d714f (tcp: properly initialize tcp memory limits) tried to fix a regression added in commits 4acb4190 & 3dc43e3, but still get it wrong. Result is machines with low amount of memory have too small tcp_rmem[2] value and slow tcp receives : Per socket limit being 1/1024 of memory instead of 1/128 in old kernels, so rcv window is capped to small values. Fix this to match comment and previous behavior. Signed-off-by: Eric Dumazet Cc: Jason Wang Cc: Glauber Costa Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5d54ed3..7758a83 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3302,8 +3302,7 @@ void __init tcp_init(void) tcp_init_mem(&init_net); /* Set per-socket limits to no more than 1/128 the pressure threshold */ - limit = nr_free_buffer_pages() << (PAGE_SHIFT - 10); - limit = max(limit, 128UL); + limit = nr_free_buffer_pages() << (PAGE_SHIFT - 7); max_share = min(4UL*1024*1024, limit); sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; -- cgit v0.10.2 From 18a223e0b9ec8979320ba364b47c9772391d6d05 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Tue, 10 Apr 2012 07:59:20 +0000 Subject: tcp: fix tcp_rcv_rtt_update() use of an unscaled RTT sample Fix a code path in tcp_rcv_rtt_update() that was comparing scaled and unscaled RTT samples. The intent in the code was to only use the 'm' measurement if it was a new minimum. However, since 'm' had not yet been shifted left 3 bits but 'new_sample' had, this comparison would nearly always succeed, leading us to erroneously set our receive-side RTT estimate to the 'm' sample when that sample could be nearly 8x too high to use. The overall effect is to often cause the receive-side RTT estimate to be significantly too large (up to 40% too large for brief periods in my tests). Signed-off-by: Neal Cardwell Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e886e2f..e7b54d2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -474,8 +474,11 @@ static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep) if (!win_dep) { m -= (new_sample >> 3); new_sample += m; - } else if (m < new_sample) - new_sample = m << 3; + } else { + m <<= 3; + if (m < new_sample) + new_sample = m; + } } else { /* No previous measure. */ new_sample = m << 3; -- cgit v0.10.2 From 3ffc9cebb65f6942cd912e33e60e1f09e497e208 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 28 Mar 2012 14:55:04 -0600 Subject: gpio/sodaville: Convert sodaville driver to new irqdomain API The irqdomain api changed significantly in v3.4 which caused a build failure for this driver. Signed-off-by: Grant Likely Acked-by: Sebastian Andrzej Siewior Cc: Hans J. Koch Cc: Torben Hohn diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index edadbda..e03653d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -430,7 +430,7 @@ config GPIO_ML_IOH config GPIO_SODAVILLE bool "Intel Sodaville GPIO support" - depends on X86 && PCI && OF && BROKEN + depends on X86 && PCI && OF select GPIO_GENERIC select GENERIC_IRQ_CHIP help diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index 9ba15d3..031e5d2 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -41,7 +41,7 @@ struct sdv_gpio_chip_data { int irq_base; void __iomem *gpio_pub_base; - struct irq_domain id; + struct irq_domain *id; struct irq_chip_generic *gc; struct bgpio_chip bgpio; }; @@ -51,10 +51,9 @@ static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct sdv_gpio_chip_data *sd = gc->private; void __iomem *type_reg; - u32 irq_offs = d->irq - sd->irq_base; u32 reg; - if (irq_offs < 8) + if (d->hwirq < 8) type_reg = sd->gpio_pub_base + GPIT1R0; else type_reg = sd->gpio_pub_base + GPIT1R1; @@ -63,11 +62,11 @@ static int sdv_gpio_pub_set_type(struct irq_data *d, unsigned int type) switch (type) { case IRQ_TYPE_LEVEL_HIGH: - reg &= ~BIT(4 * (irq_offs % 8)); + reg &= ~BIT(4 * (d->hwirq % 8)); break; case IRQ_TYPE_LEVEL_LOW: - reg |= BIT(4 * (irq_offs % 8)); + reg |= BIT(4 * (d->hwirq % 8)); break; default: @@ -91,7 +90,7 @@ static irqreturn_t sdv_gpio_pub_irq_handler(int irq, void *data) u32 irq_bit = __fls(irq_stat); irq_stat &= ~BIT(irq_bit); - generic_handle_irq(sd->irq_base + irq_bit); + generic_handle_irq(irq_find_mapping(sd->id, irq_bit)); } return IRQ_HANDLED; @@ -127,7 +126,7 @@ static int sdv_xlate(struct irq_domain *h, struct device_node *node, } static struct irq_domain_ops irq_domain_sdv_ops = { - .dt_translate = sdv_xlate, + .xlate = sdv_xlate, }; static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, @@ -149,10 +148,6 @@ static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, if (ret) goto out_free_desc; - sd->id.irq_base = sd->irq_base; - sd->id.of_node = of_node_get(pdev->dev.of_node); - sd->id.ops = &irq_domain_sdv_ops; - /* * This gpio irq controller latches level irqs. Testing shows that if * we unmask & ACK the IRQ before the source of the interrupt is gone @@ -179,7 +174,10 @@ static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); - irq_domain_add(&sd->id); + sd->id = irq_domain_add_legacy(pdev->dev.of_node, SDV_NUM_PUB_GPIOS, + sd->irq_base, 0, &irq_domain_sdv_ops, sd); + if (!sd->id) + goto out_free_irq; return 0; out_free_irq: free_irq(pdev->irq, sd); @@ -260,7 +258,6 @@ static void sdv_gpio_remove(struct pci_dev *pdev) { struct sdv_gpio_chip_data *sd = pci_get_drvdata(pdev); - irq_domain_del(&sd->id); free_irq(pdev->irq, sd); irq_free_descs(sd->irq_base, SDV_NUM_PUB_GPIOS); -- cgit v0.10.2 From 078dc65e61c562e289685fe43b5ef58118e033fc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 6 Apr 2012 20:37:43 +0800 Subject: gpio: Fix uninitialized variable bit in adp5588_irq_handler The variable 'bit' is uninitialized in the first iteration of for loop. Fix it. Signed-off-by: Axel Lin Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 9ad1703..ae5d7f1 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -252,7 +252,7 @@ static irqreturn_t adp5588_irq_handler(int irq, void *devid) if (ret < 0) memset(dev->irq_stat, 0, ARRAY_SIZE(dev->irq_stat)); - for (bank = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO); + for (bank = 0, bit = 0; bank <= ADP5588_BANK(ADP5588_MAXGPIO); bank++, bit = 0) { pending = dev->irq_stat[bank] & dev->irq_mask[bank]; -- cgit v0.10.2 From 6270d830d030da48eddffbe31ed1e4444f203fc5 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Wed, 4 Apr 2012 02:02:58 +0200 Subject: gpio: Fix range check in of_gpio_simple_xlate() of_gpio_simple_xlate() has an off-by-one bug where it checks to see if args[0] is > ngpio instead of >=. args[0] must always be less than ngpio because it is a zero-based enumeration. Signed-off-by: Roland Stigge [grant.likely: beef up commit text] Signed-off-by: Grant Likely diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index bba8121..bf984b6 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -140,7 +140,7 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) return -EINVAL; - if (gpiospec->args[0] > gc->ngpio) + if (gpiospec->args[0] >= gc->ngpio) return -EINVAL; if (flags) -- cgit v0.10.2 From a65a6f14dc24a90bde3f5d0073ba2364476200bf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 20 Mar 2012 16:59:33 +0100 Subject: USB: serial: fix race between probe and open Fix race between probe and open by making sure that the disconnected flag is not cleared until all ports have been registered. A call to tty_open while probe is running may get a reference to the serial structure in serial_install before its ports have been registered. This may lead to usb_serial_core calling driver open before port is fully initialised. With ftdi_sio this result in the following NULL-pointer dereference as the private data has not been initialised at open: [ 199.698286] IP: [] ftdi_open+0x59/0xe0 [ftdi_sio] [ 199.698297] *pde = 00000000 [ 199.698303] Oops: 0000 [#1] PREEMPT SMP [ 199.698313] Modules linked in: ftdi_sio usbserial [ 199.698323] [ 199.698327] Pid: 1146, comm: ftdi_open Not tainted 3.2.11 #70 Dell Inc. Vostro 1520/0T816J [ 199.698339] EIP: 0060:[] EFLAGS: 00010286 CPU: 0 [ 199.698344] EIP is at ftdi_open+0x59/0xe0 [ftdi_sio] [ 199.698348] EAX: 0000003e EBX: f5067000 ECX: 00000000 EDX: 80000600 [ 199.698352] ESI: f48d8800 EDI: 00000001 EBP: f515dd54 ESP: f515dcfc [ 199.698356] DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 [ 199.698361] Process ftdi_open (pid: 1146, ti=f515c000 task=f481e040 task.ti=f515c000) [ 199.698364] Stack: [ 199.698368] f811a9fe f811a9e0 f811b3ef 00000000 00000000 00001388 00000000 f4a86800 [ 199.698387] 00000002 00000000 f806e68e 00000000 f532765c f481e040 00000246 22222222 [ 199.698479] 22222222 22222222 22222222 f5067004 f5327600 f5327638 f515dd74 f806e6ab [ 199.698496] Call Trace: [ 199.698504] [] ? serial_activate+0x2e/0x70 [usbserial] [ 199.698511] [] serial_activate+0x4b/0x70 [usbserial] [ 199.698521] [] tty_port_open+0x7c/0xd0 [ 199.698527] [] ? serial_set_termios+0xa0/0xa0 [usbserial] [ 199.698534] [] serial_open+0x2f/0x70 [usbserial] [ 199.698540] [] tty_open+0x20c/0x510 [ 199.698546] [] chrdev_open+0xe7/0x230 [ 199.698553] [] __dentry_open+0x1f2/0x390 [ 199.698559] [] ? _raw_spin_unlock+0x2c/0x50 [ 199.698565] [] nameidata_to_filp+0x66/0x80 [ 199.698570] [] ? cdev_put+0x20/0x20 [ 199.698576] [] do_last+0x198/0x730 [ 199.698581] [] path_openat+0xa0/0x350 [ 199.698587] [] do_filp_open+0x35/0x80 [ 199.698593] [] ? _raw_spin_unlock+0x2c/0x50 [ 199.698599] [] ? alloc_fd+0xc0/0x100 [ 199.698605] [] ? getname_flags+0x72/0x120 [ 199.698611] [] do_sys_open+0xf0/0x1c0 [ 199.698617] [] ? trace_hardirqs_on_thunk+0xc/0x10 [ 199.698623] [] sys_open+0x2e/0x40 [ 199.698628] [] sysenter_do_call+0x12/0x36 [ 199.698632] Code: 85 89 00 00 00 8b 16 8b 4d c0 c1 e2 08 c7 44 24 14 88 13 00 00 81 ca 00 00 00 80 c7 44 24 10 00 00 00 00 c7 44 24 0c 00 00 00 00 <0f> b7 41 78 31 c9 89 44 24 08 c7 44 24 04 00 00 00 00 c7 04 24 [ 199.698884] EIP: [] ftdi_open+0x59/0xe0 [ftdi_sio] SS:ESP 0068:f515dcfc [ 199.698893] CR2: 0000000000000078 [ 199.698925] ---[ end trace 77c43ec023940cff ]--- Reported-and-tested-by: Ken Huang Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 5413bd5..97355a1 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1059,6 +1059,12 @@ int usb_serial_probe(struct usb_interface *interface, serial->attached = 1; } + /* Avoid race with tty_open and serial_install by setting the + * disconnected flag and not clearing it until all ports have been + * registered. + */ + serial->disconnected = 1; + if (get_free_serial(serial, num_ports, &minor) == NULL) { dev_err(&interface->dev, "No more free serial devices\n"); goto probe_error; @@ -1078,6 +1084,8 @@ int usb_serial_probe(struct usb_interface *interface, "continuing\n"); } + serial->disconnected = 0; + usb_serial_console_init(debug, minor); exit: -- cgit v0.10.2 From 5631f2c18f4b2845b3e97df1c659c5094a17605f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Tue, 3 Apr 2012 09:59:48 +0200 Subject: sysfs: Prevent crash on unset sysfs group attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not let the kernel crash when a device is registered with sysfs while group attributes are not set (aka NULL). Warn about the offender with some information about the offending device. This would warn instead of trying NULL pointer deref like: BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] internal_create_group+0x83/0x1a0 PGD 0 Oops: 0000 [#1] SMP CPU 0 Modules linked in: Pid: 1, comm: swapper/0 Not tainted 3.4.0-rc1-x86_64 #3 HP ProLiant DL360 G4 RIP: 0010:[] [] internal_create_group+0x83/0x1a0 RSP: 0018:ffff88019485fd70 EFLAGS: 00010202 RAX: 0000000000000001 RBX: 0000000000000000 RCX: 0000000000000001 RDX: ffff880192e99908 RSI: ffff880192e99630 RDI: ffffffff81a26c60 RBP: ffff88019485fdc0 R08: 0000000000000000 R09: 0000000000000000 R10: ffff880192e99908 R11: 0000000000000000 R12: ffffffff81a16a00 R13: ffff880192e99908 R14: ffffffff81a16900 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88019bc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000000 CR3: 0000000001a0c000 CR4: 00000000000007f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process swapper/0 (pid: 1, threadinfo ffff88019485e000, task ffff880194878000) Stack: ffff88019485fdd0 ffff880192da9d60 0000000000000000 ffff880192e99908 ffff880192e995d8 0000000000000001 ffffffff81a16a00 ffff880192da9d60 0000000000000000 0000000000000000 ffff88019485fdd0 ffffffff811527be Call Trace: [] sysfs_create_group+0xe/0x10 [] device_add_groups+0x46/0x80 [] device_add+0x46d/0x6a0 ... Signed-off-by: Bruno Prémont Acked-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index dd1701c..2df555c 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -67,7 +67,11 @@ static int internal_create_group(struct kobject *kobj, int update, /* Updates may happen before the object has been instantiated */ if (unlikely(update && !kobj->sd)) return -EINVAL; - + if (!grp->attrs) { + WARN(1, "sysfs: attrs not set by subsystem for group: %s/%s\n", + kobj->name, grp->name ? "" : grp->name); + return -EINVAL; + } if (grp->name) { error = sysfs_create_subdir(kobj, grp->name, &sd); if (error) -- cgit v0.10.2 From 3a198886ab5f228fcbebb9ace803d8b99721d49a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2012 13:41:06 -0700 Subject: sysfs: handle 'parent deleted before child added' In scsi at least two cases of the parent device being deleted before the child is added have been observed. 1/ scsi is performing async scans and the device is removed prior to the async can thread running (can happen with an in-opportune / unlikely unplug during initial scan). 2/ libsas discovery event running after the parent port has been torn down (this is a bug in libsas). Result in crash signatures like: BUG: unable to handle kernel NULL pointer dereference at 0000000000000098 IP: [] sysfs_create_dir+0x32/0xb6 ... Process scsi_scan_8 (pid: 5417, threadinfo ffff88080bd16000, task ffff880801b8a0b0) Stack: 00000000fffffffe ffff880813470628 ffff88080bd17cd0 ffff88080614b7e8 ffff88080b45c108 00000000fffffffe ffff88080bd17d20 ffffffff8125e4a8 ffff88080bd17cf0 ffffffff81075149 ffff88080bd17d30 ffff88080614b7e8 Call Trace: [] kobject_add_internal+0x120/0x1e3 [] ? trace_hardirqs_on+0xd/0xf [] kobject_add_varg+0x41/0x50 [] kobject_add+0x64/0x66 [] device_add+0x12d/0x63a In this scenario the parent is still valid (because we have a reference), but it has been device_del()'d which means its kobj->sd pointer is NULL'd via: device_del()->kobject_del()->sysfs_remove_dir() ...and then sysfs_create_dir() (without this fix) goes ahead and de-references parent_sd via sysfs_ns_type(): return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; This scenario is being fixed in scsi/libsas, but if other subsystems present the same ordering the system need not immediately crash. Cc: Greg Kroah-Hartman Cc: James Bottomley Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 8ddc102..35a36d3 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -729,6 +729,9 @@ int sysfs_create_dir(struct kobject * kobj) else parent_sd = &sysfs_root; + if (!parent_sd) + return -ENOENT; + if (sysfs_ns_type(parent_sd)) ns = kobj->ktype->namespace(kobj); type = sysfs_read_ns_type(kobj); -- cgit v0.10.2 From 282029c005e65ffdce3aa9f8220f88a8bbbc4dae Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2012 13:41:15 -0700 Subject: kobject: provide more diagnostic info for kobject_add_internal() failures 1/ convert open-coded KERN_ERR+dump_stack() to WARN(), so that automated tools pick up this warning. 2/ include the 'child' and 'parent' kobject names. This information was useful for tracking down the case where scsi invoked device_del() on a parent object and subsequently invoked device_add() on a child. Now the warning looks like: kobject_add_internal failed for target8:0:16 (error: -2 parent: end_device-8:0:24) Pid: 2942, comm: scsi_scan_8 Not tainted 3.3.0-rc7-isci+ #2 Call Trace: [] kobject_add_internal+0x1c1/0x1f3 [] ? trace_hardirqs_on+0xd/0xf [] kobject_add_varg+0x41/0x50 [] kobject_add+0x64/0x66 [] device_add+0x12d/0x63a [] ? kobject_put+0x4c/0x50 [] scsi_sysfs_add_sdev+0x4e/0x28a [] do_scan_async+0x9c/0x145 Cc: Greg Kroah-Hartman Cc: James Bottomley Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman diff --git a/lib/kobject.c b/lib/kobject.c index 21dee7c..aeefa8b 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -192,14 +192,14 @@ static int kobject_add_internal(struct kobject *kobj) /* be noisy on error issues */ if (error == -EEXIST) - printk(KERN_ERR "%s failed for %s with " - "-EEXIST, don't try to register things with " - "the same name in the same directory.\n", - __func__, kobject_name(kobj)); + WARN(1, "%s failed for %s with " + "-EEXIST, don't try to register things with " + "the same name in the same directory.\n", + __func__, kobject_name(kobj)); else - printk(KERN_ERR "%s failed for %s (%d)\n", - __func__, kobject_name(kobj), error); - dump_stack(); + WARN(1, "%s failed for %s (error: %d parent: %s)\n", + __func__, kobject_name(kobj), error, + parent ? kobject_name(parent) : "'none'"); } else kobj->state_in_sysfs = 1; -- cgit v0.10.2 From bb334e90cc3a2913906665ea966abd7f462b67c2 Mon Sep 17 00:00:00 2001 From: Alex He Date: Thu, 22 Mar 2012 15:06:59 +0800 Subject: xHCI: correct to print the true HSEE of USBCMD Correct the print of HSEE of USBCMD in xhci-dbg.c. Signed-off-by: Alex He Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index e9b0f04..4b436f5 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -119,7 +119,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci) xhci_dbg(xhci, " Event Interrupts %s\n", (temp & CMD_EIE) ? "enabled " : "disabled"); xhci_dbg(xhci, " Host System Error Interrupts %s\n", - (temp & CMD_EIE) ? "enabled " : "disabled"); + (temp & CMD_HSEIE) ? "enabled " : "disabled"); xhci_dbg(xhci, " HC has %sfinished light reset\n", (temp & CMD_LRESET) ? "not " : ""); } -- cgit v0.10.2 From a46c46a1d752756ba159dd454b746a3fb735c4f5 Mon Sep 17 00:00:00 2001 From: Gerard Snitselaar Date: Fri, 16 Mar 2012 11:34:11 -0700 Subject: usb: xhci: fix section mismatch in linux-next xhci_unregister_pci() is called in xhci_hcd_init(). Signed-off-by: Gerard Snitselaar Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index ef98b38..0d7b851 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -326,7 +326,7 @@ int __init xhci_register_pci(void) return pci_register_driver(&xhci_pci_driver); } -void __exit xhci_unregister_pci(void) +void xhci_unregister_pci(void) { pci_unregister_driver(&xhci_pci_driver); } -- cgit v0.10.2 From 923e9a1399b620d063cd88537c64561bc3d5f905 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 10 Apr 2012 13:26:44 -0700 Subject: Smack: build when CONFIG_AUDIT not defined This fixes builds where CONFIG_AUDIT is not defined and CONFIG_SECURITY_SMACK=y. This got introduced by the stack-usage reducation commit 48c62af68a40 ("LSM: shrink the common_audit_data data union"). Signed-off-by: Kees Cook Acked-by: Eric Paris Signed-off-by: Linus Torvalds diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 81c03a5..10056f2 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1939,18 +1939,19 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) char *hostsp; struct socket_smack *ssp = sk->sk_security; struct smk_audit_info ad; - struct lsm_network_audit net; rcu_read_lock(); hostsp = smack_host_label(sap); if (hostsp != NULL) { - sk_lbl = SMACK_UNLABELED_SOCKET; #ifdef CONFIG_AUDIT + struct lsm_network_audit net; + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = sap->sin_family; ad.a.u.net->dport = sap->sin_port; ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; #endif + sk_lbl = SMACK_UNLABELED_SOCKET; rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); } else { sk_lbl = SMACK_CIPSO_SOCKET; @@ -2809,11 +2810,14 @@ static int smack_unix_stream_connect(struct sock *sock, struct socket_smack *osp = other->sk_security; struct socket_smack *nsp = newsk->sk_security; struct smk_audit_info ad; - struct lsm_network_audit net; int rc = 0; +#ifdef CONFIG_AUDIT + struct lsm_network_audit net; + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other); +#endif if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); @@ -2842,11 +2846,14 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) struct socket_smack *ssp = sock->sk->sk_security; struct socket_smack *osp = other->sk->sk_security; struct smk_audit_info ad; - struct lsm_network_audit net; int rc = 0; +#ifdef CONFIG_AUDIT + struct lsm_network_audit net; + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); smk_ad_setfield_u_net_sk(&ad, other->sk); +#endif if (!capable(CAP_MAC_OVERRIDE)) rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); @@ -2993,7 +3000,9 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) char *csp; int rc; struct smk_audit_info ad; +#ifdef CONFIG_AUDIT struct lsm_network_audit net; +#endif if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) return 0; @@ -3156,7 +3165,9 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, char *sp; int rc; struct smk_audit_info ad; +#ifdef CONFIG_AUDIT struct lsm_network_audit net; +#endif /* handle mapped IPv4 packets arriving via IPv6 sockets */ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) -- cgit v0.10.2 From fae2e0fb24c61ca68c98d854a34732549ebc1854 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 11 Apr 2012 10:42:15 +1000 Subject: powerpc: Fix typo in runlatch code Commit fe1952fc0afb9a2e4c79f103c08aef5d13db1873 "powerpc: Rework runlatch code" has a nasty typo where it uses "TLF_RUNLATCH" instead of "_TLF_RUNLATCH" (bit number instead of bit mask), causing some flags to be potentially lost such as _TLF_RESTORE_SIGMASK (Brown paper bag for me ! We should be able to make that break at compile time with a bit of magic, any volunteer ?) Signed-off-by: Benjamin Herrenschmidt diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f88698c..4937c96 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -1235,7 +1235,7 @@ void __ppc64_runlatch_on(void) ctrl |= CTRL_RUNLATCH; mtspr(SPRN_CTRLT, ctrl); - ti->local_flags |= TLF_RUNLATCH; + ti->local_flags |= _TLF_RUNLATCH; } /* Called with hard IRQs off */ @@ -1244,7 +1244,7 @@ void __ppc64_runlatch_off(void) struct thread_info *ti = current_thread_info(); unsigned long ctrl; - ti->local_flags &= ~TLF_RUNLATCH; + ti->local_flags &= ~_TLF_RUNLATCH; ctrl = mfspr(SPRN_CTRLF); ctrl &= ~CTRL_RUNLATCH; -- cgit v0.10.2 From 09d208ec74b804b9dcd0b1cd9c21dfd592760807 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 10 Apr 2012 21:10:43 -0400 Subject: MAINTAINERS: Mark NATSEMI driver as orphan'd. After discussion with Tim Hockin. Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 6d05ae2..71b7f5c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4533,8 +4533,7 @@ S: Supported F: drivers/net/ethernet/myricom/myri10ge/ NATSEMI ETHERNET DRIVER (DP8381x) -M: Tim Hockin -S: Maintained +S: Orphan F: drivers/net/ethernet/natsemi/natsemi.c NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER -- cgit v0.10.2 From 9a5c7d6eb9b8cc9fa1c7169ecfd96c9e267c0452 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 3 Apr 2012 14:12:55 +0530 Subject: gpio/exynos: Fix compiler warning in gpio-samsung.c file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following warning when "SAMSUNG EXYNOS5" is not selected: warning: ‘exynos5_gpios_1’ defined but not used [-Wunused-variable] warning: ‘exynos5_gpios_2’ defined but not used [-Wunused-variable] warning: ‘exynos5_gpios_3’ defined but not used [-Wunused-variable] warning: ‘exynos5_gpios_4’ defined but not used [-Wunused-variable] Signed-off-by: Sachin Kamat Signed-off-by: Grant Likely diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 4627787..19d6fc0 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -2382,8 +2382,8 @@ static struct samsung_gpio_chip exynos4_gpios_3[] = { #endif }; -static struct samsung_gpio_chip exynos5_gpios_1[] = { #ifdef CONFIG_ARCH_EXYNOS5 +static struct samsung_gpio_chip exynos5_gpios_1[] = { { .chip = { .base = EXYNOS5_GPA0(0), @@ -2541,11 +2541,11 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = { .to_irq = samsung_gpiolib_to_irq, }, }, -#endif }; +#endif -static struct samsung_gpio_chip exynos5_gpios_2[] = { #ifdef CONFIG_ARCH_EXYNOS5 +static struct samsung_gpio_chip exynos5_gpios_2[] = { { .chip = { .base = EXYNOS5_GPE0(0), @@ -2602,11 +2602,11 @@ static struct samsung_gpio_chip exynos5_gpios_2[] = { }, }, -#endif }; +#endif -static struct samsung_gpio_chip exynos5_gpios_3[] = { #ifdef CONFIG_ARCH_EXYNOS5 +static struct samsung_gpio_chip exynos5_gpios_3[] = { { .chip = { .base = EXYNOS5_GPV0(0), @@ -2638,11 +2638,11 @@ static struct samsung_gpio_chip exynos5_gpios_3[] = { .label = "GPV4", }, }, -#endif }; +#endif -static struct samsung_gpio_chip exynos5_gpios_4[] = { #ifdef CONFIG_ARCH_EXYNOS5 +static struct samsung_gpio_chip exynos5_gpios_4[] = { { .chip = { .base = EXYNOS5_GPZ(0), @@ -2650,8 +2650,8 @@ static struct samsung_gpio_chip exynos5_gpios_4[] = { .label = "GPZ", }, }, -#endif }; +#endif #if defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) -- cgit v0.10.2 From 39ec0d38141b198f94fd19c2bb10fd7c616510d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 3 Apr 2012 15:03:44 +0200 Subject: spi/imx: prevent NULL pointer dereference in spi_imx_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no platform_data is present and either 'spi-num-chipselects' is not defined in the DT or 'cs-gpios' has less entries than 'spi-num-chipselects' specifies, the NULL platform_data pointer is being dereferenced. Signed-off-by: Lothar Waßmann Signed-off-by: Grant Likely diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 373f4ff..570f220 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -766,8 +766,12 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) } ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs); - if (ret < 0) - num_cs = mxc_platform_info->num_chipselect; + if (ret < 0) { + if (mxc_platform_info) + num_cs = mxc_platform_info->num_chipselect; + else + return ret; + } master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data) + sizeof(int) * num_cs); @@ -784,7 +788,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) for (i = 0; i < master->num_chipselect; i++) { int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); - if (cs_gpio < 0) + if (cs_gpio < 0 && mxc_platform_info) cs_gpio = mxc_platform_info->chipselect[i]; spi_imx->chipselect[i] = cs_gpio; -- cgit v0.10.2 From 5b7526e3a640e491075557acaa842c59c652c0c3 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 5 Apr 2012 16:52:13 -0700 Subject: irq/irq_domain: Quit ignoring error returns from irq_alloc_desc_from(). In commit 4bbdd45a (irq_domain/powerpc: eliminate irq_map; use irq_alloc_desc() instead) code was added that ignores error returns from irq_alloc_desc_from() by (silently) casting the return value to unsigned. The negitive value error return now suddenly looks like a valid irq number. Commits cc79ca69 (irq_domain: Move irq_domain code from powerpc to kernel/irq) and 1bc04f2c (irq_domain: Add support for base irq and hwirq in legacy mappings) move this code to its current location in irqdomain.c The result of all of this is a null pointer dereference OOPS if one of the error cases is hit. The fix: Don't cast away the negativeness of the return value and then check for errors. Signed-off-by: David Daney Acked-by: Rob Herring [grant.likely: dropped addition of new 'irq' variable] Signed-off-by: Grant Likely diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 3601f3f..9310a8d 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -350,7 +350,8 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) { - unsigned int virq, hint; + unsigned int hint; + int virq; pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq); @@ -381,9 +382,9 @@ unsigned int irq_create_mapping(struct irq_domain *domain, if (hint == 0) hint++; virq = irq_alloc_desc_from(hint, 0); - if (!virq) + if (virq <= 0) virq = irq_alloc_desc_from(1, 0); - if (!virq) { + if (virq <= 0) { pr_debug("irq: -> virq allocation failed\n"); return 0; } -- cgit v0.10.2 From a699e4e49ec3fb62c4a44394357d14081df10bef Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Tue, 3 Apr 2012 07:11:04 -0600 Subject: irq: Kill pointless irqd_to_hw export It makes no sense to export this trivial function. Make it a static inline instead. This patch also drops virq_to_hw from arch/c6x since it is unused by that architecture. v2: Move irq_hw_number_t into types.h to fix ARM build failure Signed-off-by: Grant Likely Acked-by: Thomas Gleixner Cc: Benjamin Herrenschmidt diff --git a/arch/c6x/include/asm/irq.h b/arch/c6x/include/asm/irq.h index f13b78d..ab4577f 100644 --- a/arch/c6x/include/asm/irq.h +++ b/arch/c6x/include/asm/irq.h @@ -42,10 +42,6 @@ /* This number is used when no interrupt has been assigned */ #define NO_IRQ 0 -struct irq_data; -extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); -extern irq_hw_number_t virq_to_hw(unsigned int virq); - extern void __init init_pic_c64xplus(void); extern void init_IRQ(void); diff --git a/arch/c6x/kernel/irq.c b/arch/c6x/kernel/irq.c index 65b8ddf..c90fb5e 100644 --- a/arch/c6x/kernel/irq.c +++ b/arch/c6x/kernel/irq.c @@ -130,16 +130,3 @@ int arch_show_interrupts(struct seq_file *p, int prec) seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); return 0; } - -irq_hw_number_t irqd_to_hwirq(struct irq_data *d) -{ - return d->hwirq; -} -EXPORT_SYMBOL_GPL(irqd_to_hwirq); - -irq_hw_number_t virq_to_hw(unsigned int virq) -{ - struct irq_data *irq_data = irq_get_irq_data(virq); - return WARN_ON(!irq_data) ? 0 : irq_data->hwirq; -} -EXPORT_SYMBOL_GPL(virq_to_hw); diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index cf417e51..e648af9 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h @@ -33,8 +33,6 @@ extern atomic_t ppc_n_lost_interrupts; /* Same thing, used by the generic IRQ code */ #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS -struct irq_data; -extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d); extern irq_hw_number_t virq_to_hw(unsigned int virq); /** diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 243dbab..5ec1b23 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -560,12 +560,6 @@ void do_softirq(void) local_irq_restore(flags); } -irq_hw_number_t irqd_to_hwirq(struct irq_data *d) -{ - return d->hwirq; -} -EXPORT_SYMBOL_GPL(irqd_to_hwirq); - irq_hw_number_t virq_to_hw(unsigned int virq) { struct irq_data *irq_data = irq_get_irq_data(virq); diff --git a/include/linux/irq.h b/include/linux/irq.h index bff29c5..7810406 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -263,6 +263,11 @@ static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) d->state_use_accessors &= ~IRQD_IRQ_INPROGRESS; } +static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) +{ + return d->hwirq; +} + /** * struct irq_chip - hardware interrupt chip descriptor * diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index ead4a42..ac17b9b 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -42,12 +42,6 @@ struct of_device_id; /* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16 -/* This type is the placeholder for a hardware interrupt number. It has to - * be big enough to enclose whatever representation is used by a given - * platform. - */ -typedef unsigned long irq_hw_number_t; - /** * struct irq_domain_ops - Methods for irq_domain objects * @match: Match an interrupt controller device node to a host, returns diff --git a/include/linux/types.h b/include/linux/types.h index e5fa503..7f480db 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -210,6 +210,12 @@ typedef u32 phys_addr_t; typedef phys_addr_t resource_size_t; +/* + * This type is the placeholder for a hardware interrupt number. It has to be + * big enough to enclose whatever representation is used by a given platform. + */ +typedef unsigned long irq_hw_number_t; + typedef struct { int counter; } atomic_t; -- cgit v0.10.2 From ac5830a33f5b25eae1dc0708b3e7a3d270a6c07f Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 10 Apr 2012 15:25:42 +0300 Subject: irq_domain: correct the debugfs file name The actual name of the irq_domain mapping debugfs file is "irq_domain_mapping" not "virq_mapping". Signed-off-by: Mika Westerberg Signed-off-by: Grant Likely diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig index cf1a4a6..d1a758b 100644 --- a/kernel/irq/Kconfig +++ b/kernel/irq/Kconfig @@ -62,7 +62,7 @@ config IRQ_DOMAIN_DEBUG help This option will show the mapping relationship between hardware irq numbers and Linux irq numbers. The mapping is exposed via debugfs - in the file "virq_mapping". + in the file "irq_domain_mapping". If you don't know what this means you don't need it. -- cgit v0.10.2 From 15e06bf64f686befd2030da867a3dad965b96cc0 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 11 Apr 2012 00:26:25 -0600 Subject: irqdomain: Fix debugfs formatting This patch fixes the irq_domain_mapping debugfs output to pad pointer values with leading zeros so that pointer values are displayed correctly. Otherwise you get output similar to "0x 5e0000000000000". Also, when the irq_domain is set to 'null' Signed-off-by: Grant Likely Cc: David Daney Cc: Mika Westerberg diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 9310a8d..eb05e40 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -643,8 +643,8 @@ static int virq_debug_show(struct seq_file *m, void *private) void *data; int i; - seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq", - "chip name", "chip data", "domain name"); + seq_printf(m, "%-5s %-7s %-15s %-*s %s\n", "irq", "hwirq", + "chip name", 2 * sizeof(void *) + 2, "chip data", "domain name"); for (i = 1; i < nr_irqs; i++) { desc = irq_to_desc(i); @@ -667,7 +667,7 @@ static int virq_debug_show(struct seq_file *m, void *private) seq_printf(m, "%-15s ", p); data = irq_desc_get_chip_data(desc); - seq_printf(m, "0x%16p ", data); + seq_printf(m, data ? "0x%p " : " %p ", data); if (desc->irq_data.domain && desc->irq_data.domain->of_node) p = desc->irq_data.domain->of_node->full_name; -- cgit v0.10.2 From 6069a4c988d75c0fb309fa7da0909df2a222a65e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 30 Jan 2012 11:43:52 -0800 Subject: vgaarb.h: fix build warnings Fix build warnings by providing a struct stub since no fields of the struct are used: include/linux/vgaarb.h:66:9: warning: 'struct pci_dev' declared inside parameter list include/linux/vgaarb.h:66:9: warning: its scope is only this definition or declaration, which is probably not what you want include/linux/vgaarb.h:99:34: warning: 'struct pci_dev' declared inside parameter list include/linux/vgaarb.h:109:6: warning: 'struct pci_dev' declared inside parameter list include/linux/vgaarb.h:121:8: warning: 'struct pci_dev' declared inside parameter list include/linux/vgaarb.h:140:37: warning: 'struct pci_dev' declared inside parameter list Signed-off-by: Randy Dunlap Signed-off-by: Dave Airlie diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h index 9c3120d..b572f80 100644 --- a/include/linux/vgaarb.h +++ b/include/linux/vgaarb.h @@ -47,6 +47,8 @@ */ #define VGA_DEFAULT_DEVICE (NULL) +struct pci_dev; + /* For use by clients */ /** -- cgit v0.10.2 From 46783150a6552f9513f08e62cfcc07125d6e502b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 10 Apr 2012 12:14:27 -0400 Subject: drm/radeon: only add the mm i2c bus if the hw_i2c module param is set It seems it can corrupt the monitor EDID in certain cases on certain boards when running sensors detect. It's rarely used anyway outside of AIW boards. http://lists.lm-sensors.org/pipermail/lm-sensors/2012-April/035847.html http://lists.freedesktop.org/archives/xorg/2011-January/052239.html Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Acked-by: Jean Delvare Signed-off-by: Dave Airlie diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 85bcfc8..3edec1c 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -900,6 +900,10 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_chan *i2c; int ret; + /* don't add the mm_i2c bus unless hw_i2c is enabled */ + if (rec->mm_i2c && (radeon_hw_i2c == 0)) + return NULL; + i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); if (i2c == NULL) return NULL; -- cgit v0.10.2 From 6a562e3daee217ce99fe0e31150acd89a5b22606 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 9 Apr 2012 21:10:38 +0200 Subject: Revert "drm/i915: reenable gmbus on gen3+ again" This reverts commit c3dfefa0a6d235bd465309e12f4c56ea16e71111. gmbus in 3.4 has simply too many known issues: - gmbus is too noisy, we need to rework the logging: https://bugs.freedesktop.org/show_bug.cgi?id=48248 - zero-length writes cause an OOPS, and they are userspace-triggerable: https://lkml.org/lkml/2012/3/30/176 - same for zero-length reads: https://bugs.freedesktop.org/show_bug.cgi?id=48269 We can try again for 3.5. Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 601c86e..8fdc957 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -390,7 +390,7 @@ int intel_setup_gmbus(struct drm_device *dev) bus->has_gpio = intel_gpio_setup(bus, i); /* XXX force bit banging until GMBUS is fully debugged */ - if (bus->has_gpio && IS_GEN2(dev)) + if (bus->has_gpio) bus->force_bit = true; } -- cgit v0.10.2 From 27c1cbd06a7620b354cbb363834f3bb8df4f410d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 9 Apr 2012 13:59:46 +0100 Subject: drm/i915/ringbuffer: Exclude last 2 cachlines of ring on 845g The 845g shares the errata with i830 whereby executing a command within 2 cachelines of the end of the ringbuffer may cause a GPU hang. Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e25581a..f75806e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1038,7 +1038,7 @@ int intel_init_ring_buffer(struct drm_device *dev, * of the buffer. */ ring->effective_size = ring->size; - if (IS_I830(ring->dev)) + if (IS_I830(ring->dev) || IS_845G(ring->dev)) ring->effective_size -= 128; return 0; -- cgit v0.10.2 From 80e829fade4eea5f07c410df6a551c42e2d0ca9c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sat, 31 Mar 2012 11:21:57 +0200 Subject: drm/i915: implement ColorBlt w/a According to an internal workaround master list, we need to set bit 5 of register 9400 to avoid issues with color blits. Testing shows that this seems to fix the blitter hangs when fbc is enabled on snb, thanks to Chris Wilson for figuring this out. Tested-by: Chris Wilson Tested-by: Michael "brot" Groh Acked-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2abf4eb..b4bb1ef 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3728,6 +3728,9 @@ #define GT_FIFO_FREE_ENTRIES 0x120008 #define GT_FIFO_NUM_RESERVED_ENTRIES 20 +#define GEN6_UCGCTL1 0x9400 +# define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) + #define GEN6_UCGCTL2 0x9404 # define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f446e66..bae38ac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8556,6 +8556,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); + I915_WRITE(GEN6_UCGCTL1, + I915_READ(GEN6_UCGCTL1) | + GEN6_BLBUNIT_CLOCK_GATE_DISABLE); + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock * gating disable must be set. Failure to set it results in * flickering pixels due to Z write ordering failures after -- cgit v0.10.2 From 912093bc7c08f59e97faed2c0269e1e5429dcd58 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Apr 2012 14:03:41 +0200 Subject: ALSA: hda/realtek - Add a few ALC882 model strings back Since there are still many Acer models that might not be covered by the current fixup table, let's add back a few typical model names so that user can test the fixup without recompiling. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index d97d992..03f7897 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -43,7 +43,9 @@ ALC680 ALC882/883/885/888/889 ====================== - N/A + acer-aspire-4930g Acer Aspire 4930G/5930G/6530G/6930G/7730G + acer-aspire-8930g Acer Aspire 8330G/6935G + acer-aspire Acer Aspire others ALC861/660 ========== diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9917e55..e7b2b83 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5399,6 +5399,13 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { {} }; +static const struct alc_model_fixup alc882_fixup_models[] = { + {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, + {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, + {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, + {} +}; + /* * BIOS auto configuration */ @@ -5439,7 +5446,8 @@ static int patch_alc882(struct hda_codec *codec) if (err < 0) goto error; - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); + alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, + alc882_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); -- cgit v0.10.2 From 996304bbea3d2a094b7ba54c3bd65d3fffeac57b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 4 Apr 2012 01:01:20 +0000 Subject: bridge: Do not send queries on multicast group leaves As it stands the bridge IGMP snooping system will respond to group leave messages with queries for remaining membership. This is both unnecessary and undesirable. First of all any multicast routers present should be doing this rather than us. What's more the queries that we send may end up upsetting other multicast snooping swithces in the system that are buggy. In fact, we can simply remove the code that send these queries because the existing membership expiry mechanism doesn't rely on them anyway. So this patch simply removes all code associated with group queries in response to group leave messages. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 702a1ae..27ca25e 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -241,7 +241,6 @@ static void br_multicast_group_expired(unsigned long data) hlist_del_rcu(&mp->hlist[mdb->ver]); mdb->size--; - del_timer(&mp->query_timer); call_rcu_bh(&mp->rcu, br_multicast_free_group); out: @@ -271,7 +270,6 @@ static void br_multicast_del_pg(struct net_bridge *br, rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); - del_timer(&p->query_timer); call_rcu_bh(&p->rcu, br_multicast_free_pg); if (!mp->ports && !mp->mglist && @@ -507,74 +505,6 @@ static struct sk_buff *br_multicast_alloc_query(struct net_bridge *br, return NULL; } -static void br_multicast_send_group_query(struct net_bridge_mdb_entry *mp) -{ - struct net_bridge *br = mp->br; - struct sk_buff *skb; - - skb = br_multicast_alloc_query(br, &mp->addr); - if (!skb) - goto timer; - - netif_rx(skb); - -timer: - if (++mp->queries_sent < br->multicast_last_member_count) - mod_timer(&mp->query_timer, - jiffies + br->multicast_last_member_interval); -} - -static void br_multicast_group_query_expired(unsigned long data) -{ - struct net_bridge_mdb_entry *mp = (void *)data; - struct net_bridge *br = mp->br; - - spin_lock(&br->multicast_lock); - if (!netif_running(br->dev) || !mp->mglist || - mp->queries_sent >= br->multicast_last_member_count) - goto out; - - br_multicast_send_group_query(mp); - -out: - spin_unlock(&br->multicast_lock); -} - -static void br_multicast_send_port_group_query(struct net_bridge_port_group *pg) -{ - struct net_bridge_port *port = pg->port; - struct net_bridge *br = port->br; - struct sk_buff *skb; - - skb = br_multicast_alloc_query(br, &pg->addr); - if (!skb) - goto timer; - - br_deliver(port, skb); - -timer: - if (++pg->queries_sent < br->multicast_last_member_count) - mod_timer(&pg->query_timer, - jiffies + br->multicast_last_member_interval); -} - -static void br_multicast_port_group_query_expired(unsigned long data) -{ - struct net_bridge_port_group *pg = (void *)data; - struct net_bridge_port *port = pg->port; - struct net_bridge *br = port->br; - - spin_lock(&br->multicast_lock); - if (!netif_running(br->dev) || hlist_unhashed(&pg->mglist) || - pg->queries_sent >= br->multicast_last_member_count) - goto out; - - br_multicast_send_port_group_query(pg); - -out: - spin_unlock(&br->multicast_lock); -} - static struct net_bridge_mdb_entry *br_multicast_get_group( struct net_bridge *br, struct net_bridge_port *port, struct br_ip *group, int hash) @@ -690,8 +620,6 @@ rehash: mp->addr = *group; setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp); - setup_timer(&mp->query_timer, br_multicast_group_query_expired, - (unsigned long)mp); hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]); mdb->size++; @@ -746,8 +674,6 @@ static int br_multicast_add_group(struct net_bridge *br, hlist_add_head(&p->mglist, &port->mglist); setup_timer(&p->timer, br_multicast_port_group_expired, (unsigned long)p); - setup_timer(&p->query_timer, br_multicast_port_group_query_expired, - (unsigned long)p); rcu_assign_pointer(*pp, p); @@ -1291,9 +1217,6 @@ static void br_multicast_leave_group(struct net_bridge *br, time_after(mp->timer.expires, time) : try_to_del_timer_sync(&mp->timer) >= 0)) { mod_timer(&mp->timer, time); - - mp->queries_sent = 0; - mod_timer(&mp->query_timer, now); } goto out; @@ -1310,9 +1233,6 @@ static void br_multicast_leave_group(struct net_bridge *br, time_after(p->timer.expires, time) : try_to_del_timer_sync(&p->timer) >= 0)) { mod_timer(&p->timer, time); - - p->queries_sent = 0; - mod_timer(&p->query_timer, now); } break; @@ -1681,7 +1601,6 @@ void br_multicast_stop(struct net_bridge *br) hlist_for_each_entry_safe(mp, p, n, &mdb->mhash[i], hlist[ver]) { del_timer(&mp->timer); - del_timer(&mp->query_timer); call_rcu_bh(&mp->rcu, br_multicast_free_group); } } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 0b67a63..e1d8822 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -82,9 +82,7 @@ struct net_bridge_port_group { struct hlist_node mglist; struct rcu_head rcu; struct timer_list timer; - struct timer_list query_timer; struct br_ip addr; - u32 queries_sent; }; struct net_bridge_mdb_entry @@ -94,10 +92,8 @@ struct net_bridge_mdb_entry struct net_bridge_port_group __rcu *ports; struct rcu_head rcu; struct timer_list timer; - struct timer_list query_timer; struct br_ip addr; bool mglist; - u32 queries_sent; }; struct net_bridge_mdb_htable -- cgit v0.10.2 From 87151b8689d890dfb495081f7be9b9e257f7a2df Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 10 Apr 2012 20:08:39 +0000 Subject: net: allow pskb_expand_head() to get maximum tailroom Marc Merlin reported many order-1 allocations failures in TX path on its wireless setup, that dont make any sense with MTU=1500 network, and non SG capable hardware. Turns out part of the problem comes from pskb_expand_head() not using ksize() to get exact head size given by kmalloc(). Doing the same thing than __alloc_skb() allows more tailroom in skb and can prevent future reallocations. As a bonus, struct skb_shared_info becomes cache line aligned. Reported-by: Marc MERLIN Tested-by: Marc MERLIN Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index baf8d28..e598400 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -952,9 +952,11 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, goto adjust_others; } - data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask); + data = kmalloc(size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), + gfp_mask); if (!data) goto nodata; + size = SKB_WITH_OVERHEAD(ksize(data)); /* Copy only real data... and, alas, header. This should be * optimized for the cases when header is void. -- cgit v0.10.2 From a21d45726acacc963d8baddf74607d9b74e2b723 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 10 Apr 2012 20:30:48 +0000 Subject: tcp: avoid order-1 allocations on wifi and tx path Marc Merlin reported many order-1 allocations failures in TX path on its wireless setup, that dont make any sense with MTU=1500 network, and non SG capable hardware. After investigation, it turns out TCP uses sk_stream_alloc_skb() and used as a convention skb_tailroom(skb) to know how many bytes of data payload could be put in this skb (for non SG capable devices) Note : these skb used kmalloc-4096 (MTU=1500 + MAX_HEADER + sizeof(struct skb_shared_info) being above 2048) Later, mac80211 layer need to add some bytes at the tail of skb (IEEE80211_ENCRYPT_TAILROOM = 18 bytes) and since no more tailroom is available has to call pskb_expand_head() and request order-1 allocations. This patch changes sk_stream_alloc_skb() so that only sk->sk_prot->max_header bytes of headroom are reserved, and use a new skb field, avail_size to hold the data payload limit. This way, order-0 allocations done by TCP stack can leave more than 2 KB of tailroom and no more allocation is performed in mac80211 layer (or any layer needing some tailroom) avail_size is unioned with mark/dropcount, since mark will be set later in IP stack for output packets. Therefore, skb size is unchanged. Reported-by: Marc MERLIN Tested-by: Marc MERLIN Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 3337027..70a3f8d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -481,6 +481,7 @@ struct sk_buff { union { __u32 mark; __u32 dropcount; + __u32 avail_size; }; sk_buff_data_t transport_header; @@ -1366,6 +1367,18 @@ static inline int skb_tailroom(const struct sk_buff *skb) } /** + * skb_availroom - bytes at buffer end + * @skb: buffer to check + * + * Return the number of bytes of free space at the tail of an sk_buff + * allocated by sk_stream_alloc() + */ +static inline int skb_availroom(const struct sk_buff *skb) +{ + return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len; +} + +/** * skb_reserve - adjust headroom * @skb: buffer to alter * @len: bytes to move diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7758a83..a5daa21 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -701,11 +701,12 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp) skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); if (skb) { if (sk_wmem_schedule(sk, skb->truesize)) { + skb_reserve(skb, sk->sk_prot->max_header); /* * Make sure that we have exactly size bytes * available to the caller, no more, no less. */ - skb_reserve(skb, skb_tailroom(skb) - size); + skb->avail_size = size; return skb; } __kfree_skb(skb); @@ -995,10 +996,9 @@ new_segment: copy = seglen; /* Where to copy to? */ - if (skb_tailroom(skb) > 0) { + if (skb_availroom(skb) > 0) { /* We have some space in skb head. Superb! */ - if (copy > skb_tailroom(skb)) - copy = skb_tailroom(skb); + copy = min_t(int, copy, skb_availroom(skb)); err = skb_add_data_nocache(sk, skb, from, copy); if (err) goto do_fault; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 364784a..376b2cf 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2060,7 +2060,7 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, /* Punt if not enough space exists in the first SKB for * the data in the second */ - if (skb->len > skb_tailroom(to)) + if (skb->len > skb_availroom(to)) break; if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp))) -- cgit v0.10.2 From 7fb0a5ee8889488f7568ffddffeb66ddeb50917e Mon Sep 17 00:00:00 2001 From: "Nikunj A. Dadhania" Date: Mon, 9 Apr 2012 13:52:23 +0530 Subject: perf kvm: Finding struct machine fails for PERF_RECORD_MMAP Running 'perf kvm --host --guest --guestmount /tmp/guestmount record -a -g -- sleep 2' Was resulting in a segfault. For event type PERF_RECORD_MMAP, event->ip.pid is being used in perf_session__find_machine_for_cpumode, which is not correct. The event->ip.pid field happens to be 0 in this case and results in returning a NULL machine object. Finally, access to self->pid in machine__mmap_name, results in a segfault later. For PERF_RECORD_MMAP type, pass event->mmap.pid. Signed-off-by: Nikunj A. Dadhania Reviewed-by: David Ahern Tested-by: David Ahern Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Nikunj A. Dadhania Link: http://lkml.kernel.org/r/20120409081835.10576.22018.stgit@abhimanyu.in.ibm.com Signed-off-by: Arnaldo Carvalho de Melo diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 9412e3b..00923cd 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -826,8 +826,16 @@ static struct machine * { const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) - return perf_session__find_machine(session, event->ip.pid); + if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { + u32 pid; + + if (event->header.type == PERF_RECORD_MMAP) + pid = event->mmap.pid; + else + pid = event->ip.pid; + + return perf_session__find_machine(session, pid); + } return perf_session__find_host_machine(session); } -- cgit v0.10.2 From 79549c6dfda0603dba9a70a53467ce62d9335c33 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 9 Apr 2012 21:03:50 +0200 Subject: cred: copy_process() should clear child->replacement_session_keyring keyctl_session_to_parent(task) sets ->replacement_session_keyring, it should be processed and cleared by key_replace_session_keyring(). However, this task can fork before it notices TIF_NOTIFY_RESUME and the new child gets the bogus ->replacement_session_keyring copied by dup_task_struct(). This is obviously wrong and, if nothing else, this leads to put_cred(already_freed_cred). change copy_creds() to clear this member. If copy_process() fails before this point the wrong ->replacement_session_keyring doesn't matter, exit_creds() won't be called. Cc: Signed-off-by: Oleg Nesterov Acked-by: David Howells Signed-off-by: Linus Torvalds diff --git a/kernel/cred.c b/kernel/cred.c index 97b36ee..e70683d 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -386,6 +386,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) struct cred *new; int ret; + p->replacement_session_keyring = NULL; + if ( #ifdef CONFIG_KEYS !p->cred->thread_keyring && -- cgit v0.10.2 From 4e833c0b87a30798e67f06120cecebef6ee9644c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 15 Mar 2012 16:37:08 +0200 Subject: xhci: don't re-enable IE constantly While we're at that, define IMAN bitfield to aid readability. The interrupt enable bit should be set once on driver init, and we shouldn't need to continually re-enable it. Commit c21599a3 introduced a read of the irq_pending register, and that allows us to preserve the state of the IE bit. Before that commit, we were blindly writing 0x3 to the register. This patch should be backported to kernels as old as 2.6.36, or ones that contain the commit c21599a36165dbc78b380846b254017a548b9de5 "USB: xhci: Reduce reads and writes of interrupter registers". Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6bd9d53..5ddc4ae 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2417,7 +2417,7 @@ hw_died: u32 irq_pending; /* Acknowledge the PCI interrupt */ irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); - irq_pending |= 0x3; + irq_pending |= IMAN_IP; xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 91074fd..3d69c4b 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -205,6 +205,10 @@ struct xhci_op_regs { #define CMD_PM_INDEX (1 << 11) /* bits 12:31 are reserved (and should be preserved on writes). */ +/* IMAN - Interrupt Management Register */ +#define IMAN_IP (1 << 1) +#define IMAN_IE (1 << 0) + /* USBSTS - USB status - status bitmasks */ /* HC not running - set to 1 when run/stop bit is cleared. */ #define STS_HALT XHCI_STS_HALT -- cgit v0.10.2 From 5af98bb06dee79d28c805f9fd0805ce791121784 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 16 Mar 2012 12:58:20 -0700 Subject: xhci: Warn when hosts don't halt. Eric Fu reports a problem with his VIA host controller fetching a zeroed event ring pointer on resume from suspend. The host should have been halted, but we can't be sure because that code ignores the return value from xhci_halt(). Print a warning when the host controller refuses to halt within XHCI_MAX_HALT_USEC (currently 16 seconds). (Update: it turns out that the VIA host controller is reporting a halted state when it fetches the zeroed event ring pointer. However, we still need this warning for other host controllers.) Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index e1963d4..f68bc15 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -106,6 +106,9 @@ int xhci_halt(struct xhci_hcd *xhci) STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); if (!ret) xhci->xhc_state |= XHCI_STATE_HALTED; + else + xhci_warn(xhci, "Host not halted after %u microseconds.\n", + XHCI_MAX_HALT_USEC); return ret; } -- cgit v0.10.2 From 159e1fcc9a60fc7daba23ee8fcdb99799de3fe84 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 16 Mar 2012 13:09:39 -0700 Subject: xhci: Don't write zeroed pointers to xHC registers. When xhci_mem_cleanup() is called, we can't be sure if the xHC is actually halted. We can ask the xHC to halt by writing to the RUN bit in the command register, but that might timeout due to a HW hang. If the host controller is still running, we should not write zeroed values to the event ring dequeue pointers or base tables, the DCBAA pointers, or the command ring pointers. Eric Fu reports his VIA VL800 host accesses the event ring pointers after a failed register restore on resume from suspend. The hypothesis is that the host never actually halted before the register write to change the event ring pointer to zero. Remove all writes of zeroed values to pointer registers in xhci_mem_cleanup(). Instead, make all callers of the function reset the host controller first, which will reset those registers to zero. xhci_mem_init() is the only caller that doesn't first halt and reset the host controller before calling xhci_mem_cleanup(). This should be backported to kernels as old as 2.6.32. Signed-off-by: Sarah Sharp Tested-by: Elric Fu Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index cae4c6f..68eaa90 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1796,11 +1796,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) int i; /* Free the Event Ring Segment Table and the actual Event Ring */ - if (xhci->ir_set) { - xhci_writel(xhci, 0, &xhci->ir_set->erst_size); - xhci_write_64(xhci, 0, &xhci->ir_set->erst_base); - xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue); - } size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) dma_free_coherent(&pdev->dev, size, @@ -1812,7 +1807,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); - xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -1841,7 +1835,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->medium_streams_pool = NULL; xhci_dbg(xhci, "Freed medium stream array pool\n"); - xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); if (xhci->dcbaa) dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), xhci->dcbaa, xhci->dcbaa->dma); @@ -2459,6 +2452,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) fail: xhci_warn(xhci, "Couldn't initialize memory\n"); + xhci_halt(xhci); + xhci_reset(xhci); xhci_mem_cleanup(xhci); return -ENOMEM; } -- cgit v0.10.2 From fb3d85bc7193f23c9a564502df95564c49a32c91 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 16 Mar 2012 13:27:39 -0700 Subject: xhci: Restore event ring dequeue pointer on resume. The xhci_save_registers() function saved the event ring dequeue pointer in the s3 register structure, but xhci_restore_registers() never restored it. No other code in the xHCI successful resume path would ever restore it either. Fix that. This should be backported to kernels as old as 2.6.37, that contain the commit 5535b1d5f8885695c6ded783c692e3c0d0eda8ca "USB: xHCI: PCI power management implementation". Signed-off-by: Sarah Sharp Tested-by: Elric Fu Cc: Andiry Xu Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f68bc15..d2222dc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -684,6 +684,7 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size); xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); + xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); } static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) -- cgit v0.10.2 From c7713e736526d8c9f6f87716fb90562a8ffaff2c Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 16 Mar 2012 13:19:35 -0700 Subject: xhci: Fix register save/restore order. The xHCI 1.0 spec errata released on June 13, 2011, changes the ordering that the xHCI registers are saved and restored in. It moves the interrupt pending (IMAN) and interrupt control (IMOD) registers to be saved and restored last. I believe that's because the host controller may attempt to fetch the event ring table when interrupts are re-enabled. Therefore we need to restore the event ring registers before we re-enable interrupts. This should be backported to kernels as old as 2.6.37, that contain the commit 5535b1d5f8885695c6ded783c692e3c0d0eda8ca "USB: xHCI: PCI power management implementation" Signed-off-by: Sarah Sharp Tested-by: Elric Fu Cc: Andiry Xu Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d2222dc..36641a7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -667,11 +667,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci) xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification); xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg); - xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control); xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size); xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base); xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); + xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control); } static void xhci_restore_registers(struct xhci_hcd *xhci) @@ -680,11 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification); xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg); - xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending); - xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size); xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); + xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending); + xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); } static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) -- cgit v0.10.2 From d8aec3dbdfd02627e198e7956ab4aaeba2a349fa Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Mon, 26 Mar 2012 21:16:02 +0800 Subject: USB: fix bug of device descriptor got from superspeed device When the Seagate Goflex USB3.0 device is attached to VIA xHCI host, sometimes the device will downgrade mode to high speed. By the USB analyzer, I found the device finished the link training process and worked at superspeed mode. But the device descriptor got from the device shows the device works at 2.1. It is very strange and seems like the device controller of Seagate Goflex has a little confusion. The first 8 bytes of device descriptor should be: 12 01 00 03 00 00 00 09 But the first 8 bytes of wrong device descriptor are: 12 01 10 02 00 00 00 40 The wrong device descriptor caused the initialization of mass storage failed. After a while, the device would be recognized as a high speed device and works fine. This patch will warm reset the device to fix the issue after finding the bcdUSB field of device descriptor isn't 0x0300 but the speed mode of device is superspeed. This patch should be backported to kernels as old as 3.2, or ones that contain the commit 75d7cf72ab9fa01dc70877aa5c68e8ef477229dc "usbcore: refine warm reset logic". Signed-off-by: Elric Fu Acked-by: Andiry Xu Acked-by: Sergei Shtylyov Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 28664eb..a2aa9d6 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3163,6 +3163,22 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (retval) goto fail; + /* + * Some superspeed devices have finished the link training process + * and attached to a superspeed hub port, but the device descriptor + * got from those devices show they aren't superspeed devices. Warm + * reset the port attached by the devices can fix them. + */ + if ((udev->speed == USB_SPEED_SUPER) && + (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) { + dev_err(&udev->dev, "got a wrong device descriptor, " + "warm reset device\n"); + hub_port_reset(hub, port1, udev, + HUB_BH_RESET_TIME, true); + retval = -EINVAL; + goto fail; + } + if (udev->descriptor.bMaxPacketSize0 == 0xff || udev->speed == USB_SPEED_SUPER) i = 512; -- cgit v0.10.2 From 457a4f61f9bfc3ae76e5b49f30f25d86bb696f67 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Thu, 29 Mar 2012 15:47:50 +0800 Subject: xHCI: add XHCI_RESET_ON_RESUME quirk for VIA xHCI host The suspend operation of VIA xHCI host have some issues and hibernate operation works fine, so The XHCI_RESET_ON_RESUME quirk is added for it. This patch should base on "xHCI: Don't write zeroed pointer to xHC registers" that is released by Sarah. Otherwise, the host system error will ocurr in the hibernate operation process. This should be backported to stable kernels as old as 2.6.37, that contain the commit c877b3b2ad5cb9d4fe523c5496185cc328ff3ae9 "xhci: Add reset on resume quirk for asrock p67 host". Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 0d7b851..7a856a7 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -95,6 +95,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_RESET_ON_RESUME; xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); } + if (pdev->vendor == PCI_VENDOR_ID_VIA) + xhci->quirks |= XHCI_RESET_ON_RESUME; } /* called during probe() after chip reset completes */ -- cgit v0.10.2 From 3fc8206d3dca1550eb0a1f6e2a350881835954ba Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 28 Mar 2012 10:30:26 +0300 Subject: xHCI: use gfp flags from caller instead of GFP_ATOMIC The caller is allowed to specify the GFP flags for these functions. We should prefer their flags unless we have good reason. For example, if we take a spin_lock ourselves we'd need to use GFP_ATOMIC. But in this case it's safe to use the callers GFP flags. The callers all pass GFP_ATOMIC here, so this change doesn't affect how the kernel behaves but we may add other callers later and this is a cleanup. Signed-off-by: Dan Carpenter Signed-off-by: Sarah Sharp diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 5ddc4ae..3d9422f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2734,7 +2734,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb->dev->speed == USB_SPEED_FULL) urb->interval /= 8; } - return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); + return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index); } /* @@ -3514,7 +3514,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, } ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; - return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); + return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); } /**** Command Ring Operations ****/ -- cgit v0.10.2 From 95018a53f7653e791bba1f54c8d75d9cb700d1bd Mon Sep 17 00:00:00 2001 From: Alex He Date: Fri, 30 Mar 2012 10:21:38 +0800 Subject: xHCI: Correct the #define XHCI_LEGACY_DISABLE_SMI Re-define XHCI_LEGACY_DISABLE_SMI and used it in right way. All SMI enable bits will be cleared to zero and flag bits 29:31 are also cleared to zero. Other bits should be presvered as Table 146. This patch should be backported to kernels as old as 2.6.31. Signed-off-by: Alex He Signed-off-by: Sarah Sharp Cc: stable@vger.kernel.org diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 11de5f1..32dada8 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -825,9 +825,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) } } - /* Disable any BIOS SMIs */ - writel(XHCI_LEGACY_DISABLE_SMI, - base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); + val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); + /* Mask off (turn off) any enabled SMIs */ + val &= XHCI_LEGACY_DISABLE_SMI; + /* Mask all SMI events bits, RW1C */ + val |= XHCI_LEGACY_SMI_EVENTS; + /* Disable any BIOS SMIs and clear all SMI events*/ + writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); if (usb_is_intel_switchable_xhci(pdev)) usb_enable_xhci_ports(pdev); diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index c7f3312..377f424 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -62,8 +62,9 @@ /* USB Legacy Support Control and Status Register - section 7.1.2 */ /* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ #define XHCI_LEGACY_CONTROL_OFFSET (0x04) -/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ -#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) +/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ +#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17)) +#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29) /* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */ #define XHCI_L1C (1 << 16) -- cgit v0.10.2 From 92ae03f2ef99fbc23bfa9080d6b58f25227bd7ef Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 6 Apr 2012 14:32:32 -0700 Subject: x86: merge 32/64-bit versions of 'strncpy_from_user()' and speed it up This merges the 32- and 64-bit versions of the x86 strncpy_from_user() by just rewriting it in C rather than the ancient inline asm versions that used lodsb/stosb and had been duplicated for (trivial) differences between the 32-bit and 64-bit versions. While doing that, it also speeds them up by doing the accesses a word at a time. Finally, the new routines also properly handle the case of hitting the end of the address space, which we have never done correctly before (fs/namei.c has a hack around it for that reason). Despite all these improvements, it actually removes more lines than it adds, due to the de-duplication. Also, we no longer export (or define) the legacy __strncpy_from_user() function (that was defined to not do the user permission checks), since it's not actually used anywhere, and the user address space checks are built in to the new code. Other architecture maintainers have been notified that the old hack in fs/namei.c will be going away in the 3.5 merge window, in case they copied the x86 approach of being a bit cavalier about the end of the address space. Cc: linux-arch@vger.kernel.org Cc: Ingo Molnar Cc: Peter Anvin" Signed-off-by: Linus Torvalds diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 8be5f54..e054459 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h @@ -557,6 +557,8 @@ struct __large_struct { unsigned long buf[100]; }; extern unsigned long copy_from_user_nmi(void *to, const void __user *from, unsigned long n); +extern __must_check long +strncpy_from_user(char *dst, const char __user *src, long count); /* * movsl can be slow when source and dest are not both 8-byte aligned diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h index 566e803..8084bc7 100644 --- a/arch/x86/include/asm/uaccess_32.h +++ b/arch/x86/include/asm/uaccess_32.h @@ -213,11 +213,6 @@ static inline unsigned long __must_check copy_from_user(void *to, return n; } -long __must_check strncpy_from_user(char *dst, const char __user *src, - long count); -long __must_check __strncpy_from_user(char *dst, - const char __user *src, long count); - /** * strlen_user: - Get the size of a string in user space. * @str: The string to measure. diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h index 1c66d30..fcd4b6f 100644 --- a/arch/x86/include/asm/uaccess_64.h +++ b/arch/x86/include/asm/uaccess_64.h @@ -208,10 +208,6 @@ int __copy_in_user(void __user *dst, const void __user *src, unsigned size) } } -__must_check long -strncpy_from_user(char *dst, const char __user *src, long count); -__must_check long -__strncpy_from_user(char *dst, const char __user *src, long count); __must_check long strnlen_user(const char __user *str, long n); __must_check long __strnlen_user(const char __user *str, long n); __must_check long strlen_user(const char __user *str); diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index 97be9cb..57252c9 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c @@ -7,6 +7,8 @@ #include #include +#include + /* * best effort, GUP based copy_from_user() that is NMI-safe */ @@ -41,3 +43,104 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n) return len; } EXPORT_SYMBOL_GPL(copy_from_user_nmi); + +static inline unsigned long count_bytes(unsigned long mask) +{ + mask = (mask - 1) & ~mask; + mask >>= 7; + return count_masked_bytes(mask); +} + +/* + * Do a strncpy, return length of string without final '\0'. + * 'count' is the user-supplied count (return 'count' if we + * hit it), 'max' is the address space maximum (and we return + * -EFAULT if we hit it). + */ +static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, long max) +{ + long res = 0; + + /* + * Truncate 'max' to the user-specified limit, so that + * we only have one limit we need to check in the loop + */ + if (max > count) + max = count; + + while (max >= sizeof(unsigned long)) { + unsigned long c; + + /* Fall back to byte-at-a-time if we get a page fault */ + if (unlikely(__get_user(c,(unsigned long __user *)(src+res)))) + break; + /* This can write a few bytes past the NUL character, but that's ok */ + *(unsigned long *)(dst+res) = c; + c = has_zero(c); + if (c) + return res + count_bytes(c); + res += sizeof(unsigned long); + max -= sizeof(unsigned long); + } + + while (max) { + char c; + + if (unlikely(__get_user(c,src+res))) + return -EFAULT; + dst[res] = c; + if (!c) + return res; + res++; + max--; + } + + /* + * Uhhuh. We hit 'max'. But was that the user-specified maximum + * too? If so, that's ok - we got as much as the user asked for. + */ + if (res >= count) + return count; + + /* + * Nope: we hit the address space limit, and we still had more + * characters the caller would have wanted. That's an EFAULT. + */ + return -EFAULT; +} + +/** + * strncpy_from_user: - Copy a NUL terminated string from userspace. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Source address, in user space. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from userspace to kernel space. + * + * On success, returns the length of the string (not including the trailing + * NUL). + * + * If access to userspace fails, returns -EFAULT (some data may have been + * copied). + * + * If @count is smaller than the length of the string, copies @count bytes + * and returns @count. + */ +long +strncpy_from_user(char *dst, const char __user *src, long count) +{ + unsigned long max_addr, src_addr; + + if (unlikely(count <= 0)) + return 0; + + max_addr = current_thread_info()->addr_limit.seg; + src_addr = (unsigned long)src; + if (likely(src_addr < max_addr)) { + unsigned long max = max_addr - src_addr; + return do_strncpy_from_user(dst, src, count, max); + } + return -EFAULT; +} +EXPORT_SYMBOL(strncpy_from_user); diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index d9b094c..ef2a6a5 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -33,93 +33,6 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon __movsl_is_ok((unsigned long)(a1), (unsigned long)(a2), (n)) /* - * Copy a null terminated string from userspace. - */ - -#define __do_strncpy_from_user(dst, src, count, res) \ -do { \ - int __d0, __d1, __d2; \ - might_fault(); \ - __asm__ __volatile__( \ - " testl %1,%1\n" \ - " jz 2f\n" \ - "0: lodsb\n" \ - " stosb\n" \ - " testb %%al,%%al\n" \ - " jz 1f\n" \ - " decl %1\n" \ - " jnz 0b\n" \ - "1: subl %1,%0\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %5,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(0b,3b) \ - : "=&d"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ - "=&D" (__d2) \ - : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ - : "memory"); \ -} while (0) - -/** - * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * Caller must check the specified block with access_ok() before calling - * this function. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ -long -__strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} -EXPORT_SYMBOL(__strncpy_from_user); - -/** - * strncpy_from_user: - Copy a NUL terminated string from userspace. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Source address, in user space. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from userspace to kernel space. - * - * On success, returns the length of the string (not including the trailing - * NUL). - * - * If access to userspace fails, returns -EFAULT (some data may have been - * copied). - * - * If @count is smaller than the length of the string, copies @count bytes - * and returns @count. - */ -long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} -EXPORT_SYMBOL(strncpy_from_user); - -/* * Zero Userspace */ diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c index b7c2849..0d0326f 100644 --- a/arch/x86/lib/usercopy_64.c +++ b/arch/x86/lib/usercopy_64.c @@ -9,55 +9,6 @@ #include /* - * Copy a null terminated string from userspace. - */ - -#define __do_strncpy_from_user(dst,src,count,res) \ -do { \ - long __d0, __d1, __d2; \ - might_fault(); \ - __asm__ __volatile__( \ - " testq %1,%1\n" \ - " jz 2f\n" \ - "0: lodsb\n" \ - " stosb\n" \ - " testb %%al,%%al\n" \ - " jz 1f\n" \ - " decq %1\n" \ - " jnz 0b\n" \ - "1: subq %1,%0\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movq %5,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(0b,3b) \ - : "=&r"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ - "=&D" (__d2) \ - : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ - : "memory"); \ -} while (0) - -long -__strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} -EXPORT_SYMBOL(__strncpy_from_user); - -long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - return __strncpy_from_user(dst, src, count); - return res; -} -EXPORT_SYMBOL(strncpy_from_user); - -/* * Zero Userspace */ -- cgit v0.10.2 From e72d5c7e9c831f6e393c71dcd62acafbac2b58d0 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 11 Apr 2012 12:45:20 -0400 Subject: arch/tile: avoid unused variable warning in proc.c for tilegx Until we push the unaligned access support for tilegx, it's silly to have arch/tile/kernel/proc.c generate a warning about an unused variable. Extend the #ifdef to cover all the code and data for now. Signed-off-by: Chris Metcalf diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c index 7a93270..446a7f5 100644 --- a/arch/tile/kernel/proc.c +++ b/arch/tile/kernel/proc.c @@ -146,7 +146,6 @@ static ctl_table unaligned_table[] = { }, {} }; -#endif static struct ctl_path tile_path[] = { { .procname = "tile" }, @@ -155,10 +154,9 @@ static struct ctl_path tile_path[] = { static int __init proc_sys_tile_init(void) { -#ifndef __tilegx__ /* FIXME: GX: no support for unaligned access yet */ register_sysctl_paths(tile_path, unaligned_table); -#endif return 0; } arch_initcall(proc_sys_tile_init); +#endif -- cgit v0.10.2 From a7959c1394d4126a70a53b914ce4105f5173d0aa Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 19 Mar 2012 15:44:31 -0500 Subject: rtlwifi: Preallocate USB read buffers and eliminate kalloc in read routine The current version of rtlwifi for USB operations uses kmalloc to acquire a 32-bit buffer for each read of the device. When _usb_read_sync() is called with the rcu_lock held, the result is a "sleeping function called from invalid context" BUG. This is reported for two cases in https://bugzilla.kernel.org/show_bug.cgi?id=42775. The first case has the lock originating from within rtlwifi and could be fixed by rearranging the locking; however, the second originates from within mac80211. The kmalloc() call is removed from _usb_read_sync() by creating a ring buffer pointer in the private area and allocating the buffer data in the probe routine. Signed-off-by: Larry Finger Cc: Stable [This version good for 3.3+ - different patch for 3.2 - 2.6.39] Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 2e1e352..d04dbda 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -124,46 +124,38 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, return status; } -static u32 _usb_read_sync(struct usb_device *udev, u32 addr, u16 len) +static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) { + struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(dev); u8 request; u16 wvalue; u16 index; - u32 *data; - u32 ret; + __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; - data = kmalloc(sizeof(u32), GFP_KERNEL); - if (!data) - return -ENOMEM; request = REALTEK_USB_VENQT_CMD_REQ; index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)addr; _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); - ret = le32_to_cpu(*data); - kfree(data); - return ret; + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + return le32_to_cpu(*data); } static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { - struct device *dev = rtlpriv->io.dev; - - return (u8)_usb_read_sync(to_usb_device(dev), addr, 1); + return (u8)_usb_read_sync(rtlpriv, addr, 1); } static u16 _usb_read16_sync(struct rtl_priv *rtlpriv, u32 addr) { - struct device *dev = rtlpriv->io.dev; - - return (u16)_usb_read_sync(to_usb_device(dev), addr, 2); + return (u16)_usb_read_sync(rtlpriv, addr, 2); } static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) { - struct device *dev = rtlpriv->io.dev; - - return _usb_read_sync(to_usb_device(dev), addr, 4); + return _usb_read_sync(rtlpriv, addr, 4); } static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, @@ -955,6 +947,11 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, return -ENOMEM; } rtlpriv = hw->priv; + rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), + GFP_KERNEL); + if (!rtlpriv->usb_data) + return -ENOMEM; + rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); SET_IEEE80211_DEV(hw, &intf->dev); udev = interface_to_usbdev(intf); @@ -1025,6 +1022,7 @@ void rtl_usb_disconnect(struct usb_interface *intf) /* rtl_deinit_rfkill(hw); */ rtl_usb_deinit(hw); rtl_deinit_core(hw); + kfree(rtlpriv->usb_data); rtlpriv->cfg->ops->deinit_sw_leds(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); _rtl_usb_io_handler_release(hw); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index b591614..28ebc69 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -67,7 +67,7 @@ #define QOS_QUEUE_NUM 4 #define RTL_MAC80211_NUM_QUEUE 5 #define REALTEK_USB_VENQT_MAX_BUF_SIZE 254 - +#define RTL_USB_MAX_RX_COUNT 100 #define QBSS_LOAD_SIZE 5 #define MAX_WMMELE_LENGTH 64 @@ -1629,6 +1629,10 @@ struct rtl_priv { interface or hardware */ unsigned long status; + /* data buffer pointer for USB reads */ + __le32 *usb_data; + int usb_data_index; + /*This must be the last item so that it points to the data allocated beyond this structure like: -- cgit v0.10.2 From 673f7786e205c87b5d978c62827b9a66d097bebb Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 26 Mar 2012 10:48:20 -0500 Subject: rtlwifi: Add missing DMA buffer unmapping for PCI drivers In https://bugzilla.kernel.org/show_bug.cgi?id=42976, a system with driver rtl8192se used as an AP suffers from "Out of SW-IOMMU space" errors. These are caused by the DMA buffers used for beacons never being unmapped. This bug was also reported at https://bugs.launchpad.net/ubuntu/+source/linux/+bug/961618 Reported-and-Tested-by: Da Xue Signed-off-by: Larry Finger Cc: Stable Signed-off-by: John W. Linville diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 07dd38e..288b035 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -912,8 +912,13 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ring = &rtlpci->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); - if (pskb) + if (pskb) { + struct rtl_tx_desc *entry = &ring->desc[ring->idx]; + pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc( + (u8 *) entry, true, HW_DESC_TXBUFF_ADDR), + pskb->len, PCI_DMA_TODEVICE); kfree_skb(pskb); + } /*NB: the beacon data buffer must be 32-bit aligned. */ pskb = ieee80211_beacon_get(hw, mac->vif); -- cgit v0.10.2 From b4838d12e1f3cb48c2489a0b08733b5dbf848297 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 10 Apr 2012 19:43:03 +0200 Subject: NFC: Fix the LLCP Tx fragmentation loop Reported-by: Dan Carpenter Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 7b76eb7..ef10ffc 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -474,7 +474,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, while (remaining_len > 0) { - frag_len = min_t(u16, local->remote_miu, remaining_len); + frag_len = min_t(size_t, local->remote_miu, remaining_len); pr_debug("Fragment %zd bytes remaining %zd", frag_len, remaining_len); @@ -497,7 +497,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, release_sock(sk); remaining_len -= frag_len; - msg_ptr += len; + msg_ptr += frag_len; } kfree(msg_data); -- cgit v0.10.2 From f57f9c167af7cb3fd315e6a8ebe194a8aea0832a Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2012 09:39:02 -0700 Subject: drm/i915: make rc6 module parameter read-only People have been getting confused and thinking this is a runtime control. Cc: stable@vger.kernel.org Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index dfa55e7..ae8a64f 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))"); int i915_enable_rc6 __read_mostly = -1; -module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); +module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400); MODULE_PARM_DESC(i915_enable_rc6, "Enable power-saving render C-state 6. " "Different stages can be selected via bitmask values " -- cgit v0.10.2 From d48fc63f6f3f485ed5aa9cf019d8e8e3a7d10263 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 11 Apr 2012 23:49:16 +0200 Subject: Revert "clocksource: Load the ACPI PM clocksource asynchronously" This reverts commit b519508298e0292e1771eecf14aaf67755adc39d. The reason for this revert is that making the frequency verification preemptible and interruptible is not working reliably. Michaels machine failed to use PM-timer with the message: PM-Timer running at invalid rate: 113% of normal - aborting. That's not a surprise as the frequency verification does rely on interrupts being disabled. With a async scheduled thread there is no guarantee to achieve the same result. Also some driver might fiddle with the CTC channel 2 during the verification period, which makes the result even more random and unpredictable. This can be solved by using the same mechanism as we use in the deferred TSC validation code, but that only will work if we verified a working HPET _BEFORE_ trying to do the PM-Timer lazy validation. So for now reverting is the safe option. Bisected-by: Michael Witten Cc: Arjan van de Ven Cc: Arjan van de Ven Cc: John Stultz Cc: Len Brown LKML-Reference: Signed-off-by: Thomas Gleixner diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index 82e8820..6b5cf02 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -23,7 +23,6 @@ #include #include #include -#include #include /* @@ -180,15 +179,17 @@ static int verify_pmtmr_rate(void) /* Number of reads we try to get two different values */ #define ACPI_PM_READ_CHECKS 10000 -static void __init acpi_pm_clocksource_async(void *unused, async_cookie_t cookie) +static int __init init_acpi_pm_clocksource(void) { cycle_t value1, value2; unsigned int i, j = 0; + if (!pmtmr_ioport) + return -ENODEV; /* "verify" this timing source: */ for (j = 0; j < ACPI_PM_MONOTONICITY_CHECKS; j++) { - usleep_range(100 * j, 100 * j + 100); + udelay(100 * j); value1 = clocksource_acpi_pm.read(&clocksource_acpi_pm); for (i = 0; i < ACPI_PM_READ_CHECKS; i++) { value2 = clocksource_acpi_pm.read(&clocksource_acpi_pm); @@ -202,34 +203,25 @@ static void __init acpi_pm_clocksource_async(void *unused, async_cookie_t cookie " 0x%#llx, 0x%#llx - aborting.\n", value1, value2); pmtmr_ioport = 0; - return; + return -EINVAL; } if (i == ACPI_PM_READ_CHECKS) { printk(KERN_INFO "PM-Timer failed consistency check " " (0x%#llx) - aborting.\n", value1); pmtmr_ioport = 0; - return; + return -ENODEV; } } if (verify_pmtmr_rate() != 0){ pmtmr_ioport = 0; - return; + return -ENODEV; } - clocksource_register_hz(&clocksource_acpi_pm, + return clocksource_register_hz(&clocksource_acpi_pm, PMTMR_TICKS_PER_SEC); } -static int __init init_acpi_pm_clocksource(void) -{ - if (!pmtmr_ioport) - return -ENODEV; - - async_schedule(acpi_pm_clocksource_async, NULL); - return 0; -} - /* We use fs_initcall because we want the PCI fixups to have run * but we still need to load before device_initcall */ -- cgit v0.10.2 From 0e3d0f3d960bf5b895adcf9ffc79d2077f1411d5 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 11 Apr 2012 20:55:18 -0700 Subject: Input: da9052 - fix memory leak in da9052_onkey_probe() If, in drivers/input/misc/da9052_onkey.c::da9052_onkey_probe(), the call to either kzalloc() or input_allocate_device() fails then we will return -ENOMEM from the function without freeing the other allocation that may have succeeded, thus we leak either the memory allocated for 'onkey' or the memory allocated for 'input_dev' if one succeeds and the other fails. Fix that by jumping to the 'err_free_mem' label at the end of the function that properly cleans up rather than returning directly. Signed-off-by: Jesper Juhl Signed-off-by: Dmitry Torokhov diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 34aebb8..3c843cd 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -95,7 +95,8 @@ static int __devinit da9052_onkey_probe(struct platform_device *pdev) input_dev = input_allocate_device(); if (!onkey || !input_dev) { dev_err(&pdev->dev, "Failed to allocate memory\n"); - return -ENOMEM; + error = -ENOMEM; + goto err_free_mem; } onkey->input = input_dev; -- cgit v0.10.2 From f9309d1bf220122659328040db47eede32514656 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:22 +0900 Subject: drm/exynos: remove unnecessary type conversion of hdmi and mixer When the void pointer type variable is assigned to the specific pointer type variable, don't need to do type conversion. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 575a8cb..0a71317 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1194,7 +1194,7 @@ static int hdmi_conf_index(struct hdmi_context *hdata, static bool hdmi_is_connected(void *ctx) { - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS); if (val) @@ -1207,7 +1207,7 @@ static int hdmi_get_edid(void *ctx, struct drm_connector *connector, u8 *edid, int len) { struct edid *raw_edid; - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -1275,7 +1275,7 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing) static int hdmi_check_timing(void *ctx, void *timing) { - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; struct fb_videomode *check_timing = timing; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -1914,7 +1914,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, struct drm_display_mode *adjusted_mode) { struct drm_display_mode *m; - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; int index; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -1951,7 +1951,7 @@ static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector, static void hdmi_mode_set(void *ctx, void *mode) { - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; int conf_idx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -1974,7 +1974,7 @@ static void hdmi_get_max_resol(void *ctx, unsigned int *width, static void hdmi_commit(void *ctx) { - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -1985,7 +1985,7 @@ static void hdmi_commit(void *ctx) static void hdmi_disable(void *ctx) { - struct hdmi_context *hdata = (struct hdmi_context *)ctx; + struct hdmi_context *hdata = ctx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); @@ -2020,7 +2020,7 @@ static void hdmi_hotplug_func(struct work_struct *work) static irqreturn_t hdmi_irq_handler(int irq, void *arg) { struct exynos_drm_hdmi_context *ctx = arg; - struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx; + struct hdmi_context *hdata = ctx->ctx; u32 intc_flag; intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG); @@ -2173,7 +2173,7 @@ static int hdmi_runtime_suspend(struct device *dev) DRM_DEBUG_KMS("%s\n", __func__); - hdmi_resource_poweroff((struct hdmi_context *)ctx->ctx); + hdmi_resource_poweroff(ctx->ctx); return 0; } @@ -2184,7 +2184,7 @@ static int hdmi_runtime_resume(struct device *dev) DRM_DEBUG_KMS("%s\n", __func__); - hdmi_resource_poweron((struct hdmi_context *)ctx->ctx); + hdmi_resource_poweron(ctx->ctx); return 0; } @@ -2351,7 +2351,7 @@ err_data: static int __devexit hdmi_remove(struct platform_device *pdev) { struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev); - struct hdmi_context *hdata = (struct hdmi_context *)ctx->ctx; + struct hdmi_context *hdata = ctx->ctx; DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 4d5f41e..495a7af 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -771,8 +771,7 @@ static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc) static irqreturn_t mixer_irq_handler(int irq, void *arg) { struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; - struct mixer_context *ctx = - (struct mixer_context *)drm_hdmi_ctx->ctx; + struct mixer_context *ctx = drm_hdmi_ctx->ctx; struct mixer_resources *res = &ctx->mixer_res; u32 val, val_base; @@ -902,7 +901,7 @@ static int mixer_runtime_resume(struct device *dev) DRM_DEBUG_KMS("resume - start\n"); - mixer_resource_poweron((struct mixer_context *)ctx->ctx); + mixer_resource_poweron(ctx->ctx); return 0; } @@ -913,7 +912,7 @@ static int mixer_runtime_suspend(struct device *dev) DRM_DEBUG_KMS("suspend - start\n"); - mixer_resource_poweroff((struct mixer_context *)ctx->ctx); + mixer_resource_poweroff(ctx->ctx); return 0; } @@ -926,8 +925,7 @@ static const struct dev_pm_ops mixer_pm_ops = { static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx, struct platform_device *pdev) { - struct mixer_context *mixer_ctx = - (struct mixer_context *)ctx->ctx; + struct mixer_context *mixer_ctx = ctx->ctx; struct device *dev = &pdev->dev; struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; struct resource *res; @@ -1093,7 +1091,7 @@ static int mixer_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct exynos_drm_hdmi_context *drm_hdmi_ctx = platform_get_drvdata(pdev); - struct mixer_context *ctx = (struct mixer_context *)drm_hdmi_ctx->ctx; + struct mixer_context *ctx = drm_hdmi_ctx->ctx; dev_info(dev, "remove successful\n"); -- cgit v0.10.2 From 46da222be7873bd1c79fa110d6988a2b826f7dee Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:23 +0900 Subject: drm/exynos: remove unused codes in hdmi and mixer Some members in struct mixer_context aren't used and the define HDMI_OVERLAY_NUMBER is unused in hdmi driver, remove them. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 0a71317..340424f 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -40,7 +40,6 @@ #include "exynos_hdmi.h" -#define HDMI_OVERLAY_NUMBER 3 #define MAX_WIDTH 1920 #define MAX_HEIGHT 1080 #define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 495a7af..baad0dd 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -75,13 +75,10 @@ struct mixer_resources { }; struct mixer_context { - struct fb_videomode *default_timing; unsigned int default_win; - unsigned int default_bpp; unsigned int irq; int pipe; bool interlace; - bool vp_enabled; struct mixer_resources mixer_res; struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER]; -- cgit v0.10.2 From a634dd54c05636a89a272e27e59118374065975e Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:24 +0900 Subject: drm/exynos: rename s/HDMI_OVERLAY_NUMBER/MIXER_WIN_NR HDMI_OVERLAY_NUMBER is specific of mixer driver and be used "windows layer" term in exynos user manaual, so rename it. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index baad0dd..9c99514 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -37,7 +37,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_hdmi.h" -#define HDMI_OVERLAY_NUMBER 3 +#define MIXER_WIN_NR 3 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) @@ -81,7 +81,7 @@ struct mixer_context { bool interlace; struct mixer_resources mixer_res; - struct hdmi_win_data win_data[HDMI_OVERLAY_NUMBER]; + struct hdmi_win_data win_data[MIXER_WIN_NR]; }; static const u8 filter_y_horiz_tap8[] = { @@ -642,7 +642,7 @@ static void mixer_win_mode_set(void *ctx, if (win == DEFAULT_ZPOS) win = mixer_ctx->default_win; - if (win < 0 || win > HDMI_OVERLAY_NUMBER) { + if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); return; } @@ -682,7 +682,7 @@ static void mixer_win_commit(void *ctx, int zpos) if (win == DEFAULT_ZPOS) win = mixer_ctx->default_win; - if (win < 0 || win > HDMI_OVERLAY_NUMBER) { + if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); return; } @@ -705,7 +705,7 @@ static void mixer_win_disable(void *ctx, int zpos) if (win == DEFAULT_ZPOS) win = mixer_ctx->default_win; - if (win < 0 || win > HDMI_OVERLAY_NUMBER) { + if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); return; } -- cgit v0.10.2 From a2ee151b6b6863d108552de82e02b77166ca23a8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:25 +0900 Subject: drm/exynos: use define instead of default_win member in struct mixer_context The default_win member in struct mixer_context isn't change its value after initialized to 0, so it's better using to define. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 9c99514..563092e 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -38,6 +38,7 @@ #include "exynos_drm_hdmi.h" #define MIXER_WIN_NR 3 +#define MIXER_DEFAULT_WIN 0 #define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) @@ -75,7 +76,6 @@ struct mixer_resources { }; struct mixer_context { - unsigned int default_win; unsigned int irq; int pipe; bool interlace; @@ -640,7 +640,7 @@ static void mixer_win_mode_set(void *ctx, win = overlay->zpos; if (win == DEFAULT_ZPOS) - win = mixer_ctx->default_win; + win = MIXER_DEFAULT_WIN; if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); @@ -680,7 +680,7 @@ static void mixer_win_commit(void *ctx, int zpos) DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); if (win == DEFAULT_ZPOS) - win = mixer_ctx->default_win; + win = MIXER_DEFAULT_WIN; if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); @@ -703,7 +703,7 @@ static void mixer_win_disable(void *ctx, int zpos) DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win); if (win == DEFAULT_ZPOS) - win = mixer_ctx->default_win; + win = MIXER_DEFAULT_WIN; if (win < 0 || win > MIXER_WIN_NR) { DRM_ERROR("overlay plane[%d] is wrong\n", win); -- cgit v0.10.2 From 578b6065adc8805a8774e4bf3145e18de123f8b2 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:26 +0900 Subject: drm/exynos: fix struct for operation callback functions to driver name The mixer driver and hdmi driver have each operation callback functions and they is registered to hdmi common driver. Their struct names in hdmi common driver include display, manager and overlay. It confuses to appear whose operation and two driver cannot register same operation callback functions at the same time. Use their struct names to driver name. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 14eb26b..348048b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -30,9 +30,8 @@ struct drm_hdmi_context, subdrv); /* these callback points shoud be set by specific drivers. */ -static struct exynos_hdmi_display_ops *hdmi_display_ops; -static struct exynos_hdmi_manager_ops *hdmi_manager_ops; -static struct exynos_hdmi_overlay_ops *hdmi_overlay_ops; +static struct exynos_hdmi_ops *hdmi_ops; +static struct exynos_mixer_ops *mixer_ops; struct drm_hdmi_context { struct exynos_drm_subdrv subdrv; @@ -40,31 +39,20 @@ struct drm_hdmi_context { struct exynos_drm_hdmi_context *mixer_ctx; }; -void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops - *display_ops) +void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops) { DRM_DEBUG_KMS("%s\n", __FILE__); - if (display_ops) - hdmi_display_ops = display_ops; + if (ops) + hdmi_ops = ops; } -void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops - *manager_ops) +void exynos_mixer_ops_register(struct exynos_mixer_ops *ops) { DRM_DEBUG_KMS("%s\n", __FILE__); - if (manager_ops) - hdmi_manager_ops = manager_ops; -} - -void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops - *overlay_ops) -{ - DRM_DEBUG_KMS("%s\n", __FILE__); - - if (overlay_ops) - hdmi_overlay_ops = overlay_ops; + if (ops) + mixer_ops = ops; } static bool drm_hdmi_is_connected(struct device *dev) @@ -73,8 +61,8 @@ static bool drm_hdmi_is_connected(struct device *dev) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_display_ops && hdmi_display_ops->is_connected) - return hdmi_display_ops->is_connected(ctx->hdmi_ctx->ctx); + if (hdmi_ops && hdmi_ops->is_connected) + return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx); return false; } @@ -86,9 +74,9 @@ static int drm_hdmi_get_edid(struct device *dev, DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_display_ops && hdmi_display_ops->get_edid) - return hdmi_display_ops->get_edid(ctx->hdmi_ctx->ctx, - connector, edid, len); + if (hdmi_ops && hdmi_ops->get_edid) + return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid, + len); return 0; } @@ -99,9 +87,8 @@ static int drm_hdmi_check_timing(struct device *dev, void *timing) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_display_ops && hdmi_display_ops->check_timing) - return hdmi_display_ops->check_timing(ctx->hdmi_ctx->ctx, - timing); + if (hdmi_ops && hdmi_ops->check_timing) + return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing); return 0; } @@ -112,8 +99,8 @@ static int drm_hdmi_power_on(struct device *dev, int mode) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_display_ops && hdmi_display_ops->power_on) - return hdmi_display_ops->power_on(ctx->hdmi_ctx->ctx, mode); + if (hdmi_ops && hdmi_ops->power_on) + return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode); return 0; } @@ -134,9 +121,9 @@ static int drm_hdmi_enable_vblank(struct device *subdrv_dev) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_overlay_ops && hdmi_overlay_ops->enable_vblank) - return hdmi_overlay_ops->enable_vblank(ctx->mixer_ctx->ctx, - manager->pipe); + if (mixer_ops && mixer_ops->enable_vblank) + return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx, + manager->pipe); return 0; } @@ -147,8 +134,8 @@ static void drm_hdmi_disable_vblank(struct device *subdrv_dev) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_overlay_ops && hdmi_overlay_ops->disable_vblank) - return hdmi_overlay_ops->disable_vblank(ctx->mixer_ctx->ctx); + if (mixer_ops && mixer_ops->disable_vblank) + return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx); } static void drm_hdmi_mode_fixup(struct device *subdrv_dev, @@ -160,9 +147,9 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev, DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_manager_ops && hdmi_manager_ops->mode_fixup) - hdmi_manager_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, - mode, adjusted_mode); + if (hdmi_ops && hdmi_ops->mode_fixup) + hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode, + adjusted_mode); } static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) @@ -171,8 +158,8 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_manager_ops && hdmi_manager_ops->mode_set) - hdmi_manager_ops->mode_set(ctx->hdmi_ctx->ctx, mode); + if (hdmi_ops && hdmi_ops->mode_set) + hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode); } static void drm_hdmi_get_max_resol(struct device *subdrv_dev, @@ -182,9 +169,8 @@ static void drm_hdmi_get_max_resol(struct device *subdrv_dev, DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_manager_ops && hdmi_manager_ops->get_max_resol) - hdmi_manager_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, - height); + if (hdmi_ops && hdmi_ops->get_max_resol) + hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height); } static void drm_hdmi_commit(struct device *subdrv_dev) @@ -193,8 +179,8 @@ static void drm_hdmi_commit(struct device *subdrv_dev) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_manager_ops && hdmi_manager_ops->commit) - hdmi_manager_ops->commit(ctx->hdmi_ctx->ctx); + if (hdmi_ops && hdmi_ops->commit) + hdmi_ops->commit(ctx->hdmi_ctx->ctx); } static void drm_hdmi_dpms(struct device *subdrv_dev, int mode) @@ -209,8 +195,8 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode) case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (hdmi_manager_ops && hdmi_manager_ops->disable) - hdmi_manager_ops->disable(ctx->hdmi_ctx->ctx); + if (hdmi_ops && hdmi_ops->disable) + hdmi_ops->disable(ctx->hdmi_ctx->ctx); break; default: DRM_DEBUG_KMS("unkown dps mode: %d\n", mode); @@ -235,8 +221,8 @@ static void drm_mixer_mode_set(struct device *subdrv_dev, DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_overlay_ops && hdmi_overlay_ops->win_mode_set) - hdmi_overlay_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay); + if (mixer_ops && mixer_ops->win_mode_set) + mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay); } static void drm_mixer_commit(struct device *subdrv_dev, int zpos) @@ -245,8 +231,8 @@ static void drm_mixer_commit(struct device *subdrv_dev, int zpos) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_overlay_ops && hdmi_overlay_ops->win_commit) - hdmi_overlay_ops->win_commit(ctx->mixer_ctx->ctx, zpos); + if (mixer_ops && mixer_ops->win_commit) + mixer_ops->win_commit(ctx->mixer_ctx->ctx, zpos); } static void drm_mixer_disable(struct device *subdrv_dev, int zpos) @@ -255,8 +241,8 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos) DRM_DEBUG_KMS("%s\n", __FILE__); - if (hdmi_overlay_ops && hdmi_overlay_ops->win_disable) - hdmi_overlay_ops->win_disable(ctx->mixer_ctx->ctx, zpos); + if (mixer_ops && mixer_ops->win_disable) + mixer_ops->win_disable(ctx->mixer_ctx->ctx, zpos); } static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h index 44497cf..f3ae192 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h @@ -38,15 +38,15 @@ struct exynos_drm_hdmi_context { void *ctx; }; -struct exynos_hdmi_display_ops { +struct exynos_hdmi_ops { + /* display */ bool (*is_connected)(void *ctx); int (*get_edid)(void *ctx, struct drm_connector *connector, u8 *edid, int len); int (*check_timing)(void *ctx, void *timing); int (*power_on)(void *ctx, int mode); -}; -struct exynos_hdmi_manager_ops { + /* manager */ void (*mode_fixup)(void *ctx, struct drm_connector *connector, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); @@ -57,22 +57,17 @@ struct exynos_hdmi_manager_ops { void (*disable)(void *ctx); }; -struct exynos_hdmi_overlay_ops { +struct exynos_mixer_ops { + /* manager */ int (*enable_vblank)(void *ctx, int pipe); void (*disable_vblank)(void *ctx); + + /* overlay */ void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); void (*win_commit)(void *ctx, int zpos); void (*win_disable)(void *ctx, int zpos); }; -extern struct platform_driver hdmi_driver; -extern struct platform_driver mixer_driver; - -void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops - *display_ops); -void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops - *manager_ops); -void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops - *overlay_ops); - +void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops); +void exynos_mixer_ops_register(struct exynos_mixer_ops *ops); #endif diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 340424f..b003538 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -1311,13 +1311,6 @@ static int hdmi_display_power_on(void *ctx, int mode) return 0; } -static struct exynos_hdmi_display_ops display_ops = { - .is_connected = hdmi_is_connected, - .get_edid = hdmi_get_edid, - .check_timing = hdmi_check_timing, - .power_on = hdmi_display_power_on, -}; - static void hdmi_set_acr(u32 freq, u8 *acr) { u32 n, cts; @@ -1995,7 +1988,14 @@ static void hdmi_disable(void *ctx) } } -static struct exynos_hdmi_manager_ops manager_ops = { +static struct exynos_hdmi_ops hdmi_ops = { + /* display */ + .is_connected = hdmi_is_connected, + .get_edid = hdmi_get_edid, + .check_timing = hdmi_check_timing, + .power_on = hdmi_display_power_on, + + /* manager */ .mode_fixup = hdmi_mode_fixup, .mode_set = hdmi_mode_set, .get_max_resol = hdmi_get_max_resol, @@ -2321,8 +2321,7 @@ static int __devinit hdmi_probe(struct platform_device *pdev) hdata->irq = res->start; /* register specific callbacks to common hdmi. */ - exynos_drm_display_ops_register(&display_ops); - exynos_drm_manager_ops_register(&manager_ops); + exynos_hdmi_ops_register(&hdmi_ops); hdmi_resource_poweron(hdata); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 563092e..e15438c 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -719,9 +719,12 @@ static void mixer_win_disable(void *ctx, int zpos) spin_unlock_irqrestore(&res->reg_slock, flags); } -static struct exynos_hdmi_overlay_ops overlay_ops = { +static struct exynos_mixer_ops mixer_ops = { + /* manager */ .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, + + /* overlay */ .win_mode_set = mixer_win_mode_set, .win_commit = mixer_win_commit, .win_disable = mixer_win_disable, @@ -1071,7 +1074,7 @@ static int __devinit mixer_probe(struct platform_device *pdev) goto fail; /* register specific callback point to common hdmi. */ - exynos_drm_overlay_ops_register(&overlay_ops); + exynos_mixer_ops_register(&mixer_ops); mixer_resource_poweron(ctx); -- cgit v0.10.2 From 677e84c1b5c8533ea351a9556308071ca47a1eb2 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Thu, 5 Apr 2012 20:49:27 +0900 Subject: drm/exynos: fix to pointer manager member of struct exynos_drm_subdrv The struct exynos_drm_manager has to exist for exynos drm sub driver using encoder and connector. If it isn't NULL to member of struct exynos_drm_subdrv, will create encoder and connector else will not. And the is_local member also doesn't need. Signed-off-by: Joonyoung Shim Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 411832e..eaf630d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -54,16 +54,18 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev, * * P.S. note that this driver is considered for modularization. */ - ret = subdrv->probe(dev, subdrv->manager.dev); + ret = subdrv->probe(dev, subdrv->dev); if (ret) return ret; } - if (subdrv->is_local) + if (!subdrv->manager) return 0; + subdrv->manager->dev = subdrv->dev; + /* create and initialize a encoder for this sub driver. */ - encoder = exynos_drm_encoder_create(dev, &subdrv->manager, + encoder = exynos_drm_encoder_create(dev, subdrv->manager, (1 << MAX_CRTC) - 1); if (!encoder) { DRM_ERROR("failed to create encoder\n"); @@ -186,7 +188,7 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { if (subdrv->open) { - ret = subdrv->open(dev, subdrv->manager.dev, file); + ret = subdrv->open(dev, subdrv->dev, file); if (ret) goto err; } @@ -197,7 +199,7 @@ int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file) err: list_for_each_entry_reverse(subdrv, &subdrv->list, list) { if (subdrv->close) - subdrv->close(dev, subdrv->manager.dev, file); + subdrv->close(dev, subdrv->dev, file); } return ret; } @@ -209,7 +211,7 @@ void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file) list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { if (subdrv->close) - subdrv->close(dev, subdrv->manager.dev, file); + subdrv->close(dev, subdrv->dev, file); } } EXPORT_SYMBOL_GPL(exynos_drm_subdrv_close); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index fbd0a23..1d81417 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -225,24 +225,25 @@ struct exynos_drm_private { * Exynos drm sub driver structure. * * @list: sub driver has its own list object to register to exynos drm driver. + * @dev: pointer to device object for subdrv device driver. * @drm_dev: pointer to drm_device and this pointer would be set * when sub driver calls exynos_drm_subdrv_register(). - * @is_local: appear encoder and connector disrelated device. + * @manager: subdrv has its own manager to control a hardware appropriately + * and we can access a hardware drawing on this manager. * @probe: this callback would be called by exynos drm driver after * subdrv is registered to it. * @remove: this callback is used to release resources created * by probe callback. * @open: this would be called with drm device file open. * @close: this would be called with drm device file close. - * @manager: subdrv has its own manager to control a hardware appropriately - * and we can access a hardware drawing on this manager. * @encoder: encoder object owned by this sub driver. * @connector: connector object owned by this sub driver. */ struct exynos_drm_subdrv { struct list_head list; + struct device *dev; struct drm_device *drm_dev; - bool is_local; + struct exynos_drm_manager *manager; int (*probe)(struct drm_device *drm_dev, struct device *dev); void (*remove)(struct drm_device *dev); @@ -251,7 +252,6 @@ struct exynos_drm_subdrv { void (*close)(struct drm_device *drm_dev, struct device *dev, struct drm_file *file); - struct exynos_drm_manager manager; struct drm_encoder *encoder; struct drm_connector *connector; }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index ecb6db2..29fdbfe 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -172,7 +172,7 @@ static void fimd_dpms(struct device *subdrv_dev, int mode) static void fimd_apply(struct device *subdrv_dev) { struct fimd_context *ctx = get_fimd_context(subdrv_dev); - struct exynos_drm_manager *mgr = &ctx->subdrv.manager; + struct exynos_drm_manager *mgr = ctx->subdrv.manager; struct exynos_drm_manager_ops *mgr_ops = mgr->ops; struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops; struct fimd_win_data *win_data; @@ -577,6 +577,13 @@ static struct exynos_drm_overlay_ops fimd_overlay_ops = { .disable = fimd_win_disable, }; +static struct exynos_drm_manager fimd_manager = { + .pipe = -1, + .ops = &fimd_manager_ops, + .overlay_ops = &fimd_overlay_ops, + .display_ops = &fimd_display_ops, +}; + static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) { struct exynos_drm_private *dev_priv = drm_dev->dev_private; @@ -628,7 +635,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) struct fimd_context *ctx = (struct fimd_context *)dev_id; struct exynos_drm_subdrv *subdrv = &ctx->subdrv; struct drm_device *drm_dev = subdrv->drm_dev; - struct exynos_drm_manager *manager = &subdrv->manager; + struct exynos_drm_manager *manager = subdrv->manager; u32 val; val = readl(ctx->regs + VIDINTCON1); @@ -744,7 +751,7 @@ static void fimd_clear_win(struct fimd_context *ctx, int win) static int fimd_power_on(struct fimd_context *ctx, bool enable) { struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct device *dev = subdrv->manager.dev; + struct device *dev = subdrv->dev; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -867,13 +874,10 @@ static int __devinit fimd_probe(struct platform_device *pdev) subdrv = &ctx->subdrv; + subdrv->dev = dev; + subdrv->manager = &fimd_manager; subdrv->probe = fimd_subdrv_probe; subdrv->remove = fimd_subdrv_remove; - subdrv->manager.pipe = -1; - subdrv->manager.ops = &fimd_manager_ops; - subdrv->manager.overlay_ops = &fimd_overlay_ops; - subdrv->manager.display_ops = &fimd_display_ops; - subdrv->manager.dev = dev; mutex_init(&ctx->lock); diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c index 348048b..3424463 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c @@ -117,7 +117,7 @@ static int drm_hdmi_enable_vblank(struct device *subdrv_dev) { struct drm_hdmi_context *ctx = to_context(subdrv_dev); struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct exynos_drm_manager *manager = &subdrv->manager; + struct exynos_drm_manager *manager = subdrv->manager; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -251,6 +251,12 @@ static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { .disable = drm_mixer_disable, }; +static struct exynos_drm_manager hdmi_manager = { + .pipe = -1, + .ops = &drm_hdmi_manager_ops, + .overlay_ops = &drm_hdmi_overlay_ops, + .display_ops = &drm_hdmi_display_ops, +}; static int hdmi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) @@ -318,12 +324,9 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev) subdrv = &ctx->subdrv; + subdrv->dev = dev; + subdrv->manager = &hdmi_manager; subdrv->probe = hdmi_subdrv_probe; - subdrv->manager.pipe = -1; - subdrv->manager.ops = &drm_hdmi_manager_ops; - subdrv->manager.overlay_ops = &drm_hdmi_overlay_ops; - subdrv->manager.display_ops = &drm_hdmi_display_ops; - subdrv->manager.dev = dev; platform_set_drvdata(pdev, subdrv); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 8e1339f..7b9c153 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -199,7 +199,7 @@ static void vidi_dpms(struct device *subdrv_dev, int mode) static void vidi_apply(struct device *subdrv_dev) { struct vidi_context *ctx = get_vidi_context(subdrv_dev); - struct exynos_drm_manager *mgr = &ctx->subdrv.manager; + struct exynos_drm_manager *mgr = ctx->subdrv.manager; struct exynos_drm_manager_ops *mgr_ops = mgr->ops; struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops; struct vidi_win_data *win_data; @@ -374,6 +374,13 @@ static struct exynos_drm_overlay_ops vidi_overlay_ops = { .disable = vidi_win_disable, }; +static struct exynos_drm_manager vidi_manager = { + .pipe = -1, + .ops = &vidi_manager_ops, + .overlay_ops = &vidi_overlay_ops, + .display_ops = &vidi_display_ops, +}; + static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc) { struct exynos_drm_private *dev_priv = drm_dev->dev_private; @@ -425,7 +432,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) struct vidi_context *ctx = container_of(work, struct vidi_context, work); struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct exynos_drm_manager *manager = &subdrv->manager; + struct exynos_drm_manager *manager = subdrv->manager; if (manager->pipe < 0) return; @@ -471,7 +478,7 @@ static void vidi_subdrv_remove(struct drm_device *drm_dev) static int vidi_power_on(struct vidi_context *ctx, bool enable) { struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct device *dev = subdrv->manager.dev; + struct device *dev = subdrv->dev; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -611,13 +618,10 @@ static int __devinit vidi_probe(struct platform_device *pdev) ctx->raw_edid = (struct edid *)fake_edid_info; subdrv = &ctx->subdrv; + subdrv->dev = dev; + subdrv->manager = &vidi_manager; subdrv->probe = vidi_subdrv_probe; subdrv->remove = vidi_subdrv_remove; - subdrv->manager.pipe = -1; - subdrv->manager.ops = &vidi_manager_ops; - subdrv->manager.overlay_ops = &vidi_overlay_ops; - subdrv->manager.display_ops = &vidi_display_ops; - subdrv->manager.dev = dev; mutex_init(&ctx->lock); -- cgit v0.10.2 From 9e41dd35b39c2cf40767332b8f914d7afe25cc40 Mon Sep 17 00:00:00 2001 From: Andrei Warkentin Date: Thu, 12 Apr 2012 15:55:21 +1000 Subject: MD: Bitmap version cleanup. bitmap_new_disk_sb() would still create V3 bitmap superblock with host-endian layout. Perhaps I'm confused, but shouldn't bitmap_new_disk_sb() be creating a V4 bitmap superblock instead, that is portable, as per comment in bitmap.h? Signed-off-by: Andrei Warkentin Signed-off-by: NeilBrown diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 3d0dfa7..1c264a7 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -539,9 +539,6 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap) bitmap->events_cleared = bitmap->mddev->events; sb->events_cleared = cpu_to_le64(bitmap->mddev->events); - bitmap->flags |= BITMAP_HOSTENDIAN; - sb->version = cpu_to_le32(BITMAP_MAJOR_HOSTENDIAN); - kunmap_atomic(sb); return 0; -- cgit v0.10.2 From 038d4fef376bc494d4f11072d2ab248414b7d568 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Apr 2012 17:18:12 +0200 Subject: ALSA: hda/realtek - Fix GPIO1 setup for Acer Aspire 4930 & co Add GPIO1 setup explicitly for Acer Aspire 493x & co. This could be set by alc_auto_init_amp(), but it's safer to set it more explicitly in the fixup table. Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e7b2b83..4eec215 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5269,7 +5269,9 @@ static const struct alc_fixup alc882_fixups[] = { { 0x16, 0x99130111 }, /* CLFE speaker */ { 0x17, 0x99130112 }, /* surround speaker */ { } - } + }, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, }, [ALC882_FIXUP_ACER_ASPIRE_8930G] = { .type = ALC_FIXUP_PINS, @@ -5312,7 +5314,9 @@ static const struct alc_fixup alc882_fixups[] = { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, { } - } + }, + .chained = true, + .chain_id = ALC882_FIXUP_GPIO1, }, [ALC885_FIXUP_MACPRO_GPIO] = { .type = ALC_FIXUP_FUNC, -- cgit v0.10.2 From f4380a915823dbed0bf8e3cf502ebcf2b7c7f833 Mon Sep 17 00:00:00 2001 From: majianpeng Date: Thu, 12 Apr 2012 16:04:47 +1000 Subject: md/raid1,raid10: Fix calculation of 'vcnt' when processing error recovery. If r1bio->sectors % 8 != 0,then the memcmp and a later memcpy will omit the last bio_vec. This is suitable for any stable kernel since 3.1 when bad-block management was introduced. Cc: stable@vger.kernel.org Signed-off-by: majianpeng Signed-off-by: NeilBrown diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index d35e4c9..15dd59b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1712,6 +1712,7 @@ static int process_checks(struct r1bio *r1_bio) struct r1conf *conf = mddev->private; int primary; int i; + int vcnt; for (primary = 0; primary < conf->raid_disks * 2; primary++) if (r1_bio->bios[primary]->bi_end_io == end_sync_read && @@ -1721,9 +1722,9 @@ static int process_checks(struct r1bio *r1_bio) break; } r1_bio->read_disk = primary; + vcnt = (r1_bio->sectors + PAGE_SIZE / 512 - 1) >> (PAGE_SHIFT - 9); for (i = 0; i < conf->raid_disks * 2; i++) { int j; - int vcnt = r1_bio->sectors >> (PAGE_SHIFT- 9); struct bio *pbio = r1_bio->bios[primary]; struct bio *sbio = r1_bio->bios[i]; int size; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index fff7821..c8dbb84 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1788,6 +1788,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) struct r10conf *conf = mddev->private; int i, first; struct bio *tbio, *fbio; + int vcnt; atomic_set(&r10_bio->remaining, 1); @@ -1802,10 +1803,10 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) first = i; fbio = r10_bio->devs[i].bio; + vcnt = (r10_bio->sectors + (PAGE_SIZE >> 9) - 1) >> (PAGE_SHIFT - 9); /* now find blocks with errors */ for (i=0 ; i < conf->copies ; i++) { int j, d; - int vcnt = r10_bio->sectors >> (PAGE_SHIFT-9); tbio = r10_bio->devs[i].bio; @@ -1871,7 +1872,6 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) */ for (i = 0; i < conf->copies; i++) { int j, d; - int vcnt = r10_bio->sectors >> (PAGE_SHIFT-9); tbio = r10_bio->devs[i].repl_bio; if (!tbio || !tbio->bi_end_io) -- cgit v0.10.2 From afbaa90b80b1ec66e5137cc3824746bfdf559b18 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 12 Apr 2012 16:05:06 +1000 Subject: md/bitmap: prevent bitmap_daemon_work running while initialising bitmap If a bitmap is added while the array is active, it is possible for bitmap_daemon_work to run while the bitmap is being initialised. This is particularly a problem if bitmap_daemon_work sees bitmap->filemap as non-NULL before it has been filled in properly. So hold bitmap_info.mutex while filling in ->filemap to prevent problems. This patch is suitable for any -stable kernel, though it might not apply cleanly before about 3.1. Cc: stable@vger.kernel.org Signed-off-by: NeilBrown diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1c264a7..97e73e5 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1785,7 +1785,9 @@ int bitmap_load(struct mddev *mddev) * re-add of a missing device */ start = mddev->recovery_cp; + mutex_lock(&mddev->bitmap_info.mutex); err = bitmap_init_from_disk(bitmap, start); + mutex_unlock(&mddev->bitmap_info.mutex); if (err) goto out; -- cgit v0.10.2 From 6fa6c8e25e95bdc73e92e4c96b8e3299169b616e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Wed, 15 Feb 2012 15:06:08 -0700 Subject: irq_domain: Move irq_virq_count into NOMAP revmap This patch replaces the old global setting of irq_virq_count that is only used by the NOMAP mapping and instead uses a revmap_data property so that the maximum NOMAP allocation can be set per NOMAP irq_domain. There is exactly one user of irq_virq_count in-tree right now: PS3. Also, irq_virq_count is only useful for the NOMAP mapping. So, instead of having a single global irq_virq_count values, this change drops it entirely and added a max_irq argument to irq_domain_add_nomap(). That makes it a property of an individual nomap irq domain instead of a global system settting. Signed-off-by: Grant Likely Tested-by: Benjamin Herrenschmidt Cc: Thomas Gleixner Cc: Milton Miller diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index db360fc..d09f3e8 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -392,7 +392,7 @@ static int axon_msi_probe(struct platform_device *device) } memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES); - msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic); + msic->irq_domain = irq_domain_add_nomap(dn, 0, &msic_host_ops, msic); if (!msic->irq_domain) { printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n", dn->full_name); diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index e5c3a2c..f9a48af 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c @@ -239,7 +239,7 @@ void __init beatic_init_IRQ(void) ppc_md.get_irq = beatic_get_irq; /* Allocate an irq host */ - beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL); + beatic_host = irq_domain_add_nomap(NULL, 0, &beatic_pic_host_ops, NULL); BUG_ON(beatic_host == NULL); irq_set_default_host(beatic_host); } diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index a81e5a8..b4ddaa3 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -192,7 +192,7 @@ static int psurge_secondary_ipi_init(void) { int rc = -ENOMEM; - psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL); + psurge_host = irq_domain_add_nomap(NULL, 0, &psurge_host_ops, NULL); if (psurge_host) psurge_secondary_virq = irq_create_direct_mapping(psurge_host); diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 2a4ff86..5f3b232 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -753,9 +753,8 @@ void __init ps3_init_IRQ(void) unsigned cpu; struct irq_domain *host; - host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL); + host = irq_domain_add_nomap(NULL, PS3_PLUG_MAX + 1, &ps3_host_ops, NULL); irq_set_default_host(host); - irq_set_virq_count(PS3_PLUG_MAX + 1); for_each_possible_cpu(cpu) { struct ps3_private *pd = &per_cpu(ps3_private, cpu); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index ac17b9b..c65740d 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -98,6 +98,9 @@ struct irq_domain { unsigned int size; unsigned int *revmap; } linear; + struct { + unsigned int max_irq; + } nomap; struct radix_tree_root tree; } revmap_data; const struct irq_domain_ops *ops; @@ -120,6 +123,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node, const struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, + unsigned int max_irq, const struct irq_domain_ops *ops, void *host_data); struct irq_domain *irq_domain_add_tree(struct device_node *of_node, @@ -128,7 +132,6 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node, extern struct irq_domain *irq_find_host(struct device_node *node); extern void irq_set_default_host(struct irq_domain *host); -extern void irq_set_virq_count(unsigned int count); static inline struct irq_domain *irq_domain_add_legacy_isa( struct device_node *of_node, @@ -140,7 +143,6 @@ static inline struct irq_domain *irq_domain_add_legacy_isa( } extern struct irq_domain *irq_find_host(struct device_node *node); extern void irq_set_default_host(struct irq_domain *host); -extern void irq_set_virq_count(unsigned int count); extern unsigned int irq_create_mapping(struct irq_domain *host, diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index eb05e40..d34413e 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -23,7 +23,6 @@ static LIST_HEAD(irq_domain_list); static DEFINE_MUTEX(irq_domain_mutex); static DEFINE_MUTEX(revmap_trees_mutex); -static unsigned int irq_virq_count = NR_IRQS; static struct irq_domain *irq_default_domain; /** @@ -184,13 +183,16 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node, } struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, + unsigned int max_irq, const struct irq_domain_ops *ops, void *host_data) { struct irq_domain *domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_NOMAP, ops, host_data); - if (domain) + if (domain) { + domain->revmap_data.nomap.max_irq = max_irq ? max_irq : ~0; irq_domain_add(domain); + } return domain; } @@ -262,22 +264,6 @@ void irq_set_default_host(struct irq_domain *domain) irq_default_domain = domain; } -/** - * irq_set_virq_count() - Set the maximum number of linux irqs - * @count: number of linux irqs, capped with NR_IRQS - * - * This is mainly for use by platforms like iSeries who want to program - * the virtual irq number in the controller to avoid the reverse mapping - */ -void irq_set_virq_count(unsigned int count) -{ - pr_debug("irq: Trying to set virq count to %d\n", count); - - BUG_ON(count < NUM_ISA_INTERRUPTS); - if (count < NR_IRQS) - irq_virq_count = count; -} - static int irq_setup_virq(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { @@ -320,13 +306,12 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) pr_debug("irq: create_direct virq allocation failed\n"); return 0; } - if (virq >= irq_virq_count) { + if (virq >= domain->revmap_data.nomap.max_irq) { pr_err("ERROR: no free irqs available below %i maximum\n", - irq_virq_count); + domain->revmap_data.nomap.max_irq); irq_free_desc(virq); return 0; } - pr_debug("irq: create_direct obtained virq %d\n", virq); if (irq_setup_virq(domain, virq, virq)) { @@ -378,7 +363,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain, return irq_domain_legacy_revmap(domain, hwirq); /* Allocate a virtual interrupt number */ - hint = hwirq % irq_virq_count; + hint = hwirq % nr_irqs; if (hint == 0) hint++; virq = irq_alloc_desc_from(hint, 0); @@ -516,7 +501,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) { unsigned int i; - unsigned int hint = hwirq % irq_virq_count; + unsigned int hint = hwirq % nr_irqs; /* Look for default domain if nececssary */ if (domain == NULL) @@ -537,7 +522,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain, if (data && (data->domain == domain) && (data->hwirq == hwirq)) return i; i++; - if (i >= irq_virq_count) + if (i >= nr_irqs) i = 1; } while(i != hint); return 0; -- cgit v0.10.2 From 63634806519b49bb43f37e53a1e8366eb3e846a4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Apr 2012 08:47:05 +0200 Subject: block: mtip32xx: remove HOTPLUG_PCI_PCIE dependancy This removes the HOTPLUG_PCI_PCIE dependency on the driver and makes it depend on PCI. Cc: Sam Bradshaw Signed-off-by: Greg Kroah-Hartman Acked-by: Asai Thambi S P Signed-off-by: Jens Axboe diff --git a/drivers/block/mtip32xx/Kconfig b/drivers/block/mtip32xx/Kconfig index b5dd14e..0ba837f 100644 --- a/drivers/block/mtip32xx/Kconfig +++ b/drivers/block/mtip32xx/Kconfig @@ -4,6 +4,6 @@ config BLK_DEV_PCIESSD_MTIP32XX tristate "Block Device Driver for Micron PCIe SSDs" - depends on HOTPLUG_PCI_PCIE + depends on PCI help This enables the block driver for Micron PCIe SSDs. -- cgit v0.10.2 From 15a13bbdffb0d6288a5dd04aee9736267da1335f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 12 Apr 2012 01:27:57 +0200 Subject: drm/i915: clear fencing tracking state when retiring requests This fixes a resume regression introduced in commit 7dd4906586274f3945f2aeaaa5a33b451c3b4bba Author: Chris Wilson Date: Wed Mar 21 10:48:18 2012 +0000 drm/i915: Mark untiled BLT commands as fenced on gen2/3 which fixed fencing tracking for untiled blt commands. A side effect of that patch was that now also untiled objects have a non-zero obj->last_fenced_seqno to track when a fence can be set up after a pipelined tiling change. Unfortunately this was only cleared by the fence setup and teardown code, resulting in tons of untiled but inactive objects with non-zero last_fenced_seqno. Now after resume we completely reset the seqno tracking, both on the driver side (by setting dev_priv->next_seqno = 1) and on the hw side (by allocating a new hws page, which contains the seqnos). Hilarity and indefinite waits ensued from the stale seqnos in obj->last_fenced_seqno from before the suspend. The fix is to properly clear the fencing tracking state like we already do for the normal gpu rendering while moving objects off the active list. Reported-and-tested-by: "Rafael J. Wysocki" Cc: Jiri Slaby Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4c65c63..0e3c6ac 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1493,6 +1493,7 @@ i915_gem_object_move_off_active(struct drm_i915_gem_object *obj) { list_del_init(&obj->ring_list); obj->last_rendering_seqno = 0; + obj->last_fenced_seqno = 0; } static void @@ -1521,6 +1522,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) BUG_ON(!list_empty(&obj->gpu_write_list)); BUG_ON(!obj->active); obj->ring = NULL; + obj->last_fenced_ring = NULL; i915_gem_object_move_off_active(obj); obj->fenced_gpu_access = false; -- cgit v0.10.2 From 490aa60ee7e884febf4818234d5c97669665db9a Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Thu, 12 Apr 2012 16:42:54 +0900 Subject: drm/exynos: fixed exynos broken ioctl this patch removes the pointer of uint64_t *edid. it should be just a uint64_t. Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h index 1bb2d47..e478de4 100644 --- a/include/drm/exynos_drm.h +++ b/include/drm/exynos_drm.h @@ -85,7 +85,7 @@ struct drm_exynos_gem_mmap { struct drm_exynos_vidi_connection { unsigned int connection; unsigned int extensions; - uint64_t *edid; + uint64_t edid; }; struct drm_exynos_plane_set_zpos { -- cgit v0.10.2 From 6f3603367b8f7c34598fdfc1058622e0e1951e98 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 12 Apr 2012 07:51:08 -0700 Subject: IB/srpt: Set srq_type to IB_SRQT_BASIC Since commit 96104eda0169 ("RDMA/core: Add SRQ type field"), kernel users of SRQs need to specify srq_type = IB_SRQT_BASIC in struct ib_srq_init_attr, or else most low-level drivers will fail in when srpt_add_one() calls ib_create_srq() and gets -ENOSYS. (mlx4_ib works OK nearly all of the time, because it just needs srq_type != IB_SRQT_XRC. And apparently nearly everyone using ib_srpt is using mlx4 hardware) Reported-by: Alexey Shvetsov Cc: Signed-off-by: Roland Dreier diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 69e2ad0..daf21b8 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3232,6 +3232,7 @@ static void srpt_add_one(struct ib_device *device) srq_attr.attr.max_wr = sdev->srq_size; srq_attr.attr.max_sge = 1; srq_attr.attr.srq_limit = 0; + srq_attr.srq_type = IB_SRQT_BASIC; sdev->srq = ib_create_srq(sdev->pd, &srq_attr); if (IS_ERR(sdev->srq)) -- cgit v0.10.2 From 9de29225bdd25958c1fa82521ff02726f1cab953 Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Mon, 2 Apr 2012 13:38:49 -0700 Subject: USB: update usbtmc api documentation Correct path names in API documentation for usbtmc Signed-off-by: Stephen Lewis Signed-off-by: Greg Kroah-Hartman diff --git a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc index 2a7f9a0..e960cd0 100644 --- a/Documentation/ABI/stable/sysfs-driver-usb-usbtmc +++ b/Documentation/ABI/stable/sysfs-driver-usb-usbtmc @@ -1,5 +1,5 @@ -What: /sys/bus/usb/drivers/usbtmc/devices/*/interface_capabilities -What: /sys/bus/usb/drivers/usbtmc/devices/*/device_capabilities +What: /sys/bus/usb/drivers/usbtmc/*/interface_capabilities +What: /sys/bus/usb/drivers/usbtmc/*/device_capabilities Date: August 2008 Contact: Greg Kroah-Hartman Description: @@ -12,8 +12,8 @@ Description: The files are read only. -What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_interface_capabilities -What: /sys/bus/usb/drivers/usbtmc/devices/*/usb488_device_capabilities +What: /sys/bus/usb/drivers/usbtmc/*/usb488_interface_capabilities +What: /sys/bus/usb/drivers/usbtmc/*/usb488_device_capabilities Date: August 2008 Contact: Greg Kroah-Hartman Description: @@ -27,7 +27,7 @@ Description: The files are read only. -What: /sys/bus/usb/drivers/usbtmc/devices/*/TermChar +What: /sys/bus/usb/drivers/usbtmc/*/TermChar Date: August 2008 Contact: Greg Kroah-Hartman Description: @@ -40,7 +40,7 @@ Description: sent to the device or not. -What: /sys/bus/usb/drivers/usbtmc/devices/*/TermCharEnabled +What: /sys/bus/usb/drivers/usbtmc/*/TermCharEnabled Date: August 2008 Contact: Greg Kroah-Hartman Description: @@ -51,7 +51,7 @@ Description: published by the USB-IF. -What: /sys/bus/usb/drivers/usbtmc/devices/*/auto_abort +What: /sys/bus/usb/drivers/usbtmc/*/auto_abort Date: August 2008 Contact: Greg Kroah-Hartman Description: -- cgit v0.10.2 From 8e62c2de6e23e5c1fee04f59de51b54cc2868ca5 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 12 Apr 2012 13:46:48 -0400 Subject: Revert "Btrfs: increase the global block reserve estimates" This reverts commit 5500cdbe14d7435e04f66ff3cfb8ecd8b8e44ebf. We've had a number of complaints of early enospc that bisect down to this patch. We'll hae to fix the reservations differently. CC: stable@kernel.org Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a844204..ace5e8c 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -4205,7 +4205,7 @@ static u64 calc_global_metadata_size(struct btrfs_fs_info *fs_info) num_bytes += div64_u64(data_used + meta_used, 50); if (num_bytes * 3 > meta_used) - num_bytes = div64_u64(meta_used, 3) * 2; + num_bytes = div64_u64(meta_used, 3); return ALIGN(num_bytes, fs_info->extent_root->leafsize << 10); } -- cgit v0.10.2 From fe97da1f7001ca0f572358462606eb3d1bde3f23 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Apr 2012 08:00:19 +0200 Subject: ALSA: hda/realtek - Add a fixup entry for Acer Aspire 8940G It's compatible with 8930G. Using the same fixup gives the proper 5.1 sound back. Reported-and-tested-by: Dany Martineau Cc: [v3.3+] Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4eec215..d25a6f9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5363,6 +5363,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { ALC882_FIXUP_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210), SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE), + SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736), SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), -- cgit v0.10.2 From 29ebe40284c75a5888c601872059fca7e258528d Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 12 Apr 2012 13:55:36 -0400 Subject: ALSA: hda/realtek - Add quirk for Mac Pro 5,1 machines A user reported that setting model=imac24 used to allow sound to work on their Mac Pro 5,1 machine. Commit 5671087ffa "Move ALC885 macpro and imac24 models to auto-parser" removed this model option. All Mac machines are now explicitly handled with a quirk and the auto-parser. This adds a quirk for the device found on the Mac Pro 5,1 machines. This (partially) fixes https://bugzilla.redhat.com/show_bug.cgi?id=808559 [sorted the new entry in the ID number order by tiwai] Reported-by: Gabriel Somlo Signed-off-by: Josh Boyer Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d25a6f9..8f4a484 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5389,6 +5389,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), + SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), -- cgit v0.10.2 From cce66a283e36e7479774de47ae9f33f7db2b8fcf Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 27 Mar 2012 18:59:38 -0700 Subject: drm/i915: add rc6 residency times to debugfs RC6 residency should be in intervals of 1.28us, and the counter wraps. Here is an example using awk to get the various RC6 and RC6+ residency times in seconds, since boot. cat /sys/kernel/debug/dri/0/i915_drpc_info | grep residency | awk -F':' -F' ' '{print $5 * 1.28 / 1000000}' This is primarily for QA, but has other applications as well. An upcoming patch to add interfaces should be more interesting to application developers. v2: move comment to the correct place v3: display with %u instead of %d, for Ouping CC: Ouping Zhang Reviewed-by: Eugeni Dodonov Signed-off-by: Ben Widawsky Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 967fb92..97c9630 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1171,6 +1171,17 @@ static int gen6_drpc_info(struct seq_file *m) seq_printf(m, "Core Power Down: %s\n", yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); + + /* Not exactly sure what this is */ + seq_printf(m, "RC6 \"Locked to RPn\" residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6_LOCKED)); + seq_printf(m, "RC6 residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6)); + seq_printf(m, "RC6+ residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6p)); + seq_printf(m, "RC6++ residency since boot: %u\n", + I915_READ(GEN6_GT_GFX_RC6pp)); + return 0; } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6924f44..972321f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3970,6 +3970,11 @@ GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) +#define GEN6_GT_GFX_RC6_LOCKED 0x138104 +#define GEN6_GT_GFX_RC6 0x138108 +#define GEN6_GT_GFX_RC6p 0x13810C +#define GEN6_GT_GFX_RC6pp 0x138110 + #define GEN6_PCODE_MAILBOX 0x138124 #define GEN6_PCODE_READY (1<<31) #define GEN6_READ_OC_PARAMS 0xc -- cgit v0.10.2 From 9a5a53b3923d6e8cc4d3b352301059ac6b5c8f68 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 22 Mar 2012 15:10:00 +0000 Subject: drm/i915: Reorganise rules for get_fence/put_fence By simplifying the rules to calling get_fence when writing to the through the GTT in a tiled manner, and calling put_fence before writing to the object through the GTT in a linear manner, the code becomes clearer and there is less chance of making a mistake. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter [danvet: fixed up conflict with ppgtt code and spelling in a new comment.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 92e496a..9bc64d2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1256,13 +1256,15 @@ int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); -static inline void +static inline bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) { if (obj->fence_reg != I915_FENCE_REG_NONE) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; dev_priv->fence_regs[obj->fence_reg].pin_count++; - } + return true; + } else + return false; } static inline void diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b851bd3..ad71751 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1078,10 +1078,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(obj, obj->cache_level); - if (obj->tiling_mode == I915_TILING_NONE) - ret = i915_gem_object_put_fence(obj); - else - ret = i915_gem_object_get_fence(obj, NULL); + ret = i915_gem_object_get_fence(obj, NULL); if (ret) goto unlock; @@ -2395,19 +2392,19 @@ i915_find_fence_reg(struct drm_device *dev, } /** - * i915_gem_object_get_fence - set up a fence reg for an object + * i915_gem_object_get_fence - set up fencing for an object * @obj: object to map through a fence reg * @pipelined: ring on which to queue the change, or NULL for CPU access - * @interruptible: must we wait uninterruptibly for the register to retire? * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. - * * This function walks the fence regs looking for a free one for @obj, * stealing one if it can't find any. * * It then sets up the reg based on the object's properties: address, pitch * and tiling format. + * + * For an untiled surface, this removes any existing fence. */ int i915_gem_object_get_fence(struct drm_i915_gem_object *obj, @@ -2418,6 +2415,9 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *reg; int ret; + if (obj->tiling_mode == I915_TILING_NONE) + return i915_gem_object_put_fence(obj); + /* XXX disable pipelining. There are bugs. Shocking. */ pipelined = NULL; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 254e2f6..56d1001 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -530,18 +530,13 @@ pin_and_fence_object(struct drm_i915_gem_object *obj, if (has_fenced_gpu_access) { if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { - if (obj->tiling_mode) { - ret = i915_gem_object_get_fence(obj, ring); - if (ret) - goto err_unpin; + ret = i915_gem_object_get_fence(obj, ring); + if (ret) + goto err_unpin; + if (i915_gem_object_pin_fence(obj)) entry->flags |= __EXEC_OBJECT_HAS_FENCE; - i915_gem_object_pin_fence(obj); - } else { - ret = i915_gem_object_put_fence(obj); - if (ret) - goto err_unpin; - } + obj->pending_fenced_gpu_access = true; } } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 37514a5..9dfa1fa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2152,13 +2152,11 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * framebuffer compression. For simplicity, we always install * a fence as the cost is not that onerous. */ - if (obj->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence(obj, pipelined); - if (ret) - goto err_unpin; + ret = i915_gem_object_get_fence(obj, pipelined); + if (ret) + goto err_unpin; - i915_gem_object_pin_fence(obj); - } + i915_gem_object_pin_fence(obj); dev_priv->mm.interruptible = true; return 0; -- cgit v0.10.2 From 2911a35b2e4eb87ec48d03aeb11f019e51ae3c0d Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 5 Apr 2012 14:47:36 -0700 Subject: drm/i915: use semaphores for the display plane In theory this will have performance and power improvements. Performance because we don't need to stall when the scanout BO is busy, and power because we don't have to stall when the BO is busy (and the ring can even go to sleep if the HW supports it). v2: squash 2 patches into 1 (me) un-inline the enable_semaphores function (Daniel) remove comment about SNB hangs from i915_gem_object_sync (Chris) rename intel_enable_semaphores to i915_semaphore_is_enabled (me) removed page flip comment; "no why" (Chris) To address other comments from Daniel (irc): update the comment to say 'vt-d is crap, don't enable semaphores' - I think you misinterpreted Chris' comment, it already exists. checking out whether we can pageflip on the render ring on ivb (didn't work on early silicon) - We don't want to enable workarounds for early silicon unless we have to. - I can't find any references in the docs about this. optionally use it if the fb is already busy on the render ring - This should be how the code already worked, unless I am misunderstanding your meaning. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c33b0a4..96f8efc 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -394,6 +394,21 @@ void intel_detect_pch(struct drm_device *dev) } } +bool i915_semaphore_is_enabled(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + return 0; + + if (i915_semaphores >= 0) + return i915_semaphores; + + /* Enable semaphores on SNB when IO remapping is off */ + if (INTEL_INFO(dev)->gen == 6) + return !intel_iommu_enabled; + + return 1; +} + void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { int count; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9bc64d2..7dcdccb 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -38,6 +38,7 @@ #include #include #include +#include /* General customization: */ @@ -1230,6 +1231,8 @@ void i915_gem_lastclose(struct drm_device *dev); int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); +int i915_gem_object_sync(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *to); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, u32 seqno); @@ -1439,6 +1442,7 @@ extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); +extern bool i915_semaphore_is_enabled(struct drm_device *dev); extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv); extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ad71751..d75a657 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1953,6 +1953,48 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) return 0; } +int +i915_gem_object_sync(struct drm_i915_gem_object *obj, + struct intel_ring_buffer *to) +{ + struct intel_ring_buffer *from = obj->ring; + u32 seqno; + int ret, idx; + + if (from == NULL || to == from) + return 0; + + if (!i915_semaphore_is_enabled(obj->base.dev)) + return i915_gem_object_wait_rendering(obj); + + idx = intel_ring_sync_index(from, to); + + seqno = obj->last_rendering_seqno; + if (seqno <= from->sync_seqno[idx]) + return 0; + + if (seqno == from->outstanding_lazy_request) { + struct drm_i915_gem_request *request; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (request == NULL) + return -ENOMEM; + + ret = i915_add_request(from, NULL, request); + if (ret) { + kfree(request); + return ret; + } + + seqno = request->seqno; + } + + from->sync_seqno[idx] = seqno; + + return to->sync_to(to, from, seqno - 1); + +} + static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) { u32 old_write_domain, old_read_domains; @@ -2926,11 +2968,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, * Prepare buffer for display plane (scanout, cursors, etc). * Can be called from an uninterruptible phase (modesetting) and allows * any flushes to be pipelined (for pageflips). - * - * For the display plane, we want to be in the GTT but out of any write - * domains. So in many ways this looks like set_to_gtt_domain() apart from the - * ability to pipeline the waits, pinning and any additional subtleties - * that may differentiate the display plane from ordinary buffers. */ int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, @@ -2945,8 +2982,8 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, return ret; if (pipelined != obj->ring) { - ret = i915_gem_object_wait_rendering(obj); - if (ret == -ERESTARTSYS) + ret = i915_gem_object_sync(obj, pipelined); + if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 56d1001..2a24d0c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -835,64 +835,6 @@ i915_gem_execbuffer_flush(struct drm_device *dev, return 0; } -static bool -intel_enable_semaphores(struct drm_device *dev) -{ - if (INTEL_INFO(dev)->gen < 6) - return 0; - - if (i915_semaphores >= 0) - return i915_semaphores; - - /* Disable semaphores on SNB */ - if (INTEL_INFO(dev)->gen == 6) - return 0; - - return 1; -} - -static int -i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *to) -{ - struct intel_ring_buffer *from = obj->ring; - u32 seqno; - int ret, idx; - - if (from == NULL || to == from) - return 0; - - /* XXX gpu semaphores are implicated in various hard hangs on SNB */ - if (!intel_enable_semaphores(obj->base.dev)) - return i915_gem_object_wait_rendering(obj); - - idx = intel_ring_sync_index(from, to); - - seqno = obj->last_rendering_seqno; - if (seqno <= from->sync_seqno[idx]) - return 0; - - if (seqno == from->outstanding_lazy_request) { - struct drm_i915_gem_request *request; - - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; - - ret = i915_add_request(from, NULL, request); - if (ret) { - kfree(request); - return ret; - } - - seqno = request->seqno; - } - - from->sync_seqno[idx] = seqno; - - return to->sync_to(to, from, seqno - 1); -} - static int i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) { @@ -954,7 +896,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, } list_for_each_entry(obj, objects, exec_list) { - ret = i915_gem_execbuffer_sync_rings(obj, ring); + ret = i915_gem_object_sync(obj, ring); if (ret) return ret; } -- cgit v0.10.2 From 3fdcf43192559f53305644d0c1e0f7dda398f091 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 6 Apr 2012 11:46:27 -0700 Subject: drm/i915: use register name when disabling VGA Just noticed this while verifying the VGA disable code. Signed-off-by: Jesse Barnes Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9dfa1fa..42dbe14 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9522,7 +9522,7 @@ static void i915_disable_vga(struct drm_device *dev) vga_reg = VGACNTRL; vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); - outb(1, VGA_SR_INDEX); + outb(SR01, VGA_SR_INDEX); sr1 = inb(VGA_SR_DATA); outb(sr1 | 1<<5, VGA_SR_DATA); vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); -- cgit v0.10.2 From 26883c31b0799e76edf8f0ea8be48b64e09b2a7d Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:36 +0800 Subject: drm/i915/intel_i2c: handle zero-length writes A common method of probing an i2c bus is trying to do a zero-length write. Handle this case by checking the length first before decrementing it. This is actually important, since attempting a zero-length write is one of the ways that i2cdetect and i2c_new_probed_device detect whether there is device present on the bus with a given address. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index c12db72..99a04f8 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -248,9 +248,10 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, u32 val, loop; val = loop = 0; - do { - val |= *buf++ << (8 * loop); - } while (--len && ++loop < 4); + while (len && loop < 4) { + val |= *buf++ << (8 * loop++); + len -= 1; + } I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, -- cgit v0.10.2 From 7a39a9d4767e8d22d60f2c4bf5eece4f4398c274 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:37 +0800 Subject: drm/i915/intel_i2c: use double-buffered writes The GMBUS controller GMBUS3 register is double-buffered. Take advantage of this by writing two 4-byte words before the first wait for HW_RDY. This helps keep the GMBUS controller from becoming idle during long writes. In fact, during experiments using the GMBUS interrupts, the HW_RDY interrupt would only trigger for transactions >4 bytes after 2 writes to GMBUS3. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 99a04f8..f02e52a 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -262,13 +262,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); POSTING_READ(GMBUS2 + reg_offset); while (len) { - if (wait_for(I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY), - 50)) - return -ETIMEDOUT; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - return -ENXIO; - val = loop = 0; do { val |= *buf++ << (8 * loop); @@ -276,6 +269,13 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, I915_WRITE(GMBUS3 + reg_offset, val); POSTING_READ(GMBUS2 + reg_offset); + + if (wait_for(I915_READ(GMBUS2 + reg_offset) & + (GMBUS_SATOER | GMBUS_HW_RDY), + 50)) + return -ETIMEDOUT; + if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + return -ENXIO; } return 0; } -- cgit v0.10.2 From e646d5773572bf52017983d758bdf05777dc5600 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:38 +0800 Subject: drm/i915/intel_i2c: always wait for IDLE before clearing NAK The GMBUS controller can report a NAK condition while a transaction is still active. If the driver is fast enough, and the bus is slow enough, the driver may clear the NAK condition while the controller is still busy, resulting in a confused GMBUS controller. This will leave the controller in a bad state such that the next transaction may fail. Also, return -ENXIO if a device NAKs a transaction. Note: this patch also refactors gmbus_xfer to remove the "done" label. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index f02e52a..9707868 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -324,26 +324,47 @@ gmbus_xfer(struct i2c_adapter *adapter, goto clear_err; } - goto done; + /* Mark the GMBUS interface as disabled after waiting for idle. + * We will re-enable it at the start of the next xfer, + * till then let it sleep. + */ + if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) + DRM_INFO("GMBUS [%s] timed out waiting for idle\n", + adapter->name); + I915_WRITE(GMBUS0 + reg_offset, 0); + ret = i; + goto out; clear_err: + /* + * Wait for bus to IDLE before clearing NAK. + * If we clear the NAK while bus is still active, then it will stay + * active and the next transaction may fail. + */ + if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, + 10)) + DRM_INFO("GMBUS [%s] timed out after NAK\n", adapter->name); + /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the * BUS_ERROR raised by the slave's NAK. */ I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); I915_WRITE(GMBUS1 + reg_offset, 0); + I915_WRITE(GMBUS0 + reg_offset, 0); -done: - /* Mark the GMBUS interface as disabled after waiting for idle. - * We will re-enable it at the start of the next xfer, - * till then let it sleep. + DRM_DEBUG_DRIVER("GMBUS [%s] NAK for addr: %04x %c(%d)\n", + adapter->name, msgs[i].addr, + (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); + + /* + * If no ACK is received during the address phase of a transaction, + * the adapter must report -ENXIO. + * It is not clear what to return if no ACK is received at other times. + * So, we always return -ENXIO in all NAK cases, to ensure we send + * it at least during the one case that is specified. */ - if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) - DRM_INFO("GMBUS [%s] timed out waiting for idle\n", - bus->adapter.name); - I915_WRITE(GMBUS0 + reg_offset, 0); - ret = i; + ret = -ENXIO; goto out; timeout: -- cgit v0.10.2 From 72d66afd1461effb143784a0f6cde2a9f9908b70 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:39 +0800 Subject: drm/i915/intel_i2c: use WAIT cycle, not STOP The i915 is only able to generate a STOP cycle (i.e. finalize an i2c transaction) during a DATA or WAIT phase. In other words, the controller rejects a STOP requested as part of the first transaction in a sequence. Thus, for the first transaction we must always use a WAIT cycle, detect when the device has finished (and is in a WAIT phase), and then either start the next transaction, or, if there are no more transactions, generate a STOP cycle. Note: Theoretically, the last transaction of a multi-transaction sequence could initiate a STOP cycle. However, this slight optimization is left for another patch. We return -ETIMEDOUT if the hardware doesn't deactivate after the STOP cycle. Signed-off-by: Daniel Kurtz [danvet: added comment to the code that gmbus can't generate STOP on the very first cycle.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 9707868..291e51e 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -204,8 +204,7 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) } static int -gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - bool last) +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg) { int reg_offset = dev_priv->gpio_mmio_base; u16 len = msg->len; @@ -213,7 +212,6 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (last ? GMBUS_CYCLE_STOP : 0) | (len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); @@ -239,8 +237,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, } static int -gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - bool last) +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) { int reg_offset = dev_priv->gpio_mmio_base; u16 len = msg->len; @@ -256,7 +253,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (last ? GMBUS_CYCLE_STOP : 0) | (msg->len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); @@ -289,7 +285,8 @@ gmbus_xfer(struct i2c_adapter *adapter, struct intel_gmbus, adapter); struct drm_i915_private *dev_priv = bus->dev_priv; - int i, reg_offset, ret; + int i, reg_offset; + int ret = 0; mutex_lock(&dev_priv->gmbus_mutex); @@ -303,20 +300,17 @@ gmbus_xfer(struct i2c_adapter *adapter, I915_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { - bool last = i + 1 == num; - if (msgs[i].flags & I2C_M_RD) - ret = gmbus_xfer_read(dev_priv, &msgs[i], last); + ret = gmbus_xfer_read(dev_priv, &msgs[i]); else - ret = gmbus_xfer_write(dev_priv, &msgs[i], last); + ret = gmbus_xfer_write(dev_priv, &msgs[i]); if (ret == -ETIMEDOUT) goto timeout; if (ret == -ENXIO) goto clear_err; - if (!last && - wait_for(I915_READ(GMBUS2 + reg_offset) & + if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) goto timeout; @@ -324,15 +318,24 @@ gmbus_xfer(struct i2c_adapter *adapter, goto clear_err; } + /* Generate a STOP condition on the bus. Note that gmbus can't generata + * a STOP on the very first cycle. To simplify the code we + * unconditionally generate the STOP condition with an additional gmbus + * cycle. */ + I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY); + /* Mark the GMBUS interface as disabled after waiting for idle. * We will re-enable it at the start of the next xfer, * till then let it sleep. */ - if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) + if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, + 10)) { DRM_INFO("GMBUS [%s] timed out waiting for idle\n", adapter->name); + ret = -ETIMEDOUT; + } I915_WRITE(GMBUS0 + reg_offset, 0); - ret = i; + ret = ret ?: i; goto out; clear_err: -- cgit v0.10.2 From 56f9eac05489912ac0165ffc0ebff0f8588f77d2 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:40 +0800 Subject: drm/i915/intel_i2c: use INDEX cycles for i2c read transactions It is very common for an i2c device to require a small 1 or 2 byte write followed by a read. For example, when reading from an i2c EEPROM it is common to write and address, offset or index followed by a reading some values. The i915 gmbus controller provides a special "INDEX" cycle for performing such a small write followed by a read. The INDEX can be either one or two bytes long. The advantage of using such a cycle is that the CPU has slightly less work to do once the read with INDEX cycle is started. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 291e51e..5e0912a 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -204,13 +204,15 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) } static int -gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, + u32 gmbus1_index) { int reg_offset = dev_priv->gpio_mmio_base; u16 len = msg->len; u8 *buf = msg->buf; I915_WRITE(GMBUS1 + reg_offset, + gmbus1_index | GMBUS_CYCLE_WAIT | (len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | @@ -276,6 +278,46 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) return 0; } +/* + * The gmbus controller can combine a 1 or 2 byte write with a read that + * immediately follows it by using an "INDEX" cycle. + */ +static bool +gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) +{ + return (i + 1 < num && + !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && + (msgs[i + 1].flags & I2C_M_RD)); +} + +static int +gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u32 gmbus1_index = 0; + u32 gmbus5 = 0; + int ret; + + if (msgs[0].len == 2) + gmbus5 = GMBUS_2BYTE_INDEX_EN | + msgs[0].buf[1] | (msgs[0].buf[0] << 8); + if (msgs[0].len == 1) + gmbus1_index = GMBUS_CYCLE_INDEX | + (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT); + + /* GMBUS5 holds 16-bit index */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, gmbus5); + + ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); + + /* Clear GMBUS5 after each index transfer */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, 0); + + return ret; +} + static int gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, @@ -300,10 +342,14 @@ gmbus_xfer(struct i2c_adapter *adapter, I915_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { - if (msgs[i].flags & I2C_M_RD) - ret = gmbus_xfer_read(dev_priv, &msgs[i]); - else + if (gmbus_is_index_read(msgs, i, num)) { + ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); + i += 1; /* set i to the index of the read xfer */ + } else if (msgs[i].flags & I2C_M_RD) { + ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); + } else { ret = gmbus_xfer_write(dev_priv, &msgs[i]); + } if (ret == -ETIMEDOUT) goto timeout; -- cgit v0.10.2 From 90e6b26d6b28ade684a4b16b856a74f27bc644bc Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:41 +0800 Subject: drm/i915/intel_i2c: reuse GMBUS2 value read in polling loop Save the GMBUS2 value read while polling for state changes, and then reuse this value when determining for which reason the loops were exited. This is a small optimization which saves a couple of bus accesses for memory mapped IO registers. To avoid "assigning in if clause" checkpatch errors", use a ret variable to store the wait_for macro return value. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 5e0912a..c56cc35 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -219,13 +219,16 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, GMBUS_SLAVE_READ | GMBUS_SW_RDY); POSTING_READ(GMBUS2 + reg_offset); do { + int ret; u32 val, loop = 0; + u32 gmbus2; - if (wait_for(I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY), - 50)) + ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_RDY), + 50); + if (ret) return -ETIMEDOUT; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (gmbus2 & GMBUS_SATOER) return -ENXIO; val = I915_READ(GMBUS3 + reg_offset); @@ -260,6 +263,9 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); POSTING_READ(GMBUS2 + reg_offset); while (len) { + int ret; + u32 gmbus2; + val = loop = 0; do { val |= *buf++ << (8 * loop); @@ -268,11 +274,12 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) I915_WRITE(GMBUS3 + reg_offset, val); POSTING_READ(GMBUS2 + reg_offset); - if (wait_for(I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY), - 50)) + ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_RDY), + 50); + if (ret) return -ETIMEDOUT; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (gmbus2 & GMBUS_SATOER) return -ENXIO; } return 0; @@ -342,6 +349,8 @@ gmbus_xfer(struct i2c_adapter *adapter, I915_WRITE(GMBUS0 + reg_offset, bus->reg0); for (i = 0; i < num; i++) { + u32 gmbus2; + if (gmbus_is_index_read(msgs, i, num)) { ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); i += 1; /* set i to the index of the read xfer */ @@ -356,11 +365,12 @@ gmbus_xfer(struct i2c_adapter *adapter, if (ret == -ENXIO) goto clear_err; - if (wait_for(I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), - 50)) + ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & + (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), + 50); + if (ret) goto timeout; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) + if (gmbus2 & GMBUS_SATOER) goto clear_err; } -- cgit v0.10.2 From e2ba4fb313d91c9e888f973e65a736f8f55b12b6 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 30 Mar 2012 19:46:42 +0800 Subject: drm/i915/intel_i2c: remove POSTING_READ() from gmbus transfers The POSTING_READ() calls were originally added to make sure the writes were flushed before any timing delays and across loops. Now that the code has settled a bit, let's remove them. Signed-off-by: Daniel Kurtz Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index c56cc35..cab879f 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -217,7 +217,6 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, (len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); - POSTING_READ(GMBUS2 + reg_offset); do { int ret; u32 val, loop = 0; @@ -261,7 +260,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) (msg->len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); - POSTING_READ(GMBUS2 + reg_offset); while (len) { int ret; u32 gmbus2; @@ -272,7 +270,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) } while (--len && ++loop < 4); I915_WRITE(GMBUS3 + reg_offset, val); - POSTING_READ(GMBUS2 + reg_offset); ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) & (GMBUS_SATOER | GMBUS_HW_RDY), -- cgit v0.10.2 From d1686ae3ab09a918efa7187cf7e2b2c748c905e1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Apr 2012 11:41:49 +0100 Subject: drm/i915: Ironlake shares the same video sprite controls as Sandybridge Well, almost. Just a couple of differences, Ironlake lacks a few of the RGB formats, only exposing x8r8g8b8, and lacks a couple of unused features. Given the similarities, we can then reuse the same routines as already written for Sandybridge to enable overlay support for Ironlake as well. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index a464771..da525b6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -209,7 +209,7 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) } static void -snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, +ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t x, uint32_t y, @@ -263,8 +263,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, if (obj->tiling_mode != I915_TILING_NONE) dvscntr |= DVS_TILED; - /* must disable */ - dvscntr |= DVS_TRICKLE_FEED_DISABLE; + if (IS_GEN6(dev)) + dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ dvscntr |= DVS_ENABLE; /* Sizes are 0 based */ @@ -296,7 +296,7 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, } static void -snb_disable_plane(struct drm_plane *plane) +ilk_disable_plane(struct drm_plane *plane) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -334,7 +334,7 @@ intel_disable_primary(struct drm_crtc *crtc) } static int -snb_update_colorkey(struct drm_plane *plane, +ilk_update_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { struct drm_device *dev = plane->dev; @@ -363,7 +363,7 @@ snb_update_colorkey(struct drm_plane *plane, } static void -snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) +ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -617,6 +617,14 @@ static const struct drm_plane_funcs intel_plane_funcs = { .destroy = intel_destroy_plane, }; +static uint32_t ilk_plane_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY, +}; + static uint32_t snb_plane_formats[] = { DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888, @@ -631,34 +639,56 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe) { struct intel_plane *intel_plane; unsigned long possible_crtcs; + const uint32_t *plane_formats; + int num_plane_formats; int ret; - if (!(IS_GEN6(dev) || IS_GEN7(dev))) + if (INTEL_INFO(dev)->gen < 5) return -ENODEV; intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL); if (!intel_plane) return -ENOMEM; - if (IS_GEN6(dev)) { + switch (INTEL_INFO(dev)->gen) { + case 5: + case 6: intel_plane->max_downscale = 16; - intel_plane->update_plane = snb_update_plane; - intel_plane->disable_plane = snb_disable_plane; - intel_plane->update_colorkey = snb_update_colorkey; - intel_plane->get_colorkey = snb_get_colorkey; - } else if (IS_GEN7(dev)) { + intel_plane->update_plane = ilk_update_plane; + intel_plane->disable_plane = ilk_disable_plane; + intel_plane->update_colorkey = ilk_update_colorkey; + intel_plane->get_colorkey = ilk_get_colorkey; + + if (IS_GEN6(dev)) { + plane_formats = snb_plane_formats; + num_plane_formats = ARRAY_SIZE(snb_plane_formats); + } else { + plane_formats = ilk_plane_formats; + num_plane_formats = ARRAY_SIZE(ilk_plane_formats); + } + break; + + case 7: intel_plane->max_downscale = 2; intel_plane->update_plane = ivb_update_plane; intel_plane->disable_plane = ivb_disable_plane; intel_plane->update_colorkey = ivb_update_colorkey; intel_plane->get_colorkey = ivb_get_colorkey; + + plane_formats = snb_plane_formats; + num_plane_formats = ARRAY_SIZE(snb_plane_formats); + break; + + default: + return -ENODEV; } intel_plane->pipe = pipe; possible_crtcs = (1 << pipe); ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs, - &intel_plane_funcs, snb_plane_formats, - ARRAY_SIZE(snb_plane_formats), false); + &intel_plane_funcs, + plane_formats, num_plane_formats, + false); if (ret) kfree(intel_plane); -- cgit v0.10.2 From 0136db586c028f71e7cc21cc183064ff0d5919c8 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Tue, 10 Apr 2012 21:17:01 -0700 Subject: drm/i915: rc6 in sysfs Merge rc6 information into the power group for our device. Until now the i915 driver has not had any sysfs entries (aside from the connector stuff enabled by drm core). Since it seems like we're likely to have more in the future I created a new file for sysfs stubs, as well as the rc6 sysfs functions which don't really belong elsewhere (perhaps i915_suspend, but most of the stuff is in intel_display,c). displays rc6 modes enabled (as a hex mask): cat /sys/class/drm/card0/power/rc6_enable displays #ms GPU has been in rc6 since boot: cat /sys/class/drm/card0/power/rc6_residency_ms displays #ms GPU has been in deep rc6 since boot: cat /sys/class/drm/card0/power/rc6p_residency_ms displays #ms GPU has been in deepest rc6 since boot: cat /sys/class/drm/card0/power/rc6pp_residency_ms Important note: I've seen on SNB that even when RC6 is *not* enabled the rc6 register seems to have a random value in it. I can only guess at the reason reason for this. Those writing tools that utilize this value need to be careful and probably want to scrutinize the value very carefully. v2: use common rc6 residency units to milliseconds for the other RC6 types v3: don't create sysfs files for GEN <= 5 add a rc6_enable to show a mask of enabled rc6 types use unmerge instead of remove for sysfs group squash intel_enable_rc6() extraction into this patch v4: rename sysfs files (Chris) CC: Chris Wilson CC: Daniel Vetter f CC: Arjan van de Ven Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson [danvet: squash in the 64bit division fix by Chris Wilson.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ce7fc77..f801330 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -12,6 +12,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_gem_execbuffer.o \ i915_gem_gtt.o \ i915_gem_tiling.o \ + i915_sysfs.o \ i915_trace_points.o \ intel_display.o \ intel_crt.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 652f43f..333b746 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2139,6 +2139,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } } + i915_setup_sysfs(dev); + /* Must be done after probing outputs */ intel_opregion_init(dev); acpi_video_register(); @@ -2190,6 +2192,8 @@ int i915_driver_unload(struct drm_device *dev) i915_mch_dev = NULL; spin_unlock(&mchdev_lock); + i915_teardown_sysfs(dev); + if (dev_priv->mm.inactive_shrinker.shrink) unregister_shrinker(&dev_priv->mm.inactive_shrinker); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7dcdccb..a189f75 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1385,6 +1385,10 @@ extern int i915_restore_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); +/* i915_sysfs.c */ +void i915_setup_sysfs(struct drm_device *dev_priv); +void i915_teardown_sysfs(struct drm_device *dev_priv); + /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); @@ -1441,6 +1445,7 @@ extern void ironlake_enable_rc6(struct drm_device *dev); extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); +extern int intel_enable_rc6(const struct drm_device *dev); extern bool i915_semaphore_is_enabled(struct drm_device *dev); extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c new file mode 100644 index 0000000..f1b5108 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Ben Widawsky + * + */ + +#include +#include +#include +#include +#include "i915_drv.h" + +static u32 calc_residency(struct drm_device *dev, const u32 reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u64 raw_time; /* 32b value may overflow during fixed point math */ + + if (!intel_enable_rc6(dev)) + return 0; + + raw_time = I915_READ(reg) * 128ULL + 500; + return do_div(raw_time, 100000); +} + +static ssize_t +show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev)); +} + +static ssize_t +show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); + return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); +} + +static ssize_t +show_rc6p_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); + return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); +} + +static ssize_t +show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); + return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); +} + +static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL); +static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL); +static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL); +static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL); + +static struct attribute *rc6_attrs[] = { + &dev_attr_rc6_enable.attr, + &dev_attr_rc6_residency_ms.attr, + &dev_attr_rc6p_residency_ms.attr, + &dev_attr_rc6pp_residency_ms.attr, + NULL +}; + +static struct attribute_group rc6_attr_group = { + .name = power_group_name, + .attrs = rc6_attrs +}; + +void i915_setup_sysfs(struct drm_device *dev) +{ + int ret; + + /* ILK doesn't have any residency information */ + if (INTEL_INFO(dev)->gen < 6) + return; + + ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group); + if (ret) + DRM_ERROR("sysfs setup failed\n"); +} + +void i915_teardown_sysfs(struct drm_device *dev) +{ + sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group); +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 42dbe14..5b8b3d1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8547,7 +8547,7 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -static int intel_enable_rc6(struct drm_device *dev) +int intel_enable_rc6(const struct drm_device *dev) { /* * Respect the kernel parameter if it is set -- cgit v0.10.2 From e3aef17286850a77f11a6dac28d972f65cde2235 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2012 11:58:03 -0700 Subject: drm/i915: make DP configuration vars less confusing in ironlake_crtc_mode_se Both PCH and CPU eDP are DP, so set the is_dp flag to true. Add is_cpu_edp and is_pch_edp bools to make checking for each less verbose (rather than has_edp_encoder && !intel_encoder_is_pch_edp() sprinkled everywhere). And rename the "has_edp_encoder" variable to just "edp_encoder". With the above variables cleaned up, the rest of the code becomes a bit more readable and clear. Signed-off-by: Jesse Barnes Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5b8b3d1..743ec6b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5963,9 +5963,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf; bool ok, has_reduced_clock = false, is_sdvo = false; bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false; - struct intel_encoder *has_edp_encoder = NULL; struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_encoder *encoder; + struct intel_encoder *encoder, *edp_encoder = NULL; const intel_limit_t *limit; int ret; struct fdi_m_n m_n = {0}; @@ -5974,6 +5973,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int target_clock, pixel_multiplier, lane, link_bw, factor; unsigned int pipe_bpp; bool dither; + bool is_cpu_edp = false, is_pch_edp = false; list_for_each_entry(encoder, &mode_config->encoder_list, base.head) { if (encoder->base.crtc != crtc) @@ -5999,7 +5999,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, is_dp = true; break; case INTEL_OUTPUT_EDP: - has_edp_encoder = encoder; + is_dp = true; + if (intel_encoder_is_pch_edp(&encoder->base)) + is_pch_edp = true; + else + is_cpu_edp = true; + edp_encoder = encoder; break; } @@ -6062,15 +6067,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, lane = 0; /* CPU eDP doesn't require FDI link, so just set DP M/N according to current link config */ - if (has_edp_encoder && - !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_cpu_edp) { target_clock = mode->clock; - intel_edp_link_config(has_edp_encoder, - &lane, &link_bw); + intel_edp_link_config(edp_encoder, &lane, &link_bw); } else { /* [e]DP over FDI requires target mode clock instead of link clock */ - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + if (is_dp) target_clock = mode->clock; else target_clock = adjusted_mode->clock; @@ -6161,7 +6164,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } dpll |= DPLL_DVO_HIGH_SPEED; } - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) + if (is_dp && !is_cpu_edp) dpll |= DPLL_DVO_HIGH_SPEED; /* compute bitmask from p1 value */ @@ -6206,8 +6209,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* PCH eDP needs FDI, but CPU eDP does not */ if (!intel_crtc->no_pll) { - if (!has_edp_encoder || - intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (!is_cpu_edp) { I915_WRITE(PCH_FP0(pipe), fp); I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE); @@ -6285,7 +6287,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, pipeconf |= PIPECONF_DITHER_EN; pipeconf |= PIPECONF_DITHER_TYPE_SP; } - if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_dp && !is_cpu_edp) { intel_dp_set_m_n(crtc, mode, adjusted_mode); } else { /* For non-DP output, clear any trans DP clock recovery setting.*/ @@ -6295,9 +6297,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(TRANSDPLINK_N1(pipe), 0); } - if (!intel_crtc->no_pll && - (!has_edp_encoder || - intel_encoder_is_pch_edp(&has_edp_encoder->base))) { + if (!intel_crtc->no_pll && (!edp_encoder || is_pch_edp)) { I915_WRITE(PCH_DPLL(pipe), dpll); /* Wait for the clocks to stabilize. */ @@ -6375,10 +6375,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m); I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n); - if (has_edp_encoder && - !intel_encoder_is_pch_edp(&has_edp_encoder->base)) { + if (is_cpu_edp) ironlake_set_pll_edp(crtc, adjusted_mode->clock); - } I915_WRITE(PIPECONF(pipe), pipeconf); POSTING_READ(PIPECONF(pipe)); -- cgit v0.10.2 From 211c568bc6a1ebd51e35724f6d733e76717ce368 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Apr 2012 17:29:17 +0200 Subject: drm/i915: simplify ppgtt setup We don't need the pt_addr for the !dmar case, so drop the else and move the if (dmar) condition out of the loop. v2: Fixup whitespace damage noticed by Chris Wilson. v3: Collapse the two identical if blocks. Chris Wilson makes me look like a moron right now ... Noticed-by: Konstantin Belousov Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 4fb875d..25c8bf9 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -96,11 +96,10 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) GFP_KERNEL); if (!ppgtt->pt_dma_addr) goto err_pt_alloc; - } - for (i = 0; i < ppgtt->num_pd_entries; i++) { - dma_addr_t pt_addr; - if (dev_priv->mm.gtt->needs_dmar) { + for (i = 0; i < ppgtt->num_pd_entries; i++) { + dma_addr_t pt_addr; + pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i], 0, 4096, PCI_DMA_BIDIRECTIONAL); @@ -112,8 +111,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) } ppgtt->pt_dma_addr[i] = pt_addr; - } else - pt_addr = page_to_phys(ppgtt->pt_pages[i]); + } } ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; -- cgit v0.10.2 From f84131905b9b3b02b1c5061c0720e503c8d22778 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Apr 2012 11:52:50 +0100 Subject: drm/i915: Allow concurrent read access between CPU and GPU domain Similar to allowing a buffer to be simultaneously read by the GPU and through the GTT, we wish to allow readback of the pages through the CPU domain whilst they are also being read by the GPU. Domain coherency is managed by allowing multiple readers, but only a single writer. This is used by mesa for its program cache which it may search for every new program every frame and then renews should it need to add. During renewal, mesa copies the program bo currently executing through a CPU mapping onto the new bo. This patch allows the search and that copy to proceed without causing a stall on the current batch. Testcase: i-g-t/tests/gem_cpu_concurrent_blit Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d75a657..1bfb0d2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3068,9 +3068,11 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) if (ret) return ret; - ret = i915_gem_object_wait_rendering(obj); - if (ret) - return ret; + if (write || obj->pending_gpu_write) { + ret = i915_gem_object_wait_rendering(obj); + if (ret) + return ret; + } i915_gem_object_flush_gtt_write_domain(obj); -- cgit v0.10.2 From f817586cebf1b946d1f327f9a596048efd6b64e9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 10 Apr 2012 15:50:11 +0200 Subject: drm/i915: re-init modeset hw state after gpu reset After a gpu reset we need to re-init some of the hw state we only initialize when modeset is enabled, like rc6, hw contexts or render/GT core clock gating and workaround register settings. Note that this patch has a small change in the resume code: - rc6 on gen6+ is only restored for the modeset case (for more consistency with other callsites). This is no problem because recent kernels refuse to load drm/i915 without kms on gen6+ - rc6/emon on ilk is only restored for the modeset case. This is no problem because rc6 is disabled by default on ilk, and ums on ilk has never really been a supported option outside of horrible rhel backports. v2: Chris Wilson noticed that we not only fail to restore the clock gating settings after gpu reset. v3: Move the call to modeset_init_hw in _reset out of the struct_mutext protected area - other callers don't hold it, too. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 96f8efc..ccfdc81 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -851,9 +851,14 @@ int i915_reset(struct drm_device *dev, u8 flags) i915_gem_init_ppgtt(dev); mutex_unlock(&dev->struct_mutex); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + intel_modeset_init_hw(dev); + drm_irq_uninstall(dev); drm_mode_config_reset(dev); drm_irq_install(dev); + mutex_lock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a189f75..422f424 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1433,6 +1433,7 @@ static inline void intel_unregister_dsm_handler(void) { return; } #endif /* CONFIG_ACPI */ /* modesetting */ +extern void intel_modeset_init_hw(struct drm_device *dev); extern void intel_modeset_init(struct drm_device *dev); extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 2b5eb22..0c3e3bf 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -879,17 +879,7 @@ int i915_restore_state(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); if (drm_core_check_feature(dev, DRIVER_MODESET)) - intel_init_clock_gating(dev); - - if (IS_IRONLAKE_M(dev)) { - ironlake_enable_drps(dev); - intel_init_emon(dev); - } - - if (INTEL_INFO(dev)->gen >= 6) { - gen6_enable_rps(dev_priv); - gen6_update_ring_freq(dev_priv); - } + intel_modeset_init_hw(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 743ec6b..aee389c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9530,6 +9530,23 @@ static void i915_disable_vga(struct drm_device *dev) POSTING_READ(vga_reg); } +void intel_modeset_init_hw(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_init_clock_gating(dev); + + if (IS_IRONLAKE_M(dev)) { + ironlake_enable_drps(dev); + intel_init_emon(dev); + } + + if (IS_GEN6(dev) || IS_GEN7(dev)) { + gen6_enable_rps(dev_priv); + gen6_update_ring_freq(dev_priv); + } +} + void intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -9575,17 +9592,7 @@ void intel_modeset_init(struct drm_device *dev) i915_disable_vga(dev); intel_setup_outputs(dev); - intel_init_clock_gating(dev); - - if (IS_IRONLAKE_M(dev)) { - ironlake_enable_drps(dev); - intel_init_emon(dev); - } - - if (IS_GEN6(dev) || IS_GEN7(dev)) { - gen6_enable_rps(dev_priv); - gen6_update_ring_freq(dev_priv); - } + intel_modeset_init_hw(dev); INIT_WORK(&dev_priv->idle_work, intel_idle_update); setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer, -- cgit v0.10.2 From bfa3384a9a84aaaa59443bbd776c142e7dba4b0f Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 10 Apr 2012 11:58:04 -0700 Subject: drm/i915: check PPS regs for sanity when using eDP If these regs don't have valid values, the panel won't come up, and may even cause a system hang. So do a basic sanity check when an eDP panel is detected. Signed-off-by: Jesse Barnes Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44305 Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 110552f..6346b29 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -2462,6 +2462,13 @@ intel_dp_init(struct drm_device *dev, int output_reg) pp_off = I915_READ(PCH_PP_OFF_DELAYS); pp_div = I915_READ(PCH_PP_DIVISOR); + if (!pp_on || !pp_off || !pp_div) { + DRM_INFO("bad panel power sequencing delays, disabling panel\n"); + intel_dp_encoder_destroy(&intel_dp->base.base); + intel_dp_destroy(&intel_connector->base); + return; + } + /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> PANEL_POWER_UP_DELAY_SHIFT; -- cgit v0.10.2 From b6834bd63ec407444098be233122a25bf4f17c75 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2012 09:23:33 -0700 Subject: drm/i915: disable turbo on ValleyView for now We'll probably need new init functions and will need to test it. v2: fix impossible GEN6 && GEN7 condition, move to Daniel's new init function Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aee389c..58f4b02 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9541,7 +9541,7 @@ void intel_modeset_init_hw(struct drm_device *dev) intel_init_emon(dev); } - if (IS_GEN6(dev) || IS_GEN7(dev)) { + if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) { gen6_enable_rps(dev_priv); gen6_update_ring_freq(dev_priv); } @@ -9632,7 +9632,7 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); - if (IS_GEN6(dev) || IS_GEN7(dev)) + if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) gen6_disable_rps(dev); if (IS_IRONLAKE_M(dev)) -- cgit v0.10.2 From f82cfb6bcda164ef3a66b8c3fc549b1f9bdd09ad Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 11 Apr 2012 09:23:35 -0700 Subject: drm/i915: allow PCH PWM override on IVB On IVB, there are two sets of panel backlight regs: one in the CPU and one in the PCH. The CPU ones aren't generally used, so on IVB make sure we allow the PCH regs to actually control the backlight. v2: remove unused pwm variable (Daniel) move to init_hw function so we override on resume too Signed-off-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58f4b02..33aaad3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9530,6 +9530,19 @@ static void i915_disable_vga(struct drm_device *dev) POSTING_READ(vga_reg); } +static void ivb_pch_pwm_override(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * IVB has CPU eDP backlight regs too, set things up to let the + * PCH regs control the backlight + */ + I915_WRITE(BLC_PWM_CPU_CTL2, PWM_ENABLE); + I915_WRITE(BLC_PWM_CPU_CTL, 0); + I915_WRITE(BLC_PWM_PCH_CTL1, PWM_ENABLE | (1<<30)); +} + void intel_modeset_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -9545,6 +9558,9 @@ void intel_modeset_init_hw(struct drm_device *dev) gen6_enable_rps(dev_priv); gen6_update_ring_freq(dev_priv); } + + if (IS_IVYBRIDGE(dev)) + ivb_pch_pwm_override(dev); } void intel_modeset_init(struct drm_device *dev) -- cgit v0.10.2 From 5816d648d5f0d496d7bf11ab9174a365c791ccc6 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 11 Apr 2012 11:18:19 -0700 Subject: drm/i915: i915_gem_object_sync must handle NULL When I extracted the synchronization code for implementing semaphorified pageflips (74f5f6e0), I neglected the non pipelined case which also calls this code. The modesetting code wants to make sure the object has finished rendering to the frame before configuring the scanout (ie. non-pipelined case). As a result of a follow on discussion on IRC, I've decided to add a comment about the function itself which received much inspiration from Chris as well. So really, this patch was ghost-written by Chris :). Reported-by: Chris Wilson Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Tested-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1bfb0d2..9fcdc9a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1953,6 +1953,18 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj) return 0; } +/** + * i915_gem_object_sync - sync an object to a ring. + * + * @obj: object which may be in use on another ring. + * @to: ring we wish to use the object on. May be NULL. + * + * This code is meant to abstract object synchronization with the GPU. + * Calling with NULL implies synchronizing the object with the CPU + * rather than a particular GPU ring. + * + * Returns 0 if successful, else propagates up the lower layer error. + */ int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to) @@ -1964,7 +1976,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, if (from == NULL || to == from) return 0; - if (!i915_semaphore_is_enabled(obj->base.dev)) + if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev)) return i915_gem_object_wait_rendering(obj); idx = intel_ring_sync_index(from, to); -- cgit v0.10.2 From e3a5a2250aa9e67d169f33e6c91dc7604cab513b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 11 Apr 2012 11:18:20 -0700 Subject: drm/i915: fix for when semaphore updates fail This fixes a long standing issue where emitting the semaphore updates may have failed, but we've already updated our internal data structure. Reported-by: Daniel Vetter Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9fcdc9a..0115b12 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2001,10 +2001,12 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, seqno = request->seqno; } - from->sync_seqno[idx] = seqno; - return to->sync_to(to, from, seqno - 1); + ret = to->sync_to(to, from, seqno - 1); + if (!ret) + from->sync_seqno[idx] = seqno; + return ret; } static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) -- cgit v0.10.2 From 1500f7ea06858819abcf8eec8f952e2f9281c610 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Wed, 11 Apr 2012 11:18:21 -0700 Subject: drm/i915: hide (seqno-1) in ringbuffer code Waiting for seqno-1 in our object synchronization code is an implementation detail given how we've decided to do the waits within the rest of our code. Requested-by: Daniel Vetter Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0115b12..71934dd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2002,7 +2002,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, } - ret = to->sync_to(to, from, seqno - 1); + ret = to->sync_to(to, from, seqno); if (!ret) from->sync_seqno[idx] = seqno; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index dfdb613..467b331 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -482,6 +482,12 @@ intel_ring_sync(struct intel_ring_buffer *waiter, MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER; + /* Throughout all of the GEM code, seqno passed implies our current + * seqno is >= the last seqno executed. However for hardware the + * comparison is strictly greater than. + */ + seqno -= 1; + ret = intel_ring_begin(waiter, 4); if (ret) return ret; -- cgit v0.10.2 From d95603b262edb53d6016a8df0c150371d4d61e67 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Thu, 12 Apr 2012 15:55:15 -0400 Subject: Btrfs: fix uninit variable in repair_eb_io_failure We'd have to be passing bogus extent buffers for this uninit variable to actually be used, but set it to zero just in case. Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 0c3ec00..59ec105 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1937,7 +1937,7 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb, struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; u64 start = eb->start; unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); - int ret; + int ret = 0; for (i = 0; i < num_pages; i++) { struct page *p = extent_buffer_page(eb, i); -- cgit v0.10.2 From b89203f74bdfcb15407d54d3f257b16a2ea19e62 Mon Sep 17 00:00:00 2001 From: Liu Bo Date: Thu, 12 Apr 2012 16:03:56 -0400 Subject: Btrfs: fix eof while discarding extents We miscalculate the length of extents we're discarding, and it leads to an eof of device. Reported-by: Daniel Blueman Signed-off-by: Liu Bo Signed-off-by: Chris Mason diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a872b48..759d024 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3833,6 +3833,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, int sub_stripes = 0; u64 stripes_per_dev = 0; u32 remaining_stripes = 0; + u32 last_stripe = 0; if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { @@ -3846,6 +3847,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, stripe_nr_orig, factor, &remaining_stripes); + div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); + last_stripe *= sub_stripes; } for (i = 0; i < num_stripes; i++) { @@ -3858,16 +3861,29 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, BTRFS_BLOCK_GROUP_RAID10)) { bbio->stripes[i].length = stripes_per_dev * map->stripe_len; + if (i / sub_stripes < remaining_stripes) bbio->stripes[i].length += map->stripe_len; + + /* + * Special for the first stripe and + * the last stripe: + * + * |-------|...|-------| + * |----------| + * off end_off + */ if (i < sub_stripes) bbio->stripes[i].length -= stripe_offset; - if ((i / sub_stripes + 1) % - sub_stripes == remaining_stripes) + + if (stripe_index >= last_stripe && + stripe_index <= (last_stripe + + sub_stripes - 1)) bbio->stripes[i].length -= stripe_end_offset; + if (i == sub_stripes - 1) stripe_offset = 0; } else -- cgit v0.10.2 From c6664b42c4e567792abdb17c958fb01c5bcfcb3a Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Thu, 12 Apr 2012 16:03:56 -0400 Subject: Btrfs: remove lock assert from get_restripe_target() This fixes a regression introduced by fc67c450. spin_is_locked() always returns 0 on UP kernels, which caused assert in get_restripe_target() to be fired on every call from btrfs_reduce_alloc_profile() on UP systems. Remove it completely for now, it's not clear if it's going to be needed in future. Reported-by: Bobby Powers Reported-by: Mitch Harder Tested-by: Mitch Harder Signed-off-by: Ilya Dryomov Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index ace5e8c..a2134d8 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -3152,15 +3152,14 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) /* * returns target flags in extended format or 0 if restripe for this * chunk_type is not in progress + * + * should be called with either volume_mutex or balance_lock held */ static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags) { struct btrfs_balance_control *bctl = fs_info->balance_ctl; u64 target = 0; - BUG_ON(!mutex_is_locked(&fs_info->volume_mutex) && - !spin_is_locked(&fs_info->balance_lock)); - if (!bctl) return 0; -- cgit v0.10.2 From e627ee7bcd42b4e3a03ca01a8e46dcb4033c5ae0 Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Thu, 12 Apr 2012 16:03:56 -0400 Subject: Btrfs: check return value of bio_alloc() properly bio_alloc() has the possibility of returning NULL. So, it is necessary to check the return value. Signed-off-by: Tsutomu Itoh Signed-off-by: Chris Mason diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d11afa67..646f5e6 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -405,6 +405,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, bio_put(bio); bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); + BUG_ON(!bio); bio->bi_private = cb; bio->bi_end_io = end_compressed_bio_write; bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); @@ -687,6 +688,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, GFP_NOFS); + BUG_ON(!comp_bio); comp_bio->bi_private = cb; comp_bio->bi_end_io = end_compressed_bio_read; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 59ec105..4789770 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2180,6 +2180,10 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page, } bio = bio_alloc(GFP_NOFS, 1); + if (!bio) { + free_io_failure(inode, failrec, 0); + return -EIO; + } bio->bi_private = state; bio->bi_end_io = failed_bio->bi_end_io; bio->bi_sector = failrec->logical >> 9; diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index c9a2c1a..60f0e28 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1044,6 +1044,8 @@ static int scrub_recheck_block(struct btrfs_fs_info *fs_info, BUG_ON(!page->page); bio = bio_alloc(GFP_NOFS, 1); + if (!bio) + return -EIO; bio->bi_bdev = page->bdev; bio->bi_sector = page->physical >> 9; bio->bi_end_io = scrub_complete_bio_end_io; @@ -1172,6 +1174,8 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, DECLARE_COMPLETION_ONSTACK(complete); bio = bio_alloc(GFP_NOFS, 1); + if (!bio) + return -EIO; bio->bi_bdev = page_bad->bdev; bio->bi_sector = page_bad->physical >> 9; bio->bi_end_io = scrub_complete_bio_end_io; -- cgit v0.10.2 From 4edc2ca388d62abffe38149f6ac00e749ea721c5 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 12 Apr 2012 16:03:56 -0400 Subject: Btrfs: fix use-after-free in __btrfs_end_transaction 49b25e0540904be0bf558b84475c69d72e4de66e introduced a use-after-free bug that caused spurious -EIO's to be returned. Do the check before we free the transaction. Cc: David Sterba Cc: Jeff Mahoney Signed-off-by: Dave Jones Signed-off-by: Chris Mason diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 8da29e8..11b77a5 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c @@ -480,6 +480,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, struct btrfs_transaction *cur_trans = trans->transaction; struct btrfs_fs_info *info = root->fs_info; int count = 0; + int err = 0; if (--trans->use_count) { trans->block_rsv = trans->orig_rsv; @@ -532,18 +533,18 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, if (current->journal_info == trans) current->journal_info = NULL; - memset(trans, 0, sizeof(*trans)); - kmem_cache_free(btrfs_trans_handle_cachep, trans); if (throttle) btrfs_run_delayed_iputs(root); if (trans->aborted || root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - return -EIO; + err = -EIO; } - return 0; + memset(trans, 0, sizeof(*trans)); + kmem_cache_free(btrfs_trans_handle_cachep, trans); + return err; } int btrfs_end_transaction(struct btrfs_trans_handle *trans, -- cgit v0.10.2 From 6252efcc3626bdcde1c1c2d8a83be0bc66b8cc2c Mon Sep 17 00:00:00 2001 From: Ying Han Date: Thu, 12 Apr 2012 12:49:10 -0700 Subject: memcg: fix up documentation on global LRU In v3.3-rc1, the global LRU was removed in commit 925b7673cce3 ("mm: make per-memcg LRU lists exclusive"). The patch fixes up the memcg docs. I left the swap session to someone who has better understanding of 'memory+swap'. Signed-off-by: Ying Han Acked-by: Michal Hocko Acked-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt index 4c95c00..9b1067a 100644 --- a/Documentation/cgroups/memory.txt +++ b/Documentation/cgroups/memory.txt @@ -34,8 +34,7 @@ Current Status: linux-2.6.34-mmotm(development version of 2010/April) Features: - accounting anonymous pages, file caches, swap caches usage and limiting them. - - private LRU and reclaim routine. (system's global LRU and private LRU - work independently from each other) + - pages are linked to per-memcg LRU exclusively, and there is no global LRU. - optionally, memory+swap usage can be accounted and limited. - hierarchical accounting - soft limit @@ -154,7 +153,7 @@ updated. page_cgroup has its own LRU on cgroup. 2.2.1 Accounting details All mapped anon pages (RSS) and cache pages (Page Cache) are accounted. -Some pages which are never reclaimable and will not be on the global LRU +Some pages which are never reclaimable and will not be on the LRU are not accounted. We just account pages under usual VM management. RSS pages are accounted at page_fault unless they've already been accounted -- cgit v0.10.2 From d833049bd20570cbbadeb5228c579f9f3aaa4e03 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 12 Apr 2012 12:49:11 -0700 Subject: memcg: fix broken boolen expression action != CPU_DEAD || action != CPU_DEAD_FROZEN is always true. Signed-off-by: Kirill A. Shutemov Acked-by: KAMEZAWA Hiroyuki Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7d698df..ea1e879 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2165,7 +2165,7 @@ static int __cpuinit memcg_cpu_hotplug_callback(struct notifier_block *nb, if (action == CPU_ONLINE) return NOTIFY_OK; - if ((action != CPU_DEAD) || action != CPU_DEAD_FROZEN) + if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) return NOTIFY_OK; for_each_mem_cgroup(iter) -- cgit v0.10.2 From 44e4360fa3384850d65dd36fb4e6e5f2f112709b Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 12 Apr 2012 12:49:12 -0700 Subject: drivers/char/random.c: fix boot id uniqueness race /proc/sys/kernel/random/boot_id can be read concurrently by userspace processes. If two (or more) user-space processes concurrently read boot_id when sysctl_bootid is not yet assigned, a race can occur making boot_id differ between the reads. Because the whole point of the boot id is to be unique across a kernel execution, fix this by protecting this operation with a spinlock. Given that this operation is not frequently used, hitting the spinlock on each call should not be an issue. Signed-off-by: Mathieu Desnoyers Cc: "Theodore Ts'o" Cc: Matt Mackall Signed-off-by: Eric Dumazet Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/char/random.c b/drivers/char/random.c index 54ca8b2..4ec04a7 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1260,10 +1260,15 @@ static int proc_do_uuid(ctl_table *table, int write, uuid = table->data; if (!uuid) { uuid = tmp_uuid; - uuid[8] = 0; - } - if (uuid[8] == 0) generate_random_uuid(uuid); + } else { + static DEFINE_SPINLOCK(bootid_spinlock); + + spin_lock(&bootid_spinlock); + if (!uuid[8]) + generate_random_uuid(uuid); + spin_unlock(&bootid_spinlock); + } sprintf(buf, "%pU", uuid); -- cgit v0.10.2 From bb58da08f01ee12561867fcd4385b82679ae7f6c Mon Sep 17 00:00:00 2001 From: Andreas Dumberger Date: Thu, 12 Apr 2012 12:49:12 -0700 Subject: drivers/rtc/rtc-r9701.c: reset registers if invalid values are detected hwclock refuses to set date/time if RTC registers contain invalid values. Check the date/time register values at probe time and initialize them to make hwclock happy. Signed-off-by: Andreas Dumberger Signed-off-by: Anatolij Gustschin Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 7f8e6c2..33b6ba0 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -122,6 +122,7 @@ static const struct rtc_class_ops r9701_rtc_ops = { static int __devinit r9701_probe(struct spi_device *spi) { struct rtc_device *rtc; + struct rtc_time dt; unsigned char tmp; int res; @@ -132,6 +133,27 @@ static int __devinit r9701_probe(struct spi_device *spi) return -ENODEV; } + /* + * The device seems to be present. Now check if the registers + * contain invalid values. If so, try to write a default date: + * 2000/1/1 00:00:00 + */ + r9701_get_datetime(&spi->dev, &dt); + if (rtc_valid_tm(&dt)) { + dev_info(&spi->dev, "trying to repair invalid date/time\n"); + dt.tm_sec = 0; + dt.tm_min = 0; + dt.tm_hour = 0; + dt.tm_mday = 1; + dt.tm_mon = 0; + dt.tm_year = 100; + + if (r9701_set_datetime(&spi->dev, &dt)) { + dev_err(&spi->dev, "cannot repair RTC register\n"); + return -ENODEV; + } + } + rtc = rtc_device_register("r9701", &spi->dev, &r9701_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) -- cgit v0.10.2 From 32050017cf3bf2b983571a90351328b4f66e463d Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 12 Apr 2012 12:49:12 -0700 Subject: drivers/rtc/rtc-efi.c: fix section mismatch warning efi_rtc_init() uses platform_driver_probe(), so there's no need to also set efi_rtc_driver's probe member (as it won't be used anyway). This fixes a modpost section mismatch warning (as efi_rtc_probe() validly is __init). Signed-off-by: Jan Beulich Cc: Matthew Garrett Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 5502923..c9f890b 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -213,7 +213,6 @@ static struct platform_driver efi_rtc_driver = { .name = "rtc-efi", .owner = THIS_MODULE, }, - .probe = efi_rtc_probe, .remove = __exit_p(efi_rtc_remove), }; -- cgit v0.10.2 From 569530fb1b40ab2d2ca147ee79898ac807ebdf90 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Thu, 12 Apr 2012 12:49:13 -0700 Subject: memcg: do not open code accesses to res_counter members We should use the accessor res_counter_read_u64 for that. Although a purely cosmetic change is sometimes better delayed, to avoid conflicting with other people's work, we are starting to have people touching this code as well, and reproducing the open code behavior because that's the standard =) Time to fix it, then. Signed-off-by: Glauber Costa Cc: Johannes Weiner Acked-by: Michal Hocko Cc: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/memcontrol.c b/mm/memcontrol.c index ea1e879..a7165a6 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3763,7 +3763,7 @@ move_account: goto try_to_free; cond_resched(); /* "ret" should also be checked to ensure all lists are empty. */ - } while (memcg->res.usage > 0 || ret); + } while (res_counter_read_u64(&memcg->res, RES_USAGE) > 0 || ret); out: css_put(&memcg->css); return ret; @@ -3778,7 +3778,7 @@ try_to_free: lru_add_drain_all(); /* try to free all pages in this cgroup */ shrink = 1; - while (nr_retries && memcg->res.usage > 0) { + while (nr_retries && res_counter_read_u64(&memcg->res, RES_USAGE) > 0) { int progress; if (signal_pending(current)) { -- cgit v0.10.2 From 3971dae51d7cccf4c8197786b050b3a65ace01f0 Mon Sep 17 00:00:00 2001 From: Khalid Aziz Date: Thu, 12 Apr 2012 12:49:13 -0700 Subject: MAINTAINERS: add PCDP console maintainer Add missing maintainer info for PCDP console code. Signed-off-by: Khalid Aziz Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/MAINTAINERS b/MAINTAINERS index a127097..a068fe4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5118,6 +5118,11 @@ F: drivers/i2c/busses/i2c-pca-* F: include/linux/i2c-algo-pca.h F: include/linux/i2c-pca-platform.h +PCDP - PRIMARY CONSOLE AND DEBUG PORT +M: Khalid Aziz +S: Maintained +F: drivers/firmware/pcdp.* + PCI ERROR RECOVERY M: Linas Vepstas L: linux-pci@vger.kernel.org -- cgit v0.10.2 From cd1e6f9e53e1a673a489826729709aaffa8ad621 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 12 Apr 2012 12:49:14 -0700 Subject: drivers/rtc/rtc-s3c.c: fix compilation error Fix this error: drivers/rtc/rtc-s3c.c: At top level: drivers/rtc/rtc-s3c.c:671:3: error: request for member `data' in something not a structure or union drivers/rtc/rtc-s3c.c:674:3: error: request for member `data' in something not a structure or union drivers/rtc/rtc-s3c.c:677:3: error: request for member `data' in something not a structure or union drivers/rtc/rtc-s3c.c:680:3: error: request for member `data' in something not a structure or union Signed-off-by: Tushar Behera Cc: Heiko Stuebner Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 9ccea13..2087953 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -667,16 +667,16 @@ static int s3c_rtc_resume(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id s3c_rtc_dt_match[] = { { - .compatible = "samsung,s3c2410-rtc" + .compatible = "samsung,s3c2410-rtc", .data = TYPE_S3C2410, }, { - .compatible = "samsung,s3c2416-rtc" + .compatible = "samsung,s3c2416-rtc", .data = TYPE_S3C2416, }, { - .compatible = "samsung,s3c2443-rtc" + .compatible = "samsung,s3c2443-rtc", .data = TYPE_S3C2443, }, { - .compatible = "samsung,s3c6410-rtc" + .compatible = "samsung,s3c6410-rtc", .data = TYPE_S3C64XX, }, {}, -- cgit v0.10.2 From c3cba9281ba39f3aef377fe52890e2d8f1e6dae3 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Thu, 12 Apr 2012 12:49:14 -0700 Subject: drivers/rtc/rtc-s3c.c: add placeholder for driver private data Driver data field is a pointer, hence assigning that to an integer results in compilation warnings. Fixes following compilation warnings: drivers/rtc/rtc-s3c.c: In function `s3c_rtc_get_driver_data': drivers/rtc/rtc-s3c.c:452:3: warning: return makes integer from pointer without a cast [enabled by default] drivers/rtc/rtc-s3c.c: At top level: drivers/rtc/rtc-s3c.c:674:3: warning: initialization makes pointer from integer without a cast [enabled by default] drivers/rtc/rtc-s3c.c:674:3: warning: (near initialization for `s3c_rtc_dt_match[1].data') [enabled by default] drivers/rtc/rtc-s3c.c:677:3: warning: initialization makes pointer from integer without a cast [enabled by default] drivers/rtc/rtc-s3c.c:677:3: warning: (near initialization for `s3c_rtc_dt_match[2].data') [enabled by default] drivers/rtc/rtc-s3c.c:680:3: warning: initialization makes pointer from integer without a cast [enabled by default] drivers/rtc/rtc-s3c.c:680:3: warning: (near initialization for `s3c_rtc_dt_match[3].data') [enabled by default] Signed-off-by: Tushar Behera Cc: Heiko Stuebner Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2087953..3f3a297 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -40,6 +40,10 @@ enum s3c_cpu_type { TYPE_S3C64XX, }; +struct s3c_rtc_drv_data { + int cpu_type; +}; + /* I have yet to find an S3C implementation with more than one * of these rtc blocks in */ @@ -446,10 +450,12 @@ static const struct of_device_id s3c_rtc_dt_match[]; static inline int s3c_rtc_get_driver_data(struct platform_device *pdev) { #ifdef CONFIG_OF + struct s3c_rtc_drv_data *data; if (pdev->dev.of_node) { const struct of_device_id *match; match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); - return match->data; + data = (struct s3c_rtc_drv_data *) match->data; + return data->cpu_type; } #endif return platform_get_device_id(pdev)->driver_data; @@ -664,20 +670,27 @@ static int s3c_rtc_resume(struct platform_device *pdev) #define s3c_rtc_resume NULL #endif +static struct s3c_rtc_drv_data s3c_rtc_drv_data_array[] = { + [TYPE_S3C2410] = { TYPE_S3C2410 }, + [TYPE_S3C2416] = { TYPE_S3C2416 }, + [TYPE_S3C2443] = { TYPE_S3C2443 }, + [TYPE_S3C64XX] = { TYPE_S3C64XX }, +}; + #ifdef CONFIG_OF static const struct of_device_id s3c_rtc_dt_match[] = { { .compatible = "samsung,s3c2410-rtc", - .data = TYPE_S3C2410, + .data = &s3c_rtc_drv_data_array[TYPE_S3C2410], }, { .compatible = "samsung,s3c2416-rtc", - .data = TYPE_S3C2416, + .data = &s3c_rtc_drv_data_array[TYPE_S3C2416], }, { .compatible = "samsung,s3c2443-rtc", - .data = TYPE_S3C2443, + .data = &s3c_rtc_drv_data_array[TYPE_S3C2443], }, { .compatible = "samsung,s3c6410-rtc", - .data = TYPE_S3C64XX, + .data = &s3c_rtc_drv_data_array[TYPE_S3C64XX], }, {}, }; -- cgit v0.10.2 From f3ec434c69ac7f447ff6e6389c19727c9f002087 Mon Sep 17 00:00:00 2001 From: Konstantin Shlyakhovoy Date: Thu, 12 Apr 2012 12:49:15 -0700 Subject: drivers/rtc/rtc-twl.c: use static register while reading time RTC stores time and date in several registers. Due to the fact that these registers can't be read instantaneously, there is a chance that reading from counting registers gives an error of one minute, one hour, one day, etc. To address this issue, the RTC has hardware support to copy the RTC counting registers to static shadowed registers. The current implementation does not use this feature, and in a stress test, we can reproduce this error at a rate of around two times per 300000 readings. Fix the implementation to ensure that the right snapshot of time is captured. Signed-off-by: Konstantin Shlyakhovoy Signed-off-by: Nishanth Menon Cc: Alessandro Zummo Cc: Benoit Cousson Cc: linux-omap Acked-by: Mykola Oleksiienko Acked-by: Oleksandr Dmytryshyn Acked-by: Graeme Gregory Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 4c2c6df..258abea 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -112,6 +112,7 @@ static const u8 twl6030_rtc_reg_map[] = { #define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 #define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 +#define BIT_RTC_CTRL_REG_RTC_V_OPT 0x80 /* RTC_STATUS_REG bitfields */ #define BIT_RTC_STATUS_REG_RUN_M 0x02 @@ -235,25 +236,57 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned char rtc_data[ALL_TIME_REGS + 1]; int ret; u8 save_control; + u8 rtc_control; ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); - if (ret < 0) + if (ret < 0) { + dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret); return ret; + } + /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ + if (twl_class_is_6030()) { + if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { + save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; + ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s clr GET_TIME, error %d\n", + __func__, ret); + return ret; + } + } + } - save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; + /* Copy RTC counting registers to static registers or latches */ + rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); - if (ret < 0) + /* for twl6030/32 enable read access to static shadowed registers */ + if (twl_class_is_6030()) + rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; + + ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret); return ret; + } ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "%s: reading data, error %d\n", __func__, ret); return ret; } + /* for twl6030 restore original state of rtc control register */ + if (twl_class_is_6030()) { + ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + if (ret < 0) { + dev_err(dev, "%s: restore CTRL_REG, error %d\n", + __func__, ret); + return ret; + } + } + tm->tm_sec = bcd2bin(rtc_data[0]); tm->tm_min = bcd2bin(rtc_data[1]); tm->tm_hour = bcd2bin(rtc_data[2]); -- cgit v0.10.2 From 66aebce747eaf9bc456bf1f1b217d8db843031d0 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 12 Apr 2012 12:49:15 -0700 Subject: hugetlb: fix race condition in hugetlb_fault() The race is as follows: Suppose a multi-threaded task forks a new process (on cpu A), thus bumping up the ref count on all the pages. While the fork is occurring (and thus we have marked all the PTEs as read-only), another thread in the original process (on cpu B) tries to write to a huge page, taking an access violation from the write-protect and calling hugetlb_cow(). Now, suppose the fork() fails. It will undo the COW and decrement the ref count on the pages, so the ref count on the huge page drops back to 1. Meanwhile hugetlb_cow() also decrements the ref count by one on the original page, since the original address space doesn't need it any more, having copied a new page to replace the original page. This leaves the ref count at zero, and when we call unlock_page(), we panic. fork on CPU A fault on CPU B ============= ============== ... down_write(&parent->mmap_sem); down_write_nested(&child->mmap_sem); ... while duplicating vmas if error break; ... up_write(&child->mmap_sem); up_write(&parent->mmap_sem); ... down_read(&parent->mmap_sem); ... lock_page(page); handle COW page_mapcount(old_page) == 2 alloc and prepare new_page ... handle error page_remove_rmap(page); put_page(page); ... fold new_page into pte page_remove_rmap(page); put_page(page); ... oops ==> unlock_page(page); up_read(&parent->mmap_sem); The solution is to take an extra reference to the page while we are holding the lock on it. Signed-off-by: Chris Metcalf Cc: Hillf Danton Cc: Michal Hocko Cc: KAMEZAWA Hiroyuki Cc: Hugh Dickins Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/hugetlb.c b/mm/hugetlb.c index b8ce6f4..cd65cb1 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2791,6 +2791,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, * so no worry about deadlock. */ page = pte_page(entry); + get_page(page); if (page != pagecache_page) lock_page(page); @@ -2822,6 +2823,7 @@ out_page_table_lock: } if (page != pagecache_page) unlock_page(page); + put_page(page); out_mutex: mutex_unlock(&hugetlb_instantiation_mutex); -- cgit v0.10.2 From 41c93088127df2579e8ca64010929ec9e41d5543 Mon Sep 17 00:00:00 2001 From: Ying Han Date: Thu, 12 Apr 2012 12:49:16 -0700 Subject: Revert "mm: vmscan: fix misused nr_reclaimed in shrink_mem_cgroup_zone()" This reverts commit c38446cc65e1f2b3eb8630c53943b94c4f65f670. Before the commit, the code makes senses to me but not after the commit. The "nr_reclaimed" is the number of pages reclaimed by scanning through the memcg's lru lists. The "nr_to_reclaim" is the target value for the whole function. For example, we like to early break the reclaim if reclaimed 32 pages under direct reclaim (not DEF_PRIORITY). After the reverted commit, the target "nr_to_reclaim" is decremented each time by "nr_reclaimed" but we still use it to compare the "nr_reclaimed". It just doesn't make sense to me... Signed-off-by: Ying Han Acked-by: Hugh Dickins Cc: Rik van Riel Cc: Hillf Danton Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/mm/vmscan.c b/mm/vmscan.c index 33c332b..1a51868 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2107,12 +2107,7 @@ restart: * with multiple processes reclaiming pages, the total * freeing target can get unreasonably large. */ - if (nr_reclaimed >= nr_to_reclaim) - nr_to_reclaim = 0; - else - nr_to_reclaim -= nr_reclaimed; - - if (!nr_to_reclaim && priority < DEF_PRIORITY) + if (nr_reclaimed >= nr_to_reclaim && priority < DEF_PRIORITY) break; } blk_finish_plug(&plug); -- cgit v0.10.2 From 2f3972168353d355854d6381f1f360ce83b723e5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 12 Apr 2012 12:49:16 -0700 Subject: drivers/rtc/rtc-pl031.c: enable clock on all ST variants The ST variants of the PL031 all require bit 26 in the control register to be set before they work properly. Discovered this when testing on the Nomadik board where it would suprisingly just stand still. Signed-off-by: Linus Walleij Cc: Mian Yousaf Kaukab Cc: Alessandro Rubini Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 692de73..684ef4b 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -339,8 +339,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision); /* Enable the clockwatch on ST Variants */ - if ((ldata->hw_designer == AMBA_VENDOR_ST) && - (ldata->hw_revision > 1)) + if (ldata->hw_designer == AMBA_VENDOR_ST) writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN, ldata->base + RTC_CR); -- cgit v0.10.2 From 026ee1f66aaa7f01b617a0ba89ac4b531f9603f1 Mon Sep 17 00:00:00 2001 From: Jason Wessel Date: Thu, 12 Apr 2012 12:49:17 -0700 Subject: panic: fix stack dump print on direct call to panic() Commit 6e6f0a1f0fa6 ("panic: don't print redundant backtraces on oops") causes a regression where no stack trace will be printed at all for the case where kernel code calls panic() directly while not processing an oops, and of course there are 100's of instances of this type of call. The original commit executed the check (!oops_in_progress), but this will always be false because just before the dump_stack() there is a call to bust_spinlocks(1), which does the following: void __attribute__((weak)) bust_spinlocks(int yes) { if (yes) { ++oops_in_progress; The proper way to resolve the problem that original commit tried to solve is to avoid printing a stack dump from panic() when the either of the following conditions is true: 1) TAINT_DIE has been set (this is done by oops_end()) This indicates and oops has already been printed. 2) oops_in_progress > 1 This guards against the rare case where panic() is invoked a second time, or in between oops_begin() and oops_end() Signed-off-by: Jason Wessel Cc: Andi Kleen Cc: [3.3+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds diff --git a/kernel/panic.c b/kernel/panic.c index 80aed44..8ed89a1 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -97,7 +97,7 @@ void panic(const char *fmt, ...) /* * Avoid nested stack-dumping if a panic occurs during oops processing */ - if (!oops_in_progress) + if (!test_taint(TAINT_DIE) && oops_in_progress <= 1) dump_stack(); #endif -- cgit v0.10.2 From 62d2feb9803f18c4e3c8a1a2c7e30a54df8a1d72 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Thu, 12 Apr 2012 21:48:03 +0200 Subject: staging: iio: hmc5843: Fix crash in probe function. Fix crash after issuing: echo hmc5843 0x1e > /sys/class/i2c-dev/i2c-2/device/new_device [ 37.180999] device: '2-001e': device_add [ 37.188293] bus: 'i2c': add device 2-001e [ 37.194549] PM: Adding info for i2c:2-001e [ 37.200958] bus: 'i2c': driver_probe_device: matched device 2-001e with driver hmc5843 [ 37.210815] bus: 'i2c': really_probe: probing driver hmc5843 with device 2-001e [ 37.224884] HMC5843 initialized [ 37.228759] ------------[ cut here ]------------ [ 37.233612] kernel BUG at mm/slab.c:505! [ 37.237701] Internal error: Oops - BUG: 0 [#1] PREEMPT [ 37.243103] Modules linked in: [ 37.246337] CPU: 0 Not tainted (3.3.1-gta04+ #28) [ 37.251647] PC is at kfree+0x84/0x144 [ 37.255493] LR is at kfree+0x20/0x144 [ 37.259338] pc : [] lr : [] psr: 40000093 [ 37.259368] sp : de249cd8 ip : 0000000c fp : 00000090 [ 37.271362] r10: 0000000a r9 : de229eac r8 : c0236274 [ 37.276855] r7 : c09d6490 r6 : a0000013 r5 : de229c00 r4 : de229c10 [ 37.283691] r3 : c0f00218 r2 : 00000400 r1 : c0eea000 r0 : c00b4028 [ 37.290527] Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 37.298095] Control: 10c5387d Table: 9e1d0019 DAC: 00000015 [ 37.304107] Process sh (pid: 91, stack limit = 0xde2482f0) [ 37.309844] Stack: (0xde249cd8 to 0xde24a000) [ 37.314422] 9cc0: de229c10 de229c00 [ 37.322998] 9ce0: de229c10 ffffffea 00000005 c0236274 de140a80 c00b4798 dec00080 de140a80 [ 37.331573] 9d00: c032f37c dec00080 000080d0 00000001 de229c00 de229c10 c048d578 00000005 [ 37.340148] 9d20: de229eac 0000000a 00000090 c032fa40 00000001 00000000 00000001 de229c10 [ 37.348724] 9d40: de229eac 00000029 c075b558 00000001 00000003 00000004 de229c10 c048d594 [ 37.357299] 9d60: 00000000 60000013 00000018 205b0007 37332020 3432322e 5d343838 c0060020 [ 37.365905] 9d80: de251600 00000001 00000000 de251600 00000001 c0065a84 de229c00 de229c48 [ 37.374481] 9da0: 00000006 0048d62c de229c38 de229c00 de229c00 de1f6c00 de1f6c20 00000001 [ 37.383056] 9dc0: 00000000 c048d62c 00000000 de229c00 de229c00 de1f6c00 de1f6c20 00000001 [ 37.391632] 9de0: 00000000 c048d62c 00000000 c0330164 00000000 de1f6c20 c048d62c de1f6c00 [ 37.400207] 9e00: c0330078 de1f6c04 c078d714 de189b58 00000000 c02ccfd8 de1f6c20 c0795f40 [ 37.408782] 9e20: c0238330 00000000 00000000 c02381a8 de1b9fc0 de1f6c20 de1f6c20 de249e48 [ 37.417358] 9e40: c0238330 c0236bb0 decdbed8 de7d0f14 de1f6c20 de1f6c20 de1f6c54 de1f6c20 [ 37.425933] 9e60: 00000000 c0238030 de1f6c20 c078d7bc de1f6c20 c02377ec de1f6c20 de1f6c28 [ 37.434509] 9e80: dee64cb0 c0236138 c047c554 de189b58 00000000 c004b45c de1f6c20 de1f6cd8 [ 37.443084] 9ea0: c0edfa6c de1f6c00 dee64c68 de1f6c04 de1f6c20 dee64cb8 c047c554 de189b58 [ 37.451690] 9ec0: 00000000 c02cd634 dee64c68 de249ef4 de23b008 dee64cb0 0000000d de23b000 [ 37.460266] 9ee0: de23b007 c02cd78c 00000002 00000000 00000000 35636d68 00333438 00000000 [ 37.468841] 9f00: 00000000 00000000 001e0000 00000000 00000000 00000000 00000000 0a10cec0 [ 37.477416] 9f20: 00000002 de249f80 0000000d dee62990 de189b40 c0234d88 0000000d c010c354 [ 37.485992] 9f40: 0000000d de210f28 000acc88 de249f80 0000000d de248000 00000000 c00b7bf8 [ 37.494567] 9f60: de210f28 000acc88 de210f28 000acc88 00000000 00000000 0000000d c00b7ed8 [ 37.503143] 9f80: 00000000 00000000 0000000d 00000000 0007fa28 0000000d 000acc88 00000004 [ 37.511718] 9fa0: c000e544 c000e380 0007fa28 0000000d 00000001 000acc88 0000000d 00000000 [ 37.520294] 9fc0: 0007fa28 0000000d 000acc88 00000004 00000001 00000020 00000002 00000000 [ 37.528869] 9fe0: 00000000 beab8624 0000ea05 b6eaebac 600d0010 00000001 00000000 00000000 [ 37.537475] [] (kfree+0x84/0x144) from [] (device_add+0x530/0x57c) [ 37.545806] [] (device_add+0x530/0x57c) from [] (iio_device_register+0x8c8/0x990) [ 37.555480] [] (iio_device_register+0x8c8/0x990) from [] (hmc5843_probe+0xec/0x114) [ 37.565338] [] (hmc5843_probe+0xec/0x114) from [] (i2c_device_probe+0xc4/0xf8) [ 37.574737] [] (i2c_device_probe+0xc4/0xf8) from [] (driver_probe_device+0x118/0x218) [ 37.584777] [] (driver_probe_device+0x118/0x218) from [] (bus_for_each_drv+0x4c/0x84) [ 37.594818] [] (bus_for_each_drv+0x4c/0x84) from [] (device_attach+0x78/0xa4) [ 37.604125] [] (device_attach+0x78/0xa4) from [] (bus_probe_device+0x28/0x9c) [ 37.613433] [] (bus_probe_device+0x28/0x9c) from [] (device_add+0x3f4/0x57c) [ 37.622650] [] (device_add+0x3f4/0x57c) from [] (i2c_new_device+0xf8/0x19c) [ 37.631805] [] (i2c_new_device+0xf8/0x19c) from [] (i2c_sysfs_new_device+0xb4/0x130) [ 37.641754] [] (i2c_sysfs_new_device+0xb4/0x130) from [] (dev_attr_store+0x18/0x24) [ 37.651611] [] (dev_attr_store+0x18/0x24) from [] (sysfs_write_file+0x10c/0x140) [ 37.661193] [] (sysfs_write_file+0x10c/0x140) from [] (vfs_write+0xb0/0x178) [ 37.670410] [] (vfs_write+0xb0/0x178) from [] (sys_write+0x3c/0x68) [ 37.678833] [] (sys_write+0x3c/0x68) from [] (ret_fast_syscall+0x0/0x3c) [ 37.687683] Code: 1593301c e5932000 e3120080 1a000000 (e7f001f2) [ 37.700775] ---[ end trace aaf805debdb69390 ]--- Client data was assigned to iio_dev structure in probe but in hmc5843_init_client function casted to private driver data structure which is wrong. Possibly calling mutex_init(&data->lock); corrupt data which the lead to above crash. Signed-off-by: Marek Belisko Cc: stable Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index 91dd3da..e00b416 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -521,7 +521,9 @@ static int hmc5843_detect(struct i2c_client *client, /* Called when we have found a new HMC5843. */ static void hmc5843_init_client(struct i2c_client *client) { - struct hmc5843_data *data = i2c_get_clientdata(client); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct hmc5843_data *data = iio_priv(indio_dev); + hmc5843_set_meas_conf(client, data->meas_conf); hmc5843_set_rate(client, data->rate); hmc5843_configure(client, data->operating_mode); -- cgit v0.10.2 From 17b7e1ba1e2ecc9a09f5e154e555accd2a2eaedf Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 12 Apr 2012 00:35:46 +0200 Subject: staging: vt6656: Don't leak memory in drivers/staging/vt6656/ioctl.c::private_ioctl() If copy_to_user() fails in the WLAN_CMD_GET_NODE_LIST case of the switch in drivers/staging/vt6656/ioctl.c::private_ioctl() we'll leak the memory allocated to 'pNodeList'. Fix that by kfree'ing the memory in the failure case. Also remove a pointless cast (to type 'PSNodeList') of a kmalloc() return value - kmalloc() returns a void pointer that is implicitly converted, so there is no need for an explicit cast. Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c index 1463d76..d59456c 100644 --- a/drivers/staging/vt6656/ioctl.c +++ b/drivers/staging/vt6656/ioctl.c @@ -565,7 +565,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -ENOMEM; break; } - pNodeList = (PSNodeList)kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); + pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC); if (pNodeList == NULL) { result = -ENOMEM; break; @@ -601,6 +601,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) } } if (copy_to_user(pReq->data, pNodeList, sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)))) { + kfree(pNodeList); result = -EFAULT; break; } -- cgit v0.10.2 From 474a89885f77953b12bce9f23660c31ef5c2630e Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 11 Apr 2012 22:10:20 +0200 Subject: staging: android: fix mem leaks in __persistent_ram_init() If, in __persistent_ram_init(), the call to persistent_ram_buffer_init() fails or the call to persistent_ram_init_ecc() fails then we fail to free the memory we allocated to 'prz' with kzalloc() - thus leaking it. To prevent the leaks I consolidated all error exits from the function at a 'err:' label at the end and made all error cases jump to that label where we can then make sure we always free 'prz'. This is safe since all the situations where the code bails out happen before 'prz' has been stored anywhere and although we'll do a redundant kfree(NULL) call in the case of kzalloc() itself failing that's OK since kfree() deals gracefully with NULL pointers and I felt it was more important to keep all error exits at a single location than to avoid that one harmless/redundant kfree() on a error path. Signed-off-by: Jesper Juhl Acked-by: Colin Cross Cc: stable Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/staging/android/persistent_ram.c b/drivers/staging/android/persistent_ram.c index e08f257..8d8c1e3 100644 --- a/drivers/staging/android/persistent_ram.c +++ b/drivers/staging/android/persistent_ram.c @@ -399,12 +399,12 @@ static __init struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) { struct persistent_ram_zone *prz; - int ret; + int ret = -ENOMEM; prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); if (!prz) { pr_err("persistent_ram: failed to allocate persistent ram zone\n"); - return ERR_PTR(-ENOMEM); + goto err; } INIT_LIST_HEAD(&prz->node); @@ -412,13 +412,13 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) ret = persistent_ram_buffer_init(dev_name(dev), prz); if (ret) { pr_err("persistent_ram: failed to initialize buffer\n"); - return ERR_PTR(ret); + goto err; } prz->ecc = ecc; ret = persistent_ram_init_ecc(prz, prz->buffer_size); if (ret) - return ERR_PTR(ret); + goto err; if (prz->buffer->sig == PERSISTENT_RAM_SIG) { if (buffer_size(prz) > prz->buffer_size || @@ -442,6 +442,9 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc) atomic_set(&prz->buffer->size, 0); return prz; +err: + kfree(prz); + return ERR_PTR(ret); } struct persistent_ram_zone * __init -- cgit v0.10.2 From 5269a9ab7def9a3116663347d59c4d70afa2d180 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 12 Apr 2012 14:42:15 -0600 Subject: irq_domain: fix type mismatch in debugfs output format sizeof(void*) returns an unsigned long, but it was being used as a width parameter to a "%-*s" format string which requires an int. On 64 bit platforms this causes a type mismatch: linux/kernel/irq/irqdomain.c:575: warning: field width should have type 'int', but argument 6 has type 'long unsigned int' This change casts the size to an int so printf gets the right data type. Reported-by: Andreas Schwab Signed-off-by: Grant Likely Cc: David Daney diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index d34413e..0e0ba5f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -629,7 +629,8 @@ static int virq_debug_show(struct seq_file *m, void *private) int i; seq_printf(m, "%-5s %-7s %-15s %-*s %s\n", "irq", "hwirq", - "chip name", 2 * sizeof(void *) + 2, "chip data", "domain name"); + "chip name", (int)(2 * sizeof(void *) + 2), "chip data", + "domain name"); for (i = 1; i < nr_irqs; i++) { desc = irq_to_desc(i); -- cgit v0.10.2 From d53ba47484ed6245e640ee4bfe9d21e9bfc15765 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 12 Apr 2012 16:03:57 -0400 Subject: Btrfs: use commit root when loading free space cache A user reported that booting his box up with btrfs root on 3.4 was way slower than on 3.3 because I removed the ideal caching code. It turns out that we don't load the free space cache if we're in a commit for deadlock reasons, but since we're reading the cache and it hasn't changed yet we are safe reading the inode and free space item from the commit root, so do that and remove all of the deadlock checks so we don't unnecessarily skip loading the free space cache. The user reported this fixed the slowness. Thanks, Tested-by: Calvin Walton Signed-off-by: Josef Bacik Signed-off-by: Chris Mason diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a2134d8..2b35f8d 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -529,9 +529,7 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, * allocate blocks for the tree root we can't do the fast caching since * we likely hold important locks. */ - if (trans && (!trans->transaction->in_commit) && - (root && root != root->fs_info->tree_root) && - btrfs_test_opt(root, SPACE_CACHE)) { + if (fs_info->mount_opt & BTRFS_MOUNT_SPACE_CACHE) { ret = load_free_space_cache(fs_info, cache); spin_lock(&cache->lock); diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 054707e..baaa518 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c @@ -748,13 +748,6 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, u64 used = btrfs_block_group_used(&block_group->item); /* - * If we're unmounting then just return, since this does a search on the - * normal root and not the commit root and we could deadlock. - */ - if (btrfs_fs_closing(fs_info)) - return 0; - - /* * If this block group has been marked to be cleared for one reason or * another then we can't trust the on disk cache, so just return. */ @@ -768,6 +761,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, path = btrfs_alloc_path(); if (!path) return 0; + path->search_commit_root = 1; + path->skip_locking = 1; inode = lookup_free_space_inode(root, block_group, path); if (IS_ERR(inode)) { -- cgit v0.10.2 From 69349c2dc01c489eccaa4c472542c08e370c6d7e Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 12 Apr 2012 19:46:32 -0400 Subject: kconfig: fix IS_ENABLED to not require all options to be defined Using IS_ENABLED() within C (vs. within CPP #if statements) in its current form requires us to actually define every possible bool/tristate Kconfig option twice (__enabled_* and __enabled_*_MODULE variants). This results in a huge autoconf.h file, on the order of 16k lines for a x86_64 defconfig. Fixing IS_ENABLED to be able to work on the smaller subset of just things that we really have defined is step one to fixing this. Which means it has to not choke when fed non-enabled options, such as: include/linux/netdevice.h:964:1: warning: "__enabled_CONFIG_FCOE_MODULE" is not defined [-Wundef] The original prototype of how to implement a C and preprocessor compatible way of doing this came from the Google+ user "comex ." in response to Linus' crowdsourcing challenge for a possible improvement on his earlier C specific solution: #define config_enabled(x) (__stringify(x)[0] == '1') In this implementation, I've chosen variable names that hopefully make how it works more understandable. Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index 067eda0..be342b9 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -4,29 +4,43 @@ #include /* - * Helper macros to use CONFIG_ options in C expressions. Note that + * Helper macros to use CONFIG_ options in C/CPP expressions. Note that * these only work with boolean and tristate options. */ /* + * Getting something that works in C and CPP for an arg that may or may + * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" + * we match on the placeholder define, insert the "0," for arg1 and generate + * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). + * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when + * the last step cherry picks the 2nd arg, we get a zero. + */ +#define __ARG_PLACEHOLDER_1 0, +#define config_enabled(cfg) _config_enabled(cfg) +#define _config_enabled(value) __config_enabled(__ARG_PLACEHOLDER_##value) +#define __config_enabled(arg1_or_junk) ___config_enabled(arg1_or_junk 1, 0) +#define ___config_enabled(__ignored, val, ...) val + +/* * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', * 0 otherwise. * */ #define IS_ENABLED(option) \ - (__enabled_ ## option || __enabled_ ## option ## _MODULE) + (config_enabled(option) || config_enabled(option##_MODULE)) /* * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 * otherwise. For boolean options, this is equivalent to * IS_ENABLED(CONFIG_FOO). */ -#define IS_BUILTIN(option) __enabled_ ## option +#define IS_BUILTIN(option) config_enabled(option) /* * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0 * otherwise. */ -#define IS_MODULE(option) __enabled_ ## option ## _MODULE +#define IS_MODULE(option) config_enabled(option##_MODULE) #endif /* __LINUX_KCONFIG_H */ -- cgit v0.10.2 From a959613533a176a8f5f402585827e94a5220d2db Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 12 Apr 2012 19:46:33 -0400 Subject: Revert "kconfig: fix __enabled_ macros definition for invisible and un-selected symbols" This reverts commit 953742c8fe8ac45be453fee959d7be40cd89f920. Dumping two lines into autoconf.h for all existing Kconfig options results in a giant file (~16k lines) we have to process each time we compile something. We've weaned IS_ENABLED() and similar off of requiring the __enabled_ definitions so now we can revert the change which caused all the extra lines. Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 0586085..9d06744 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -489,6 +489,17 @@ header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) fprintf(fp, "#define %s%s%s 1\n", CONFIG_, sym->name, suffix); } + /* + * Generate the __enabled_CONFIG_* and + * __enabled_CONFIG_*_MODULE macros for use by the + * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is + * generated even for booleans so that the IS_ENABLED() macro + * works. + */ + fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", + sym->name, (*value == 'y')); + fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", + sym->name, (*value == 'm')); break; } case S_HEX: { @@ -540,35 +551,6 @@ static struct conf_printer header_printer_cb = }; /* - * Generate the __enabled_CONFIG_* and __enabled_CONFIG_*_MODULE macros for - * use by the IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is - * generated even for booleans so that the IS_ENABLED() macro works. - */ -static void -header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: { - fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", - sym->name, (*value == 'y')); - fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", - sym->name, (*value == 'm')); - break; - } - default: - break; - } -} - -static struct conf_printer header__enabled_printer_cb = -{ - .print_symbol = header_print__enabled_symbol, - .print_comment = header_print_comment, -}; - -/* * Tristate printer * * This printer is used when generating the `include/config/tristate.conf' file. @@ -949,16 +931,11 @@ int conf_write_autoconf(void) conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { - if (!sym->name) - continue; - sym_calc_value(sym); - - conf_write_symbol(out_h, sym, &header__enabled_printer_cb, NULL); - - if (!(sym->flags & SYMBOL_WRITE)) + if (!(sym->flags & SYMBOL_WRITE) || !sym->name) continue; + /* write symbol to auto.conf, tristate and header files */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); -- cgit v0.10.2 From e4757cab4cff01e9c47b14376be7438694032c3c Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Thu, 12 Apr 2012 19:46:34 -0400 Subject: kconfig: delete last traces of __enabled_ from autoconf.h We've now fixed IS_ENABLED() and friends to not require any special "__enabled_" prefixed versions of the normal Kconfig options, so delete the last traces of them being generated. Signed-off-by: Paul Gortmaker Signed-off-by: Linus Torvalds diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 9d06744..52577f0 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -489,17 +489,6 @@ header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) fprintf(fp, "#define %s%s%s 1\n", CONFIG_, sym->name, suffix); } - /* - * Generate the __enabled_CONFIG_* and - * __enabled_CONFIG_*_MODULE macros for use by the - * IS_{ENABLED,BUILTIN,MODULE} macros. The _MODULE variant is - * generated even for booleans so that the IS_ENABLED() macro - * works. - */ - fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", - sym->name, (*value == 'y')); - fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", - sym->name, (*value == 'm')); break; } case S_HEX: { -- cgit v0.10.2 From 7d7eb9ea314e992413620610b4d09c9cd5fa8959 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 12 Apr 2012 22:11:25 +0200 Subject: ALSA: hda/realtek - Fix mem leak (and rid us of trailing whitespace). In sound/pci/hda/patch_realtek.c::alc_auto_fill_dac_nids(), in the 'for (;;)' loop, if the 'badness' value returned from fill_and_eval_dacs() is negative, then we'll return from the function without freeing the memory we allocated for 'best_cfg', thus leaking. Fix the leak by kfree()'ing the memory when badness is negative. While I was there I also noticed some trailing whitespace in the function that I removed (along with all other trailing whitespace in the file) - it didn't seem worth-while to do that as two patches, so I hope it's OK that I just did it all as one patch. Signed-off-by: Jesper Juhl Signed-off-by: Takashi Iwai diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8f4a484..2508f81 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3398,8 +3398,10 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) for (;;) { badness = fill_and_eval_dacs(codec, fill_hardwired, fill_mio_first); - if (badness < 0) + if (badness < 0) { + kfree(best_cfg); return badness; + } debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", cfg->line_out_type, fill_hardwired, fill_mio_first, badness); @@ -3434,7 +3436,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; fill_hardwired = true; continue; - } + } if (cfg->hp_outs > 0 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { cfg->speaker_outs = cfg->line_outs; @@ -3448,7 +3450,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) cfg->line_out_type = AUTO_PIN_HP_OUT; fill_hardwired = true; continue; - } + } break; } @@ -4423,7 +4425,7 @@ static int alc_parse_auto_config(struct hda_codec *codec, static int alc880_parse_auto_config(struct hda_codec *codec) { static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; - static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; + static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids); } @@ -6093,7 +6095,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { * Basically the device should work as is without the fixup table. * If BIOS doesn't give a proper info, enable the corresponding * fixup entry. - */ + */ SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", ALC269_FIXUP_AMIC), SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC), @@ -6310,7 +6312,7 @@ static void alc_fixup_no_jack_detect(struct hda_codec *codec, { if (action == ALC_FIXUP_ACT_PRE_PROBE) codec->no_jack_detect = 1; -} +} static const struct alc_fixup alc861_fixups[] = { [ALC861_FIXUP_FSC_AMILO_PI1505] = { @@ -6728,7 +6730,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { * Basically the device should work as is without the fixup table. * If BIOS doesn't give a proper info, enable the corresponding * fixup entry. - */ + */ SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1), -- cgit v0.10.2 From 6a848ccb800f5330ca368cd804795b7ce644e36c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:46 +0200 Subject: drm/i915: rip out ring->irq_mask We only ever enable/disable one interrupt (namely user_interrupts and pipe_notify), so we don't need to track the interrupt masking state. Also rename irq_enable to irq_enable_mask, now that it won't collide - beforehand both a irq_mask and irq_enable_mask would have looked a bit strange. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 467b331..915aa07 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -798,7 +798,6 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 mask = ring->irq_enable; if (!dev->irq_enabled) return false; @@ -810,9 +809,8 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) { - ring->irq_mask &= ~mask; - I915_WRITE_IMR(ring, ring->irq_mask); - ironlake_enable_irq(dev_priv, mask); + I915_WRITE_IMR(ring, ~ring->irq_enable_mask); + ironlake_enable_irq(dev_priv, ring->irq_enable_mask); } spin_unlock(&ring->irq_lock); @@ -824,13 +822,11 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 mask = ring->irq_enable; spin_lock(&ring->irq_lock); if (--ring->irq_refcount == 0) { - ring->irq_mask |= mask; - I915_WRITE_IMR(ring, ring->irq_mask); - ironlake_disable_irq(dev_priv, mask); + I915_WRITE_IMR(ring, ~0); + ironlake_disable_irq(dev_priv, ring->irq_enable_mask); } spin_unlock(&ring->irq_lock); @@ -1002,7 +998,6 @@ int intel_init_ring_buffer(struct drm_device *dev, init_waitqueue_head(&ring->irq_queue); spin_lock_init(&ring->irq_lock); - ring->irq_mask = ~0; if (I915_NEED_GFX_HWS(dev)) { ret = init_status_page(ring); @@ -1380,7 +1375,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .flush = gen6_ring_flush, .add_request = gen6_add_request, .get_seqno = gen6_ring_get_seqno, - .irq_enable = GEN6_BSD_USER_INTERRUPT, + .irq_enable_mask = GEN6_BSD_USER_INTERRUPT, .irq_get = gen6_ring_get_irq, .irq_put = gen6_ring_put_irq, .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, @@ -1426,7 +1421,7 @@ static const struct intel_ring_buffer gen6_blt_ring = { .get_seqno = gen6_ring_get_seqno, .irq_get = gen6_ring_get_irq, .irq_put = gen6_ring_put_irq, - .irq_enable = GEN6_BLITTER_USER_INTERRUPT, + .irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT, .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, .sync_to = gen6_blt_ring_sync_to, .semaphore_register = {MI_SEMAPHORE_SYNC_BR, @@ -1446,7 +1441,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->flush = gen6_render_ring_flush; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; - ring->irq_enable = GT_USER_INTERRUPT; + ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; @@ -1471,7 +1466,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->add_request = gen6_add_request; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; - ring->irq_enable = GT_USER_INTERRUPT; + ring->irq_enable_mask = GT_USER_INTERRUPT; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->get_seqno = pc_render_get_seqno; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 3488a5a..06a66ad 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -58,8 +58,7 @@ struct intel_ring_buffer { spinlock_t irq_lock; u32 irq_refcount; - u32 irq_mask; - u32 irq_enable; /* IRQs enabled for this ring */ + u32 irq_enable_mask; /* bitmask to enable ring interrupt */ u32 irq_seqno; /* last seq seem at irq time */ u32 trace_irq_seqno; u32 waiting_seqno; -- cgit v0.10.2 From dfc9ef2fb0ba01ad8256f4dfa9a8e8fcc6288fc4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:47 +0200 Subject: drm/i915: set ring->size in common ring setup code Eventually we want to scale the ring size depending upon available gtt space. For now just consolidate this instead of replicating it over all ringbuffer templates. Reviewed-by: Eric Anholt Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 915aa07..87e2907 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -995,6 +995,7 @@ int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->gpu_write_list); + ring->size = 32 * PAGE_SIZE; init_waitqueue_head(&ring->irq_queue); spin_lock_init(&ring->irq_lock); @@ -1268,7 +1269,6 @@ static const struct intel_ring_buffer render_ring = { .name = "render ring", .id = RCS, .mmio_base = RENDER_RING_BASE, - .size = 32 * PAGE_SIZE, .init = init_render_ring, .write_tail = ring_write_tail, .flush = render_ring_flush, @@ -1291,7 +1291,6 @@ static const struct intel_ring_buffer bsd_ring = { .name = "bsd ring", .id = VCS, .mmio_base = BSD_RING_BASE, - .size = 32 * PAGE_SIZE, .init = init_ring_common, .write_tail = ring_write_tail, .flush = bsd_ring_flush, @@ -1369,7 +1368,6 @@ static const struct intel_ring_buffer gen6_bsd_ring = { .name = "gen6 bsd ring", .id = VCS, .mmio_base = GEN6_BSD_RING_BASE, - .size = 32 * PAGE_SIZE, .init = init_ring_common, .write_tail = gen6_bsd_ring_write_tail, .flush = gen6_ring_flush, @@ -1413,7 +1411,6 @@ static const struct intel_ring_buffer gen6_blt_ring = { .name = "blt ring", .id = BCS, .mmio_base = BLT_RING_BASE, - .size = 32 * PAGE_SIZE, .init = init_ring_common, .write_tail = ring_write_tail, .flush = blt_ring_flush, -- cgit v0.10.2 From 59465b5f78db752622350e3e01dbe18a6f19e876 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:48 +0200 Subject: drm/i915: dynamically set up the render ring functions and params Our hw is simply not well-designed enough that it neatly fits into boxes. Everywhere else we set up vtables and similar things dynamically using switch statements - it's simply much more flexible. This is prep work to rework the pre-gen6 ring irq stuff - it'll add a few more differences. With the current const struct templates, that would be a mess. This leads to some unfortunate duplication with the old dri1 code, but we can reap that again because gen6 isn't actually supported there. But that's for a separate patch. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 87e2907..fd8e27a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1265,26 +1265,6 @@ void intel_ring_advance(struct intel_ring_buffer *ring) ring->write_tail(ring, ring->tail); } -static const struct intel_ring_buffer render_ring = { - .name = "render ring", - .id = RCS, - .mmio_base = RENDER_RING_BASE, - .init = init_render_ring, - .write_tail = ring_write_tail, - .flush = render_ring_flush, - .add_request = render_ring_add_request, - .get_seqno = ring_get_seqno, - .irq_get = render_ring_get_irq, - .irq_put = render_ring_put_irq, - .dispatch_execbuffer = render_ring_dispatch_execbuffer, - .cleanup = render_ring_cleanup, - .sync_to = render_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_INVALID, - MI_SEMAPHORE_SYNC_RV, - MI_SEMAPHORE_SYNC_RB}, - .signal_mbox = {GEN6_VRSYNC, GEN6_BRSYNC}, -}; - /* ring buffer for bit-stream decoder */ static const struct intel_ring_buffer bsd_ring = { @@ -1432,7 +1412,10 @@ int intel_init_render_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; - *ring = render_ring; + ring->name = "render ring"; + ring->id = RCS; + ring->mmio_base = RENDER_RING_BASE; + if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; ring->flush = gen6_render_ring_flush; @@ -1440,10 +1423,30 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; + ring->sync_to = render_ring_sync_to; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; + ring->signal_mbox[0] = GEN6_VRSYNC; + ring->signal_mbox[1] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; + ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; + ring->irq_get = render_ring_get_irq; + ring->irq_put = render_ring_put_irq; + } else { + ring->add_request = render_ring_add_request; + ring->flush = render_ring_flush; + ring->get_seqno = ring_get_seqno; + ring->irq_get = render_ring_get_irq; + ring->irq_put = render_ring_put_irq; } + ring->write_tail = ring_write_tail; + ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; + ring->init = init_render_ring; + ring->cleanup = render_ring_cleanup; + if (!I915_NEED_GFX_HWS(dev)) { ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; @@ -1458,16 +1461,40 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[RCS]; - *ring = render_ring; + ring->name = "render ring"; + ring->id = RCS; + ring->mmio_base = RENDER_RING_BASE; + if (INTEL_INFO(dev)->gen >= 6) { ring->add_request = gen6_add_request; + ring->flush = gen6_render_ring_flush; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT; + ring->get_seqno = gen6_ring_get_seqno; + ring->sync_to = render_ring_sync_to; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; + ring->signal_mbox[0] = GEN6_VRSYNC; + ring->signal_mbox[1] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; + ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; + ring->irq_get = render_ring_get_irq; + ring->irq_put = render_ring_put_irq; + } else { + ring->add_request = render_ring_add_request; + ring->flush = render_ring_flush; + ring->get_seqno = ring_get_seqno; + ring->irq_get = render_ring_get_irq; + ring->irq_put = render_ring_put_irq; } + ring->write_tail = ring_write_tail; + ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; + ring->init = init_render_ring; + ring->cleanup = render_ring_cleanup; if (!I915_NEED_GFX_HWS(dev)) ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; -- cgit v0.10.2 From 58fa3835874bc3466e84e3bba6057f43acd6eb18 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:49 +0200 Subject: drm/i915: dynamically set up bsd ring functions and params The same treatment for the bsd ring. Again, this will be split up further by the irq rework. Reviewed-by: Eric Anholt Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fd8e27a..683d1f0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1265,22 +1265,6 @@ void intel_ring_advance(struct intel_ring_buffer *ring) ring->write_tail(ring, ring->tail); } -/* ring buffer for bit-stream decoder */ - -static const struct intel_ring_buffer bsd_ring = { - .name = "bsd ring", - .id = VCS, - .mmio_base = BSD_RING_BASE, - .init = init_ring_common, - .write_tail = ring_write_tail, - .flush = bsd_ring_flush, - .add_request = ring_add_request, - .get_seqno = ring_get_seqno, - .irq_get = bsd_ring_get_irq, - .irq_put = bsd_ring_put_irq, - .dispatch_execbuffer = ring_dispatch_execbuffer, -}; - static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring, u32 value) @@ -1343,27 +1327,6 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, return 0; } -/* ring buffer for Video Codec for Gen6+ */ -static const struct intel_ring_buffer gen6_bsd_ring = { - .name = "gen6 bsd ring", - .id = VCS, - .mmio_base = GEN6_BSD_RING_BASE, - .init = init_ring_common, - .write_tail = gen6_bsd_ring_write_tail, - .flush = gen6_ring_flush, - .add_request = gen6_add_request, - .get_seqno = gen6_ring_get_seqno, - .irq_enable_mask = GEN6_BSD_USER_INTERRUPT, - .irq_get = gen6_ring_get_irq, - .irq_put = gen6_ring_put_irq, - .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, - .sync_to = gen6_bsd_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_VR, - MI_SEMAPHORE_SYNC_INVALID, - MI_SEMAPHORE_SYNC_VB}, - .signal_mbox = {GEN6_RVSYNC, GEN6_BVSYNC}, -}; - /* Blitter support (SandyBridge+) */ static int blt_ring_flush(struct intel_ring_buffer *ring, @@ -1531,10 +1494,37 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[VCS]; - if (IS_GEN6(dev) || IS_GEN7(dev)) - *ring = gen6_bsd_ring; - else - *ring = bsd_ring; + ring->name = "bsd ring"; + ring->id = VCS; + + if (IS_GEN6(dev) || IS_GEN7(dev)) { + ring->mmio_base = GEN6_BSD_RING_BASE; + ring->write_tail = gen6_bsd_ring_write_tail; + ring->flush = gen6_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + ring->sync_to = gen6_bsd_ring_sync_to; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB; + ring->signal_mbox[0] = GEN6_RVSYNC; + ring->signal_mbox[1] = GEN6_BVSYNC; + } else { + ring->mmio_base = BSD_RING_BASE; + ring->write_tail = ring_write_tail; + ring->flush = bsd_ring_flush; + ring->add_request = ring_add_request; + ring->get_seqno = ring_get_seqno; + ring->irq_get = bsd_ring_get_irq; + ring->irq_put = bsd_ring_put_irq; + ring->dispatch_execbuffer = ring_dispatch_execbuffer; + } + ring->init = init_ring_common; + return intel_init_ring_buffer(dev, ring); } -- cgit v0.10.2 From 3535d9dd5a19c2f7b88caf67d650bdaa0750b06c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:50 +0200 Subject: drm/i915: dynamically set up blt ring functions and parameters Just for consistency. Reviewed-by: Eric Anholt Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 683d1f0..5b11c53 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1350,26 +1350,6 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, return 0; } -static const struct intel_ring_buffer gen6_blt_ring = { - .name = "blt ring", - .id = BCS, - .mmio_base = BLT_RING_BASE, - .init = init_ring_common, - .write_tail = ring_write_tail, - .flush = blt_ring_flush, - .add_request = gen6_add_request, - .get_seqno = gen6_ring_get_seqno, - .irq_get = gen6_ring_get_irq, - .irq_put = gen6_ring_put_irq, - .irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT, - .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, - .sync_to = gen6_blt_ring_sync_to, - .semaphore_register = {MI_SEMAPHORE_SYNC_BR, - MI_SEMAPHORE_SYNC_BV, - MI_SEMAPHORE_SYNC_INVALID}, - .signal_mbox = {GEN6_RBSYNC, GEN6_VBSYNC}, -}; - int intel_init_render_ring_buffer(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -1534,7 +1514,25 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = &dev_priv->ring[BCS]; - *ring = gen6_blt_ring; + ring->name = "blitter ring"; + ring->id = BCS; + + ring->mmio_base = BLT_RING_BASE; + ring->write_tail = ring_write_tail; + ring->flush = blt_ring_flush; + ring->add_request = gen6_add_request; + ring->get_seqno = gen6_ring_get_seqno; + ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT; + ring->irq_get = gen6_ring_get_irq; + ring->irq_put = gen6_ring_put_irq; + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + ring->sync_to = gen6_blt_ring_sync_to; + ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR; + ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV; + ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID; + ring->signal_mbox[0] = GEN6_RBSYNC; + ring->signal_mbox[1] = GEN6_VBSYNC; + ring->init = init_ring_common; return intel_init_ring_buffer(dev, ring); } -- cgit v0.10.2 From b4178f8aaf84ae59d9b2a17a4a21aa19499f577a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:51 +0200 Subject: drm/i915: don't set up rings on gen6+ for non-kms It's not supported, and with the patch to refuse loading on gen6+ without kms enabled, there's also no way we can hit this. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 5b11c53..be405f2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1409,18 +1409,8 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->mmio_base = RENDER_RING_BASE; if (INTEL_INFO(dev)->gen >= 6) { - ring->add_request = gen6_add_request; - ring->flush = gen6_render_ring_flush; - ring->irq_get = gen6_ring_get_irq; - ring->irq_put = gen6_ring_put_irq; - ring->irq_enable_mask = GT_USER_INTERRUPT; - ring->get_seqno = gen6_ring_get_seqno; - ring->sync_to = render_ring_sync_to; - ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; - ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; - ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; - ring->signal_mbox[0] = GEN6_VRSYNC; - ring->signal_mbox[1] = GEN6_BRSYNC; + /* non-kms not supported on gen6+ */ + return -ENODEV; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; ring->flush = render_ring_flush; -- cgit v0.10.2 From 686cb5f9f5dc7db150c9f4e49cc0d45ef952450b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:52 +0200 Subject: drm/i915: consolidate ring->sync-to functions The waiter is always the ring itself (otherwise we'd have a decent snafu in a callsite), so we can unify this easily. Also give it the usual gen6_ prefix, in case anyone is foolish enough to implement hw semaphores for gen5. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index be405f2..bc33f13 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -472,10 +472,9 @@ gen6_add_request(struct intel_ring_buffer *ring, * @seqno - seqno which the waiter will block on */ static int -intel_ring_sync(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - int ring, - u32 seqno) +gen6_ring_sync(struct intel_ring_buffer *waiter, + struct intel_ring_buffer *signaller, + u32 seqno) { int ret; u32 dw1 = MI_SEMAPHORE_MBOX | @@ -488,11 +487,15 @@ intel_ring_sync(struct intel_ring_buffer *waiter, */ seqno -= 1; + WARN_ON(signaller->semaphore_register[waiter->id] == + MI_SEMAPHORE_SYNC_INVALID); + ret = intel_ring_begin(waiter, 4); if (ret) return ret; - intel_ring_emit(waiter, dw1 | signaller->semaphore_register[ring]); + intel_ring_emit(waiter, + dw1 | signaller->semaphore_register[waiter->id]); intel_ring_emit(waiter, seqno); intel_ring_emit(waiter, 0); intel_ring_emit(waiter, MI_NOOP); @@ -501,47 +504,6 @@ intel_ring_sync(struct intel_ring_buffer *waiter, return 0; } -/* VCS->RCS (RVSYNC) or BCS->RCS (RBSYNC) */ -int -render_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - WARN_ON(signaller->semaphore_register[RCS] == MI_SEMAPHORE_SYNC_INVALID); - return intel_ring_sync(waiter, - signaller, - RCS, - seqno); -} - -/* RCS->VCS (VRSYNC) or BCS->VCS (VBSYNC) */ -int -gen6_bsd_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - WARN_ON(signaller->semaphore_register[VCS] == MI_SEMAPHORE_SYNC_INVALID); - return intel_ring_sync(waiter, - signaller, - VCS, - seqno); -} - -/* RCS->BCS (BRSYNC) or VCS->BCS (BVSYNC) */ -int -gen6_blt_ring_sync_to(struct intel_ring_buffer *waiter, - struct intel_ring_buffer *signaller, - u32 seqno) -{ - WARN_ON(signaller->semaphore_register[BCS] == MI_SEMAPHORE_SYNC_INVALID); - return intel_ring_sync(waiter, - signaller, - BCS, - seqno); -} - - - #define PIPE_CONTROL_FLUSH(ring__, addr__) \ do { \ intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE | \ @@ -1366,7 +1328,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; - ring->sync_to = render_ring_sync_to; + ring->sync_to = gen6_ring_sync; ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB; @@ -1477,7 +1439,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; - ring->sync_to = gen6_bsd_ring_sync_to; + ring->sync_to = gen6_ring_sync; ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR; ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB; @@ -1516,7 +1478,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; - ring->sync_to = gen6_blt_ring_sync_to; + ring->sync_to = gen6_ring_sync; ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR; ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV; ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID; -- cgit v0.10.2 From e367031966c3546b213f6699b83669739cb6fb1d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:53 +0200 Subject: drm/i915: abstract away ring-specific irq_get/put Inspired by Ben Widawsky's patch for gen6+. Now after restructuring how we set up the ring vtables and parameters, we can do this right. This kills the bsd specific get/put_irq functions, they're now the same. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bc33f13..a09e8aa 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -645,7 +645,7 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) } static bool -render_ring_get_irq(struct intel_ring_buffer *ring) +i9xx_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -657,9 +657,9 @@ render_ring_get_irq(struct intel_ring_buffer *ring) if (ring->irq_refcount++ == 0) { if (INTEL_INFO(dev)->gen >= 5) ironlake_enable_irq(dev_priv, - GT_PIPE_NOTIFY | GT_USER_INTERRUPT); + ring->irq_enable_mask); else - i915_enable_irq(dev_priv, I915_USER_INTERRUPT); + i915_enable_irq(dev_priv, ring->irq_enable_mask); } spin_unlock(&ring->irq_lock); @@ -667,7 +667,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) } static void -render_ring_put_irq(struct intel_ring_buffer *ring) +i9xx_ring_put_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -676,10 +676,9 @@ render_ring_put_irq(struct intel_ring_buffer *ring) if (--ring->irq_refcount == 0) { if (INTEL_INFO(dev)->gen >= 5) ironlake_disable_irq(dev_priv, - GT_USER_INTERRUPT | - GT_PIPE_NOTIFY); + ring->irq_enable_mask); else - i915_disable_irq(dev_priv, I915_USER_INTERRUPT); + i915_disable_irq(dev_priv, ring->irq_enable_mask); } spin_unlock(&ring->irq_lock); } @@ -795,42 +794,6 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) gen6_gt_force_wake_put(dev_priv); } -static bool -bsd_ring_get_irq(struct intel_ring_buffer *ring) -{ - struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - if (!dev->irq_enabled) - return false; - - spin_lock(&ring->irq_lock); - if (ring->irq_refcount++ == 0) { - if (IS_G4X(dev)) - i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT); - else - ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT); - } - spin_unlock(&ring->irq_lock); - - return true; -} -static void -bsd_ring_put_irq(struct intel_ring_buffer *ring) -{ - struct drm_device *dev = ring->dev; - drm_i915_private_t *dev_priv = dev->dev_private; - - spin_lock(&ring->irq_lock); - if (--ring->irq_refcount == 0) { - if (IS_G4X(dev)) - i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT); - else - ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT); - } - spin_unlock(&ring->irq_lock); -} - static int ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) { @@ -1338,14 +1301,16 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->add_request = pc_render_add_request; ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; - ring->irq_get = render_ring_get_irq; - ring->irq_put = render_ring_put_irq; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { ring->add_request = render_ring_add_request; ring->flush = render_ring_flush; ring->get_seqno = ring_get_seqno; - ring->irq_get = render_ring_get_irq; - ring->irq_put = render_ring_put_irq; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + ring->irq_enable_mask = I915_USER_INTERRUPT; } ring->write_tail = ring_write_tail; ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; @@ -1377,14 +1342,16 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->add_request = pc_render_add_request; ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; - ring->irq_get = render_ring_get_irq; - ring->irq_put = render_ring_put_irq; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { ring->add_request = render_ring_add_request; ring->flush = render_ring_flush; ring->get_seqno = ring_get_seqno; - ring->irq_get = render_ring_get_irq; - ring->irq_put = render_ring_put_irq; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + ring->irq_enable_mask = I915_USER_INTERRUPT; } ring->write_tail = ring_write_tail; ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; @@ -1451,8 +1418,12 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = bsd_ring_flush; ring->add_request = ring_add_request; ring->get_seqno = ring_get_seqno; - ring->irq_get = bsd_ring_get_irq; - ring->irq_put = bsd_ring_put_irq; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + if (IS_GEN5(dev)) + ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; + else + ring->irq_enable_mask = I915_BSD_USER_INTERRUPT; ring->dispatch_execbuffer = ring_dispatch_execbuffer; } ring->init = init_ring_common; -- cgit v0.10.2 From e48d86347c602c55159714f6ddcd88969a1b2f21 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:54 +0200 Subject: drm/i915: split out the gen5 ring irq get/put functions Now that we have sensibly split up, we can nicely get rid of that ugly is_gen5 check. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a09e8aa..7e1f221 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -645,6 +645,35 @@ i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) } static bool +gen5_ring_get_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + if (!dev->irq_enabled) + return false; + + spin_lock(&ring->irq_lock); + if (ring->irq_refcount++ == 0) + ironlake_enable_irq(dev_priv, ring->irq_enable_mask); + spin_unlock(&ring->irq_lock); + + return true; +} + +static void +gen5_ring_put_irq(struct intel_ring_buffer *ring) +{ + struct drm_device *dev = ring->dev; + drm_i915_private_t *dev_priv = dev->dev_private; + + spin_lock(&ring->irq_lock); + if (--ring->irq_refcount == 0) + ironlake_disable_irq(dev_priv, ring->irq_enable_mask); + spin_unlock(&ring->irq_lock); +} + +static bool i9xx_ring_get_irq(struct intel_ring_buffer *ring) { struct drm_device *dev = ring->dev; @@ -654,13 +683,8 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock(&ring->irq_lock); - if (ring->irq_refcount++ == 0) { - if (INTEL_INFO(dev)->gen >= 5) - ironlake_enable_irq(dev_priv, - ring->irq_enable_mask); - else - i915_enable_irq(dev_priv, ring->irq_enable_mask); - } + if (ring->irq_refcount++ == 0) + i915_enable_irq(dev_priv, ring->irq_enable_mask); spin_unlock(&ring->irq_lock); return true; @@ -673,13 +697,8 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring) drm_i915_private_t *dev_priv = dev->dev_private; spin_lock(&ring->irq_lock); - if (--ring->irq_refcount == 0) { - if (INTEL_INFO(dev)->gen >= 5) - ironlake_disable_irq(dev_priv, - ring->irq_enable_mask); - else - i915_disable_irq(dev_priv, ring->irq_enable_mask); - } + if (--ring->irq_refcount == 0) + i915_disable_irq(dev_priv, ring->irq_enable_mask); spin_unlock(&ring->irq_lock); } @@ -1301,8 +1320,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->add_request = pc_render_add_request; ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; - ring->irq_get = i9xx_ring_get_irq; - ring->irq_put = i9xx_ring_put_irq; + ring->irq_get = gen5_ring_get_irq; + ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { ring->add_request = render_ring_add_request; @@ -1342,8 +1361,8 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->add_request = pc_render_add_request; ring->flush = render_ring_flush; ring->get_seqno = pc_render_get_seqno; - ring->irq_get = i9xx_ring_get_irq; - ring->irq_put = i9xx_ring_put_irq; + ring->irq_get = gen5_ring_get_irq; + ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { ring->add_request = render_ring_add_request; @@ -1418,12 +1437,15 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = bsd_ring_flush; ring->add_request = ring_add_request; ring->get_seqno = ring_get_seqno; - ring->irq_get = i9xx_ring_get_irq; - ring->irq_put = i9xx_ring_put_irq; - if (IS_GEN5(dev)) + if (IS_GEN5(dev)) { ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; - else + ring->irq_get = gen5_ring_get_irq; + ring->irq_put = gen5_ring_put_irq; + } else { ring->irq_enable_mask = I915_BSD_USER_INTERRUPT; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + } ring->dispatch_execbuffer = ring_dispatch_execbuffer; } ring->init = init_ring_common; -- cgit v0.10.2 From 0fd2c201482e62492f2d7dc6c2798cf7f66c9570 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:55 +0200 Subject: drm/i915: don't enable the gen6 bsd ring tail write enable on gen7 HW engineers have fixed this issue for ivb. Again, a nice cleanup possible thanks to the more flexible ring initialization. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 7e1f221..68e1255 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1415,9 +1415,12 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->name = "bsd ring"; ring->id = VCS; + ring->write_tail = ring_write_tail; if (IS_GEN6(dev) || IS_GEN7(dev)) { ring->mmio_base = GEN6_BSD_RING_BASE; - ring->write_tail = gen6_bsd_ring_write_tail; + /* gen6 bsd needs a special wa for tail updates */ + if (IS_GEN6(dev)) + ring->write_tail = gen6_bsd_ring_write_tail; ring->flush = gen6_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; @@ -1433,7 +1436,6 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->signal_mbox[1] = GEN6_BVSYNC; } else { ring->mmio_base = BSD_RING_BASE; - ring->write_tail = ring_write_tail; ring->flush = bsd_ring_flush; ring->add_request = ring_add_request; ring->get_seqno = ring_get_seqno; -- cgit v0.10.2 From fb3256da8db2cb70be7d2c7f058b8676a9a85aaf Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:56 +0200 Subject: drm/i915: split up ring->dispatch_execbuffer functions Now that we can, we should split them up in a way that makes some sense and banishes the IS_ checks into init code. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 68e1255..8cffd0b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -814,7 +814,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) } static int -ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) +i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) { int ret; @@ -832,37 +832,36 @@ ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) } static int -render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring, +i830_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 len) { - struct drm_device *dev = ring->dev; int ret; - if (IS_I830(dev) || IS_845G(dev)) { - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; + ret = intel_ring_begin(ring, 4); + if (ret) + return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); - intel_ring_emit(ring, offset + len - 8); - intel_ring_emit(ring, 0); - } else { - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; + intel_ring_emit(ring, MI_BATCH_BUFFER); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); + intel_ring_emit(ring, offset + len - 8); + intel_ring_emit(ring, 0); + intel_ring_advance(ring); - if (INTEL_INFO(dev)->gen >= 4) { - intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6) | - MI_BATCH_NON_SECURE_I965); - intel_ring_emit(ring, offset); - } else { - intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6)); - intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); - } - } + return 0; +} + +static int +i915_dispatch_execbuffer(struct intel_ring_buffer *ring, + u32 offset, u32 len) +{ + int ret; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6)); + intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); intel_ring_advance(ring); return 0; @@ -1332,7 +1331,14 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_enable_mask = I915_USER_INTERRUPT; } ring->write_tail = ring_write_tail; - ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; + if (INTEL_INFO(dev)->gen >= 6) + ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer; + else if (INTEL_INFO(dev)->gen >= 4) + ring->dispatch_execbuffer = i965_dispatch_execbuffer; + else if (IS_I830(dev) || IS_845G(dev)) + ring->dispatch_execbuffer = i830_dispatch_execbuffer; + else + ring->dispatch_execbuffer = i915_dispatch_execbuffer; ring->init = init_render_ring; ring->cleanup = render_ring_cleanup; @@ -1373,7 +1379,12 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->irq_enable_mask = I915_USER_INTERRUPT; } ring->write_tail = ring_write_tail; - ring->dispatch_execbuffer = render_ring_dispatch_execbuffer; + if (INTEL_INFO(dev)->gen >= 4) + ring->dispatch_execbuffer = i965_dispatch_execbuffer; + else if (IS_I830(dev) || IS_845G(dev)) + ring->dispatch_execbuffer = i830_dispatch_execbuffer; + else + ring->dispatch_execbuffer = i915_dispatch_execbuffer; ring->init = init_render_ring; ring->cleanup = render_ring_cleanup; @@ -1448,7 +1459,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->irq_get = i9xx_ring_get_irq; ring->irq_put = i9xx_ring_put_irq; } - ring->dispatch_execbuffer = ring_dispatch_execbuffer; + ring->dispatch_execbuffer = i965_dispatch_execbuffer; } ring->init = init_ring_common; -- cgit v0.10.2 From 8620a3a908da34e1a0db9ad457136bc96340911f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:57 +0200 Subject: drm/i915: consolidate ring->add_request a bit They're indentical, so just kill one. Also give the other a prefix to distinguish it from the gen6+ functions - this add_request function is not really generic code. v2: Fixup commit message as noted by Ben Widawsky. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 8cffd0b..ac05c74 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -565,27 +565,6 @@ pc_render_add_request(struct intel_ring_buffer *ring, return 0; } -static int -render_ring_add_request(struct intel_ring_buffer *ring, - u32 *result) -{ - u32 seqno = i915_gem_next_request_seqno(ring); - int ret; - - ret = intel_ring_begin(ring, 4); - if (ret) - return ret; - - intel_ring_emit(ring, MI_STORE_DWORD_INDEX); - intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, seqno); - intel_ring_emit(ring, MI_USER_INTERRUPT); - intel_ring_advance(ring); - - *result = seqno; - return 0; -} - static u32 gen6_ring_get_seqno(struct intel_ring_buffer *ring) { @@ -751,7 +730,7 @@ bsd_ring_flush(struct intel_ring_buffer *ring, } static int -ring_add_request(struct intel_ring_buffer *ring, +i9xx_add_request(struct intel_ring_buffer *ring, u32 *result) { u32 seqno; @@ -1323,7 +1302,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { - ring->add_request = render_ring_add_request; + ring->add_request = i9xx_add_request; ring->flush = render_ring_flush; ring->get_seqno = ring_get_seqno; ring->irq_get = i9xx_ring_get_irq; @@ -1371,7 +1350,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { - ring->add_request = render_ring_add_request; + ring->add_request = i9xx_add_request; ring->flush = render_ring_flush; ring->get_seqno = ring_get_seqno; ring->irq_get = i9xx_ring_get_irq; @@ -1448,7 +1427,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) } else { ring->mmio_base = BSD_RING_BASE; ring->flush = bsd_ring_flush; - ring->add_request = ring_add_request; + ring->add_request = i9xx_add_request; ring->get_seqno = ring_get_seqno; if (IS_GEN5(dev)) { ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; -- cgit v0.10.2 From 28f0cbf71f5ed9b080878c04158c754b090a674a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:58 +0200 Subject: drm/i915: don't set up gem ring functions on gen5 for !kms We already disallow initialition of gem in this case in the corresponding ioctl, so don't bother setting up the gem support ring functions in the legacy dri render ring init. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index ac05c74..6b3ff37 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1342,21 +1342,17 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) if (INTEL_INFO(dev)->gen >= 6) { /* non-kms not supported on gen6+ */ return -ENODEV; - } else if (IS_GEN5(dev)) { - ring->add_request = pc_render_add_request; - ring->flush = render_ring_flush; - ring->get_seqno = pc_render_get_seqno; - ring->irq_get = gen5_ring_get_irq; - ring->irq_put = gen5_ring_put_irq; - ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; - } else { - ring->add_request = i9xx_add_request; - ring->flush = render_ring_flush; - ring->get_seqno = ring_get_seqno; - ring->irq_get = i9xx_ring_get_irq; - ring->irq_put = i9xx_ring_put_irq; - ring->irq_enable_mask = I915_USER_INTERRUPT; } + + /* Note: gem is not supported on gen5/ilk without kms (the corresponding + * gem_init ioctl returns with -ENODEV). Hence we do not need to set up + * the special gen5 functions. */ + ring->add_request = i9xx_add_request; + ring->flush = render_ring_flush; + ring->get_seqno = ring_get_seqno; + ring->irq_get = i9xx_ring_get_irq; + ring->irq_put = i9xx_ring_put_irq; + ring->irq_enable_mask = I915_USER_INTERRUPT; ring->write_tail = ring_write_tail; if (INTEL_INFO(dev)->gen >= 4) ring->dispatch_execbuffer = i965_dispatch_execbuffer; -- cgit v0.10.2 From f637fde434c9e3687798730c7ddd367e93666013 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 22:12:59 +0200 Subject: drm/i915: inline enable/disable_irq into ring->get/put_irq Now that these are properly refactored this additional indirection doesn't really buy us anything but confusion. Hence inline them. This duplicates the ironlake gt enable/disable code snippet, but we've already separate ilk from gen6+ gt irq in i915_irq.c, so I think this makes more sense. Reviewed-by: Eric Anholt Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6b3ff37..6c14457 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -591,38 +591,6 @@ pc_render_get_seqno(struct intel_ring_buffer *ring) return pc->cpu_page[0]; } -static void -ironlake_enable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - dev_priv->gt_irq_mask &= ~mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); -} - -static void -ironlake_disable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - dev_priv->gt_irq_mask |= mask; - I915_WRITE(GTIMR, dev_priv->gt_irq_mask); - POSTING_READ(GTIMR); -} - -static void -i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - dev_priv->irq_mask &= ~mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); -} - -static void -i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask) -{ - dev_priv->irq_mask |= mask; - I915_WRITE(IMR, dev_priv->irq_mask); - POSTING_READ(IMR); -} - static bool gen5_ring_get_irq(struct intel_ring_buffer *ring) { @@ -633,8 +601,11 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock(&ring->irq_lock); - if (ring->irq_refcount++ == 0) - ironlake_enable_irq(dev_priv, ring->irq_enable_mask); + if (ring->irq_refcount++ == 0) { + dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); + } spin_unlock(&ring->irq_lock); return true; @@ -647,8 +618,11 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring) drm_i915_private_t *dev_priv = dev->dev_private; spin_lock(&ring->irq_lock); - if (--ring->irq_refcount == 0) - ironlake_disable_irq(dev_priv, ring->irq_enable_mask); + if (--ring->irq_refcount == 0) { + dev_priv->gt_irq_mask |= ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); + } spin_unlock(&ring->irq_lock); } @@ -662,8 +636,11 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring) return false; spin_lock(&ring->irq_lock); - if (ring->irq_refcount++ == 0) - i915_enable_irq(dev_priv, ring->irq_enable_mask); + if (ring->irq_refcount++ == 0) { + dev_priv->irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); + } spin_unlock(&ring->irq_lock); return true; @@ -676,8 +653,11 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring) drm_i915_private_t *dev_priv = dev->dev_private; spin_lock(&ring->irq_lock); - if (--ring->irq_refcount == 0) - i915_disable_irq(dev_priv, ring->irq_enable_mask); + if (--ring->irq_refcount == 0) { + dev_priv->irq_mask |= ring->irq_enable_mask; + I915_WRITE(IMR, dev_priv->irq_mask); + POSTING_READ(IMR); + } spin_unlock(&ring->irq_lock); } @@ -769,7 +749,9 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring) spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) { I915_WRITE_IMR(ring, ~ring->irq_enable_mask); - ironlake_enable_irq(dev_priv, ring->irq_enable_mask); + dev_priv->gt_irq_mask &= ~ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); } spin_unlock(&ring->irq_lock); @@ -785,7 +767,9 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring) spin_lock(&ring->irq_lock); if (--ring->irq_refcount == 0) { I915_WRITE_IMR(ring, ~0); - ironlake_disable_irq(dev_priv, ring->irq_enable_mask); + dev_priv->gt_irq_mask |= ring->irq_enable_mask; + I915_WRITE(GTIMR, dev_priv->gt_irq_mask); + POSTING_READ(GTIMR); } spin_unlock(&ring->irq_lock); -- cgit v0.10.2 From 79985eee842ef146ed6307a29fdc2fa008036421 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 13 Apr 2012 19:47:53 +0800 Subject: drm/i915/intel_i2c: handle zero-length reads A common method of probing an i2c bus is trying to do a zero-length read. Handle this case by checking the length first waiting for data to be read. This is actually important, since attempting a zero-length read is one of the ways that i2cdetect and i2c_new_probed_device detect whether there is device present on the bus with a given address. Reviewed-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48269 Signed-off-by: Daniel Kurtz Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index cab879f..e249160 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -217,7 +217,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, (len << GMBUS_BYTE_COUNT_SHIFT) | (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); - do { + while (len) { int ret; u32 val, loop = 0; u32 gmbus2; @@ -235,7 +235,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, *buf++ = val & 0xff; val >>= 8; } while (--len && ++loop < 4); - } while (len); + } return 0; } -- cgit v0.10.2 From 56fa6d6ff76c7700f8dd131bee9ffa6c3c06dcd4 Mon Sep 17 00:00:00 2001 From: Daniel Kurtz Date: Fri, 13 Apr 2012 19:47:54 +0800 Subject: drm/i915/intel_i2c: reduce verbosity of some messages Some of these messages can be hit when userspace tries to probe the i2c with nothing connected or if the driver code tries to do the same. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48248 Signed-off-by: Daniel Kurtz Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index e249160..e04255e 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -383,7 +383,7 @@ gmbus_xfer(struct i2c_adapter *adapter, */ if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) { - DRM_INFO("GMBUS [%s] timed out waiting for idle\n", + DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n", adapter->name); ret = -ETIMEDOUT; } @@ -399,7 +399,8 @@ clear_err: */ if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) - DRM_INFO("GMBUS [%s] timed out after NAK\n", adapter->name); + DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", + adapter->name); /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the @@ -409,7 +410,7 @@ clear_err: I915_WRITE(GMBUS1 + reg_offset, 0); I915_WRITE(GMBUS0 + reg_offset, 0); - DRM_DEBUG_DRIVER("GMBUS [%s] NAK for addr: %04x %c(%d)\n", + DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n", adapter->name, msgs[i].addr, (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); -- cgit v0.10.2 From 1e45860f541497d73162305d48b638d9b87e1ae3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 13 Apr 2012 13:11:50 +0100 Subject: ARM: 7366/3: amba: Remove AMBA level regulator support The AMBA bus regulator support is being used to model on/off switches for power domains which isn't terribly idiomatic for modern kernels with the generic power domain code and creates integration problems on platforms which don't use regulators for their power domains as it's hard to tell the difference between a regulator that is needed but failed to be provided and one that isn't supposed to be there (though DT does make that easier). Platforms that wish to use the regulator API to manage their power domains can indirect via the power domain interface. This feature is only used with the vape supply of the db8500 PRCMU driver which supplies the UARTs and MMC controllers, none of which have support for managing vcore at runtime in mainline (only pl022 SPI controller does). Update that supply to have an always_on constraint until the power domain support for the system is updated so that it is enabled for these users, this is likely to have no impact on practical systems as probably at least one of these devices will be active and cause AMBA to hold the supply on anyway. Signed-off-by: Mark Brown Acked-by: Linus Walleij Tested-by: Shawn Guo Signed-off-by: Russell King diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 01c2cf4..cc27322 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -247,8 +247,7 @@ static int amba_pm_restore(struct device *dev) /* * Hooks to provide runtime PM of the pclk (bus clock). It is safe to * enable/disable the bus clock at runtime PM suspend/resume as this - * does not result in loss of context. However, disabling vcore power - * would do, so we leave that to the driver. + * does not result in loss of context. */ static int amba_pm_runtime_suspend(struct device *dev) { @@ -354,39 +353,6 @@ static void amba_put_disable_pclk(struct amba_device *pcdev) clk_put(pclk); } -static int amba_get_enable_vcore(struct amba_device *pcdev) -{ - struct regulator *vcore = regulator_get(&pcdev->dev, "vcore"); - int ret; - - pcdev->vcore = vcore; - - if (IS_ERR(vcore)) { - /* It is OK not to supply a vcore regulator */ - if (PTR_ERR(vcore) == -ENODEV) - return 0; - return PTR_ERR(vcore); - } - - ret = regulator_enable(vcore); - if (ret) { - regulator_put(vcore); - pcdev->vcore = ERR_PTR(-ENODEV); - } - - return ret; -} - -static void amba_put_disable_vcore(struct amba_device *pcdev) -{ - struct regulator *vcore = pcdev->vcore; - - if (!IS_ERR(vcore)) { - regulator_disable(vcore); - regulator_put(vcore); - } -} - /* * These are the device model conversion veneers; they convert the * device model structures to our more specific structures. @@ -399,10 +365,6 @@ static int amba_probe(struct device *dev) int ret; do { - ret = amba_get_enable_vcore(pcdev); - if (ret) - break; - ret = amba_get_enable_pclk(pcdev); if (ret) break; @@ -420,7 +382,6 @@ static int amba_probe(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); - amba_put_disable_vcore(pcdev); } while (0); return ret; @@ -442,7 +403,6 @@ static int amba_remove(struct device *dev) pm_runtime_put_noidle(dev); amba_put_disable_pclk(pcdev); - amba_put_disable_vcore(pcdev); return ret; } diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index ebc1e86..5be3248 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2788,6 +2788,7 @@ static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = { .constraints = { .name = "db8500-vape", .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = true, }, .consumer_supplies = db8500_vape_consumers, .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers), diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 96f0da6..09c925a 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2195,7 +2195,6 @@ static int pl022_runtime_suspend(struct device *dev) struct pl022 *pl022 = dev_get_drvdata(dev); clk_disable(pl022->clk); - amba_vcore_disable(pl022->adev); return 0; } @@ -2204,7 +2203,6 @@ static int pl022_runtime_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - amba_vcore_enable(pl022->adev); clk_enable(pl022->clk); return 0; diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index 7847e19..8d54f79 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -30,7 +30,6 @@ struct amba_device { struct device dev; struct resource res; struct clk *pclk; - struct regulator *vcore; u64 dma_mask; unsigned int periphid; unsigned int irq[AMBA_NR_IRQS]; @@ -75,12 +74,6 @@ void amba_release_regions(struct amba_device *); #define amba_pclk_disable(d) \ do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0) -#define amba_vcore_enable(d) \ - (IS_ERR((d)->vcore) ? 0 : regulator_enable((d)->vcore)) - -#define amba_vcore_disable(d) \ - do { if (!IS_ERR((d)->vcore)) regulator_disable((d)->vcore); } while (0) - /* Some drivers don't use the struct amba_device */ #define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff) #define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f) -- cgit v0.10.2 From 9c5fd9e85f574d9d0361b2b878f55732290afe5b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Apr 2012 14:52:55 +0100 Subject: ARM: 7379/1: DT: fix atags_to_fdt() second call site atags_to_fdt() returns 1 when it fails to find a valid FDT signature. The CONFIG_ARM_ATAG_DTB_COMPAT code is supposed to retry with another location, but only does so when the initial call doesn't fail. Fix this by using the correct condition in the assembly code. Acked-by: Nicolas Pitre Signed-off-by: Marc Zyngier Cc: stable@vger.kernel.org Signed-off-by: Russell King diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 5f6045f..dc7e8ce 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -273,7 +273,7 @@ restart: adr r0, LC0 add r0, r0, #0x100 mov r1, r6 sub r2, sp, r6 - blne atags_to_fdt + bleq atags_to_fdt ldmfd sp!, {r0-r3, ip, lr} sub sp, sp, #0x10000 -- cgit v0.10.2 From a106b21a352517b57af1c3581e15b8787ffe4e98 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 11 Apr 2012 14:52:56 +0100 Subject: ARM: 7380/1: DT: do not add a zero-sized memory property Some bootloaders are broken enough to expose an ATAG_MEM with a null size. Converting such tag to a memory node leads to an unbootable system. Skip over zero sized ATAG_MEM to avoid this situation. Acked-by: Nicolas Pitre Signed-off-by: Marc Zyngier Signed-off-by: Russell King diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c index 6ce11c4..797f04b 100644 --- a/arch/arm/boot/compressed/atags_to_fdt.c +++ b/arch/arm/boot/compressed/atags_to_fdt.c @@ -77,6 +77,8 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space) } else if (atag->hdr.tag == ATAG_MEM) { if (memcount >= sizeof(mem_reg_property)/4) continue; + if (!atag->u.mem.size) + continue; mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); } else if (atag->hdr.tag == ATAG_INITRD2) { -- cgit v0.10.2 From 9b7333a9c1c22409f685ff6bb6a9e3638e7ff06f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 12 Apr 2012 17:12:37 +0100 Subject: ARM: 7381/1: nommu: fix typo in mm/Kconfig The description for the CPU_HIGH_VECTOR Kconfig option for nommu builds doesn't make any sense. This patch fixes up the trivial grammatical error. Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 7edef91..7c8a7d8 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -723,7 +723,7 @@ config CPU_HIGH_VECTOR bool "Select the High exception vector" help Say Y here to select high exception vector(0xFFFF0000~). - The exception vector can be vary depending on the platform + The exception vector can vary depending on the platform design in nommu mode. If your platform needs to select high exception vector, say Y. Otherwise or if you are unsure, say N, and the low exception -- cgit v0.10.2 From 6b8e5c912f4294611351aba151324764ebbefa1b Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 12 Apr 2012 17:16:01 +0100 Subject: ARM: 7383/1: nommu: populate vectors page from paging_init Commit 94e5a85b ("ARM: earlier initialization of vectors page") made it the responsibility of paging_init to initialise the vectors page. This patch adds a call to early_trap_init for the !CONFIG_MMU case, placing the vectors at CONFIG_VECTORS_BASE. Cc: Jonathan Austin Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 6486d2f..d51225f 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "mm.h" @@ -39,6 +40,7 @@ void __init sanity_check_meminfo(void) */ void __init paging_init(struct machine_desc *mdesc) { + early_trap_init((void *)CONFIG_VECTORS_BASE); bootmem_init(); } -- cgit v0.10.2 From 5ba840f9da1ff96e0c6e982608a9e80e35333cc5 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 2 Apr 2012 16:04:13 -0400 Subject: alpha: fix build failures from system.h dismemberment commit ec2212088c42ff7d1362629ec26dda4f3e8bdad3 "Disintegrate asm/system.h for Alpha" combined with commit b4816afa3986704d1404fc48e931da5135820472 "Move the asm-generic/system.h xchg() implementation to asm-generic/cmpxchg.h" introduced the concept of asm/cmpxchg.h but the alpha arch never got one. Fork the cmpxchg content out of the asm/atomic.h file to create one. Some minor whitespace fixups were done on the block of code that created the new file. Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Matt Turner Cc: David Howells Acked-by: Matt Turner Signed-off-by: Paul Gortmaker diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index f62251e..3bb7ffe 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -3,6 +3,7 @@ #include #include +#include /* * Atomic operations that C can't guarantee us. Useful for @@ -168,73 +169,6 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v) return result; } -/* - * Atomic exchange routines. - */ - -#define __ASM__MB -#define ____xchg(type, args...) __xchg ## type ## _local(args) -#define ____cmpxchg(type, args...) __cmpxchg ## type ## _local(args) -#include - -#define xchg_local(ptr,x) \ - ({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_, \ - sizeof(*(ptr))); \ - }) - -#define cmpxchg_local(ptr, o, n) \ - ({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \ - (unsigned long)_n_, \ - sizeof(*(ptr))); \ - }) - -#define cmpxchg64_local(ptr, o, n) \ - ({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - cmpxchg_local((ptr), (o), (n)); \ - }) - -#ifdef CONFIG_SMP -#undef __ASM__MB -#define __ASM__MB "\tmb\n" -#endif -#undef ____xchg -#undef ____cmpxchg -#define ____xchg(type, args...) __xchg ##type(args) -#define ____cmpxchg(type, args...) __cmpxchg ##type(args) -#include - -#define xchg(ptr,x) \ - ({ \ - __typeof__(*(ptr)) _x_ = (x); \ - (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, \ - sizeof(*(ptr))); \ - }) - -#define cmpxchg(ptr, o, n) \ - ({ \ - __typeof__(*(ptr)) _o_ = (o); \ - __typeof__(*(ptr)) _n_ = (n); \ - (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ - (unsigned long)_n_, sizeof(*(ptr)));\ - }) - -#define cmpxchg64(ptr, o, n) \ - ({ \ - BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ - cmpxchg((ptr), (o), (n)); \ - }) - -#undef __ASM__MB -#undef ____cmpxchg - -#define __HAVE_ARCH_CMPXCHG 1 - #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) diff --git a/arch/alpha/include/asm/cmpxchg.h b/arch/alpha/include/asm/cmpxchg.h new file mode 100644 index 0000000..429e8cd --- /dev/null +++ b/arch/alpha/include/asm/cmpxchg.h @@ -0,0 +1,71 @@ +#ifndef _ALPHA_CMPXCHG_H +#define _ALPHA_CMPXCHG_H + +/* + * Atomic exchange routines. + */ + +#define __ASM__MB +#define ____xchg(type, args...) __xchg ## type ## _local(args) +#define ____cmpxchg(type, args...) __cmpxchg ## type ## _local(args) +#include + +#define xchg_local(ptr, x) \ +({ \ + __typeof__(*(ptr)) _x_ = (x); \ + (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_, \ + sizeof(*(ptr))); \ +}) + +#define cmpxchg_local(ptr, o, n) \ +({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, \ + sizeof(*(ptr))); \ +}) + +#define cmpxchg64_local(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + cmpxchg_local((ptr), (o), (n)); \ +}) + +#ifdef CONFIG_SMP +#undef __ASM__MB +#define __ASM__MB "\tmb\n" +#endif +#undef ____xchg +#undef ____cmpxchg +#define ____xchg(type, args...) __xchg ##type(args) +#define ____cmpxchg(type, args...) __cmpxchg ##type(args) +#include + +#define xchg(ptr, x) \ +({ \ + __typeof__(*(ptr)) _x_ = (x); \ + (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, \ + sizeof(*(ptr))); \ +}) + +#define cmpxchg(ptr, o, n) \ +({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr)));\ +}) + +#define cmpxchg64(ptr, o, n) \ +({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + cmpxchg((ptr), (o), (n)); \ +}) + +#undef __ASM__MB +#undef ____cmpxchg + +#define __HAVE_ARCH_CMPXCHG 1 + +#endif /* _ALPHA_CMPXCHG_H */ diff --git a/arch/alpha/include/asm/xchg.h b/arch/alpha/include/asm/xchg.h index 1d1b436..0ca9724 100644 --- a/arch/alpha/include/asm/xchg.h +++ b/arch/alpha/include/asm/xchg.h @@ -1,10 +1,10 @@ -#ifndef _ALPHA_ATOMIC_H +#ifndef _ALPHA_CMPXCHG_H #error Do not include xchg.h directly! #else /* * xchg/xchg_local and cmpxchg/cmpxchg_local share the same code * except that local version do not have the expensive memory barrier. - * So this file is included twice from asm/system.h. + * So this file is included twice from asm/cmpxchg.h. */ /* -- cgit v0.10.2 From 85f8f7759e418c814ee2ceacf73eddb9bed39492 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 3 Apr 2012 13:51:35 -0400 Subject: ia64: populate the cmpxchg header with appropriate code commit 93f378883cecb9dcb2cf5b51d9d24175906659da "Fix ia64 build errors (fallout from system.h disintegration)" introduced arch/ia64/include/asm/cmpxchg.h as a temporary build fix and stated: "... leave the migration of xchg() and cmpxchg() to this new header file for a future patch." Migrate the appropriate chunks from asm/intrinsics.h and fix the whitespace issues in the migrated chunk. Cc: Fenghua Yu Cc: David Howells Acked-by: Tony Luck Signed-off-by: Paul Gortmaker diff --git a/arch/ia64/include/asm/cmpxchg.h b/arch/ia64/include/asm/cmpxchg.h index 4c96187..4f37dbb 100644 --- a/arch/ia64/include/asm/cmpxchg.h +++ b/arch/ia64/include/asm/cmpxchg.h @@ -1 +1,147 @@ -#include +#ifndef _ASM_IA64_CMPXCHG_H +#define _ASM_IA64_CMPXCHG_H + +/* + * Compare/Exchange, forked from asm/intrinsics.h + * which was: + * + * Copyright (C) 2002-2003 Hewlett-Packard Co + * David Mosberger-Tang + */ + +#ifndef __ASSEMBLY__ + +#include +/* include compiler specific intrinsics */ +#include +#ifdef __INTEL_COMPILER +# include +#else +# include +#endif + +/* + * This function doesn't exist, so you'll get a linker error if + * something tries to do an invalid xchg(). + */ +extern void ia64_xchg_called_with_bad_pointer(void); + +#define __xchg(x, ptr, size) \ +({ \ + unsigned long __xchg_result; \ + \ + switch (size) { \ + case 1: \ + __xchg_result = ia64_xchg1((__u8 *)ptr, x); \ + break; \ + \ + case 2: \ + __xchg_result = ia64_xchg2((__u16 *)ptr, x); \ + break; \ + \ + case 4: \ + __xchg_result = ia64_xchg4((__u32 *)ptr, x); \ + break; \ + \ + case 8: \ + __xchg_result = ia64_xchg8((__u64 *)ptr, x); \ + break; \ + default: \ + ia64_xchg_called_with_bad_pointer(); \ + } \ + __xchg_result; \ +}) + +#define xchg(ptr, x) \ +((__typeof__(*(ptr))) __xchg((unsigned long) (x), (ptr), sizeof(*(ptr)))) + +/* + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + */ + +#define __HAVE_ARCH_CMPXCHG 1 + +/* + * This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid cmpxchg(). + */ +extern long ia64_cmpxchg_called_with_bad_pointer(void); + +#define ia64_cmpxchg(sem, ptr, old, new, size) \ +({ \ + __u64 _o_, _r_; \ + \ + switch (size) { \ + case 1: \ + _o_ = (__u8) (long) (old); \ + break; \ + case 2: \ + _o_ = (__u16) (long) (old); \ + break; \ + case 4: \ + _o_ = (__u32) (long) (old); \ + break; \ + case 8: \ + _o_ = (__u64) (long) (old); \ + break; \ + default: \ + break; \ + } \ + switch (size) { \ + case 1: \ + _r_ = ia64_cmpxchg1_##sem((__u8 *) ptr, new, _o_); \ + break; \ + \ + case 2: \ + _r_ = ia64_cmpxchg2_##sem((__u16 *) ptr, new, _o_); \ + break; \ + \ + case 4: \ + _r_ = ia64_cmpxchg4_##sem((__u32 *) ptr, new, _o_); \ + break; \ + \ + case 8: \ + _r_ = ia64_cmpxchg8_##sem((__u64 *) ptr, new, _o_); \ + break; \ + \ + default: \ + _r_ = ia64_cmpxchg_called_with_bad_pointer(); \ + break; \ + } \ + (__typeof__(old)) _r_; \ +}) + +#define cmpxchg_acq(ptr, o, n) \ + ia64_cmpxchg(acq, (ptr), (o), (n), sizeof(*(ptr))) +#define cmpxchg_rel(ptr, o, n) \ + ia64_cmpxchg(rel, (ptr), (o), (n), sizeof(*(ptr))) + +/* for compatibility with other platforms: */ +#define cmpxchg(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) +#define cmpxchg64(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) + +#define cmpxchg_local cmpxchg +#define cmpxchg64_local cmpxchg64 + +#ifdef CONFIG_IA64_DEBUG_CMPXCHG +# define CMPXCHG_BUGCHECK_DECL int _cmpxchg_bugcheck_count = 128; +# define CMPXCHG_BUGCHECK(v) \ +do { \ + if (_cmpxchg_bugcheck_count-- <= 0) { \ + void *ip; \ + extern int printk(const char *fmt, ...); \ + ip = (void *) ia64_getreg(_IA64_REG_IP); \ + printk("CMPXCHG_BUGCHECK: stuck at %p on word %p\n", ip, (v));\ + break; \ + } \ +} while (0) +#else /* !CONFIG_IA64_DEBUG_CMPXCHG */ +# define CMPXCHG_BUGCHECK_DECL +# define CMPXCHG_BUGCHECK(v) +#endif /* !CONFIG_IA64_DEBUG_CMPXCHG */ + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASM_IA64_CMPXCHG_H */ diff --git a/arch/ia64/include/asm/intrinsics.h b/arch/ia64/include/asm/intrinsics.h index e4076b5..d129e36 100644 --- a/arch/ia64/include/asm/intrinsics.h +++ b/arch/ia64/include/asm/intrinsics.h @@ -18,6 +18,7 @@ #else # include #endif +#include #define ia64_native_get_psr_i() (ia64_native_getreg(_IA64_REG_PSR) & IA64_PSR_I) @@ -81,119 +82,6 @@ extern unsigned long __bad_increment_for_ia64_fetch_and_add (void); #define ia64_fetch_and_add(i,v) (ia64_fetchadd(i, v, rel) + (i)) /* return new value */ -/* - * This function doesn't exist, so you'll get a linker error if - * something tries to do an invalid xchg(). - */ -extern void ia64_xchg_called_with_bad_pointer (void); - -#define __xchg(x,ptr,size) \ -({ \ - unsigned long __xchg_result; \ - \ - switch (size) { \ - case 1: \ - __xchg_result = ia64_xchg1((__u8 *)ptr, x); \ - break; \ - \ - case 2: \ - __xchg_result = ia64_xchg2((__u16 *)ptr, x); \ - break; \ - \ - case 4: \ - __xchg_result = ia64_xchg4((__u32 *)ptr, x); \ - break; \ - \ - case 8: \ - __xchg_result = ia64_xchg8((__u64 *)ptr, x); \ - break; \ - default: \ - ia64_xchg_called_with_bad_pointer(); \ - } \ - __xchg_result; \ -}) - -#define xchg(ptr,x) \ - ((__typeof__(*(ptr))) __xchg ((unsigned long) (x), (ptr), sizeof(*(ptr)))) - -/* - * Atomic compare and exchange. Compare OLD with MEM, if identical, - * store NEW in MEM. Return the initial value in MEM. Success is - * indicated by comparing RETURN with OLD. - */ - -#define __HAVE_ARCH_CMPXCHG 1 - -/* - * This function doesn't exist, so you'll get a linker error - * if something tries to do an invalid cmpxchg(). - */ -extern long ia64_cmpxchg_called_with_bad_pointer (void); - -#define ia64_cmpxchg(sem,ptr,old,new,size) \ -({ \ - __u64 _o_, _r_; \ - \ - switch (size) { \ - case 1: _o_ = (__u8 ) (long) (old); break; \ - case 2: _o_ = (__u16) (long) (old); break; \ - case 4: _o_ = (__u32) (long) (old); break; \ - case 8: _o_ = (__u64) (long) (old); break; \ - default: break; \ - } \ - switch (size) { \ - case 1: \ - _r_ = ia64_cmpxchg1_##sem((__u8 *) ptr, new, _o_); \ - break; \ - \ - case 2: \ - _r_ = ia64_cmpxchg2_##sem((__u16 *) ptr, new, _o_); \ - break; \ - \ - case 4: \ - _r_ = ia64_cmpxchg4_##sem((__u32 *) ptr, new, _o_); \ - break; \ - \ - case 8: \ - _r_ = ia64_cmpxchg8_##sem((__u64 *) ptr, new, _o_); \ - break; \ - \ - default: \ - _r_ = ia64_cmpxchg_called_with_bad_pointer(); \ - break; \ - } \ - (__typeof__(old)) _r_; \ -}) - -#define cmpxchg_acq(ptr, o, n) \ - ia64_cmpxchg(acq, (ptr), (o), (n), sizeof(*(ptr))) -#define cmpxchg_rel(ptr, o, n) \ - ia64_cmpxchg(rel, (ptr), (o), (n), sizeof(*(ptr))) - -/* for compatibility with other platforms: */ -#define cmpxchg(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) -#define cmpxchg64(ptr, o, n) cmpxchg_acq((ptr), (o), (n)) - -#define cmpxchg_local cmpxchg -#define cmpxchg64_local cmpxchg64 - -#ifdef CONFIG_IA64_DEBUG_CMPXCHG -# define CMPXCHG_BUGCHECK_DECL int _cmpxchg_bugcheck_count = 128; -# define CMPXCHG_BUGCHECK(v) \ - do { \ - if (_cmpxchg_bugcheck_count-- <= 0) { \ - void *ip; \ - extern int printk(const char *fmt, ...); \ - ip = (void *) ia64_getreg(_IA64_REG_IP); \ - printk("CMPXCHG_BUGCHECK: stuck at %p on word %p\n", ip, (v)); \ - break; \ - } \ - } while (0) -#else /* !CONFIG_IA64_DEBUG_CMPXCHG */ -# define CMPXCHG_BUGCHECK_DECL -# define CMPXCHG_BUGCHECK(v) -#endif /* !CONFIG_IA64_DEBUG_CMPXCHG */ - #endif #ifdef __KERNEL__ -- cgit v0.10.2 From ef1f0982540e5f79c8bbf3675bbc0a9734dba3fc Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 11 Apr 2012 12:21:39 -0400 Subject: irq_work: fix compile failure on tile from missing include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building with IRQ_WORK configured results in kernel/irq_work.c: In function ‘irq_work_run’: kernel/irq_work.c:110: error: implicit declaration of function ‘irqs_disabled’ The appropriate header just needs to be included. Signed-off-by: Chris Metcalf Signed-off-by: Paul Gortmaker diff --git a/kernel/irq_work.c b/kernel/irq_work.c index 0c56d44..1588e3b 100644 --- a/kernel/irq_work.c +++ b/kernel/irq_work.c @@ -11,6 +11,7 @@ #include #include #include +#include #include /* -- cgit v0.10.2 From 1c07ae43bb7f01480c0aceec36d1f27dd6c598bf Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 11 Apr 2012 21:04:02 -0700 Subject: arm: msm: halibut: remove unneeded fixup This old fixup causes a build failure, so I remove it just like in trout. Signed-off-by: Daniel Walker Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/board-halibut.c b/arch/arm/mach-msm/board-halibut.c index 3698a37..26aac36 100644 --- a/arch/arm/mach-msm/board-halibut.c +++ b/arch/arm/mach-msm/board-halibut.c @@ -86,9 +86,6 @@ static void __init halibut_init(void) static void __init halibut_fixup(struct tag *tags, char **cmdline, struct meminfo *mi) { - mi->nr_banks=1; - mi->bank[0].start = PHYS_OFFSET; - mi->bank[0].size = (101*1024*1024); } static void __init halibut_map_io(void) -- cgit v0.10.2 From 204241c27c8fa2186e6d656d587f941422fff1b9 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Thu, 12 Apr 2012 08:45:37 -0700 Subject: arm: msm: trout: fix compile failure Fixes the following warnings, arch/arm/mach-msm/board-trout.c: In function 'trout_init': arch/arm/mach-msm/board-trout.c:71: error: 'system_rev' undeclared (first use in this function) arch/arm/mach-msm/board-trout.c:71: error: (Each undeclared identifier is reported only once arch/arm/mach-msm/board-trout.c:71: error: for each function it appears in.) and arch/arm/mach-msm/board-trout-panel.c: In function 'trout_init_panel': arch/arm/mach-msm/board-trout-panel.c:267: error: 'system_rev' undeclared (first use in this function) arch/arm/mach-msm/board-trout-panel.c:267: error: (Each undeclared identifier is reported only once arch/arm/mach-msm/board-trout-panel.c:267: error: for each function it appears in.) This came in with the following commit 9f97da78bf018206fb623cd351d454af2f105fe0 which removes asm/system.h Signed-off-by: Daniel Walker cc: David Howells cc: Bryan Huntsman cc: linux-arm-msm@vger.kernel.org cc: linux-arm-kernel@lists.infradead.org Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/board-trout-panel.c b/arch/arm/mach-msm/board-trout-panel.c index 25105c1..89bf6b4 100644 --- a/arch/arm/mach-msm/board-trout-panel.c +++ b/arch/arm/mach-msm/board-trout-panel.c @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-msm/board-trout.c b/arch/arm/mach-msm/board-trout.c index 5414f76..d4060a3 100644 --- a/arch/arm/mach-msm/board-trout.c +++ b/arch/arm/mach-msm/board-trout.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include -- cgit v0.10.2 From e89c0e4377303a101d1032bf1dde822218372f15 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 12 Apr 2012 11:36:50 -0700 Subject: video: msm: Fix section mismatches in mddi.c The change commit 461cbe77d0a4f887c33a3a95ea68a7daf23b4302 Author: Gregory Bean Date: Wed Jul 28 10:22:13 2010 -0700 video: msm: Fix section mismatch in mddi.c. fixes a section mismatch between the board file and the driver's probe function, however, it misses the additional mismatches between the probe function and some routines it calls. Fix these up as well. Signed-off-by: David Brown diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c index 4527cbf..b061d70 100644 --- a/drivers/video/msm/mddi.c +++ b/drivers/video/msm/mddi.c @@ -420,7 +420,7 @@ static void mddi_resume(struct msm_mddi_client_data *cdata) mddi_set_auto_hibernate(&mddi->client_data, 1); } -static int __init mddi_get_client_caps(struct mddi_info *mddi) +static int __devinit mddi_get_client_caps(struct mddi_info *mddi) { int i, j; @@ -622,9 +622,9 @@ uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg) static struct mddi_info mddi_info[2]; -static int __init mddi_clk_setup(struct platform_device *pdev, - struct mddi_info *mddi, - unsigned long clk_rate) +static int __devinit mddi_clk_setup(struct platform_device *pdev, + struct mddi_info *mddi, + unsigned long clk_rate) { int ret; -- cgit v0.10.2 From af33eadc73e4a5d35a966c1c7ffe28a8424c9d96 Mon Sep 17 00:00:00 2001 From: David Brown Date: Thu, 12 Apr 2012 11:36:50 -0700 Subject: ARM: msm: Fix section mismatches in proc_comm.c The change commit 4416e9eb0b4859b3d28016c5fd0a609bdcbc8a2a Author: Gregory Bean Date: Wed Jul 28 10:22:12 2010 -0700 arm: msm: Fix section mismatch in smd.c. fixes a section mismatch between the board file and the smd driver's probe function, however, it misses the additional mismatches between the probe function and some routines it calls. Fix these up as well. Signed-off-by: David Brown diff --git a/arch/arm/mach-msm/proc_comm.c b/arch/arm/mach-msm/proc_comm.c index 67e701c..9980dc7 100644 --- a/arch/arm/mach-msm/proc_comm.c +++ b/arch/arm/mach-msm/proc_comm.c @@ -121,7 +121,7 @@ int msm_proc_comm(unsigned cmd, unsigned *data1, unsigned *data2) * and unknown state. This function should be called early to * wait on the ARM9. */ -void __init proc_comm_boot_wait(void) +void __devinit proc_comm_boot_wait(void) { void __iomem *base = MSM_SHARED_RAM_BASE; -- cgit v0.10.2 From 9e0daff30fd7ecf698e5d20b0fa7f851e427cca5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 13 Apr 2012 11:56:22 -0700 Subject: sparc64: Fix bootup crash on sun4v. The DS driver registers as a subsys_initcall() but this can be too early, in particular this risks registering before we've had a chance to allocate and setup module_kset in kernel/params.c which is performed also as a subsyts_initcall(). Register DS using device_initcall() insteal. Signed-off-by: David S. Miller Cc: stable@vger.kernel.org diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index fea13c7..b93c2c9 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -1264,4 +1264,4 @@ static int __init ds_init(void) return vio_register_driver(&ds_driver); } -subsys_initcall(ds_init); +fs_initcall(ds_init); -- cgit v0.10.2 From 3d3eeb2ef26112a200785e5fca58ec58dd33bf1e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 13 Apr 2012 03:35:13 +0000 Subject: sparc64: Eliminate obsolete __handle_softirq() function The invocation of softirq is now handled by irq_exit(), so there is no need for sparc64 to invoke it on the trap-return path. In fact, doing so is a bug because if the trap occurred in the idle loop, this invocation can result in lockdep-RCU failures. The problem is that RCU ignores idle CPUs, and the sparc64 trap-return path to the softirq handlers fails to tell RCU that the CPU must be considered non-idle while those handlers are executing. This means that RCU is ignoring any RCU read-side critical sections in those handlers, which in turn means that RCU-protected data can be yanked out from under those read-side critical sections. The shiny new lockdep-RCU ability to detect RCU read-side critical sections that RCU is ignoring located this problem. The fix is straightforward: Make sparc64 stop manually invoking the softirq handlers. Reported-by: Meelis Roos Suggested-by: David Miller Signed-off-by: Paul E. McKenney Tested-by: Meelis Roos Cc: stable@vger.kernel.org Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S index 77f1b95e..9171fc2 100644 --- a/arch/sparc/kernel/rtrap_64.S +++ b/arch/sparc/kernel/rtrap_64.S @@ -20,11 +20,6 @@ .text .align 32 -__handle_softirq: - call do_softirq - nop - ba,a,pt %xcc, __handle_softirq_continue - nop __handle_preemption: call schedule wrpr %g0, RTRAP_PSTATE, %pstate @@ -89,9 +84,7 @@ rtrap: cmp %l1, 0 /* mm/ultra.S:xcall_report_regs KNOWS about this load. */ - bne,pn %icc, __handle_softirq ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 -__handle_softirq_continue: rtrap_xcall: sethi %hi(0xf << 20), %l4 and %l1, %l4, %l4 -- cgit v0.10.2 From 2d59dcfb54ade45cacc59a6e7bd96b8c19088c3d Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 13 Apr 2012 13:32:30 -0700 Subject: cpufreq: OMAP: fix build errors: depends on ARCH_OMAP2PLUS The OMAP driver needs a 'depends on ARCH_OMAP2PLUS' since it only builds for OMAP2+ platforms. This 'depends on' was in the original patch from Russell King, but was erroneously removed by me when making this option user-selectable in commit b09db45c (cpufreq: OMAP driver depends CPUfreq tables.) This patch remedies that. Apologies to Russell King for breaking his originally working patch. Also, thanks to Grazvydas Ignotas for reporting the same problem. Cc: Russell King Cc: Grazvydas Ignotas Signed-off-by: Kevin Hilman Signed-off-by: Linus Torvalds diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index ffbb446..5961e64 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -4,6 +4,7 @@ config ARM_OMAP2PLUS_CPUFREQ bool "TI OMAP2+" + depends on ARCH_OMAP2PLUS default ARCH_OMAP2PLUS select CPU_FREQ_TABLE -- cgit v0.10.2 From 3cd21f6162e7703adc13c5030f316db9ec6bf5cf Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Sat, 14 Apr 2012 07:42:04 -0700 Subject: ARM: SAMSUNG: make SAMSUNG_PM_DEBUG select DEBUG_LL When selecting SAMSUNG_PM_DEBUG, it complains about a missing printascii() function if you do not select DEBUG_LL, so make the former select the latter. Signed-off-by: Maurus Cuelenaere Acked-by: Heiko Stuebner Signed-off-by: Kukjin Kim diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig index 71553f4..a0ffc77d 100644 --- a/arch/arm/plat-samsung/Kconfig +++ b/arch/arm/plat-samsung/Kconfig @@ -302,6 +302,7 @@ comment "Power management" config SAMSUNG_PM_DEBUG bool "S3C2410 PM Suspend debug" depends on PM + select DEBUG_LL help Say Y here if you want verbose debugging from the PM Suspend and Resume code. See -- cgit v0.10.2 From f441f8a0a180827e3f7bd705aed9cffba62cebc2 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Apr 2012 21:10:32 -0700 Subject: ARM: EXYNOS: fix regulator name for NURI board Regulator names should not contain slash to avoid issues with debugfs. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index b3982c8..f92ec88 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -571,7 +571,7 @@ static struct regulator_init_data __initdata max8997_ldo7_data = { static struct regulator_init_data __initdata max8997_ldo8_data = { .constraints = { - .name = "VUSB/VDAC_3.3V_C210", + .name = "VUSB+VDAC_3.3V_C210", .min_uV = 3300000, .max_uV = 3300000, .valid_ops_mask = REGULATOR_CHANGE_STATUS, -- cgit v0.10.2 From 3d3231b1c986aa3ee1d94ffe36082faf45f0d96b Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Apr 2012 21:10:32 -0700 Subject: ARM: EXYNOS: set fix xusbxti clock for NURI and Universal210 boards On some versions of NURI and UniversalC210 boards, camera clocks are routed directly to xusbxti clock source. This patch sets the correct value for this clock to let usb and camera sensors to work correctly and avoid division by zero on driver's probe. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index f92ec88..dd3ec8e 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1347,6 +1347,7 @@ static struct platform_device *nuri_devices[] __initdata = { static void __init nuri_map_io(void) { + clk_xusbxti.rate = 24000000; exynos_init_io(NULL, 0); s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs)); @@ -1379,7 +1380,6 @@ static void __init nuri_machine_init(void) nuri_camera_init(); nuri_ehci_init(); - clk_xusbxti.rate = 24000000; /* Last */ platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 6bb9dbd..7ebf79c 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -1057,6 +1058,7 @@ static struct platform_device *universal_devices[] __initdata = { static void __init universal_map_io(void) { + clk_xusbxti.rate = 24000000; exynos_init_io(NULL, 0); s3c24xx_init_clocks(24000000); s3c24xx_init_uarts(universal_uartcfgs, ARRAY_SIZE(universal_uartcfgs)); -- cgit v0.10.2 From 5262c543317cf362fe7223563609efaeb555f716 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 9 Apr 2012 21:10:32 -0700 Subject: ARM: EXYNOS: Remove broken config values for touchscren for NURI board The atmel_mxt_ts driver has been extended to support more 'configuration objects' in commit 81c88a711 ("Input: atmel_mxt_ts - update object list"), what broke the configuration values for NURI board. These values are optional anyway, so remove them to get the driver working correctly. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index dd3ec8e..b4f1f90 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -307,49 +307,7 @@ static struct i2c_board_info i2c1_devs[] __initdata = { }; /* TSP */ -static u8 mxt_init_vals[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x02, 0x08, 0x10, 0x00, -}; - static struct mxt_platform_data mxt_platform_data = { - .config = mxt_init_vals, - .config_length = ARRAY_SIZE(mxt_init_vals), - .x_line = 18, .y_line = 11, .x_size = 1024, -- cgit v0.10.2 From 2084c24a81413b75bc97e4bee56b32ffece70460 Mon Sep 17 00:00:00 2001 From: Lubos Lunak Date: Wed, 21 Mar 2012 14:08:24 +0100 Subject: do not export kernel's NULL #define to userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC's NULL is actually __null, which allows detecting some questionable NULL usage and warn about it. Moreover each platform/compiler should have its own stddef.h anyway (which is different from linux/stddef.h). So there's no good reason to leak kernel's NULL to userspace and override what the compiler provides. Signed-off-by: Luboš Luňák Acked-by: Arnd Bergmann Signed-off-by: Linus Torvalds diff --git a/include/linux/stddef.h b/include/linux/stddef.h index 6a40c76..1747b67 100644 --- a/include/linux/stddef.h +++ b/include/linux/stddef.h @@ -3,14 +3,10 @@ #include +#ifdef __KERNEL__ + #undef NULL -#if defined(__cplusplus) -#define NULL 0 -#else #define NULL ((void *)0) -#endif - -#ifdef __KERNEL__ enum { false = 0, -- cgit v0.10.2 From 5ad14306a3f468df61e1739f9f252663f18f1702 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 14 Apr 2012 07:53:51 -0700 Subject: ARM: EXYNOS: Fix Kconfig dependencies for device tree enabled machine files Add config dependency for Exynos4 and Exynos5 device tree enabled machine files on config options ARCH_EXYNOS4 and ARCH_EXYNOS5 respectively. Enabling machine support without proper ARCH support enabled is incorrect. Signed-off-by: Sachin Kamat Signed-off-by: Kukjin Kim diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 0491cee..e81c35f 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -368,6 +368,7 @@ comment "Flattened Device Tree based board for EXYNOS SoCs" config MACH_EXYNOS4_DT bool "Samsung Exynos4 Machine using device tree" + depends on ARCH_EXYNOS4 select CPU_EXYNOS4210 select USE_OF select ARM_AMBA @@ -380,6 +381,7 @@ config MACH_EXYNOS4_DT config MACH_EXYNOS5_DT bool "SAMSUNG EXYNOS5 Machine using device tree" + depends on ARCH_EXYNOS5 select SOC_EXYNOS5250 select USE_OF select ARM_AMBA -- cgit v0.10.2 From eb03f28002c3dc96cbb8d3869df2d8aef3ef3b01 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 12 Apr 2012 10:17:28 -0500 Subject: ARM: dts: remove blank interrupt-parent properties These were incorrectly introduced and can cause problems for of_irq_init. The correct way to define a root controller is no interrupt-parent set at all or the interrupt-parent is set to the root controller itself when inherited from a parent node. Signed-off-by: Rob Herring Tested-by: Lee Jones Signed-off-by: Olof Johansson diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi index 799ad18..773ef48 100644 --- a/arch/arm/boot/dts/at91sam9g20.dtsi +++ b/arch/arm/boot/dts/at91sam9g20.dtsi @@ -55,7 +55,6 @@ #interrupt-cells = <2>; compatible = "atmel,at91rm9200-aic"; interrupt-controller; - interrupt-parent; reg = <0xfffff000 0x200>; }; diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 9e6eb6e..c804214 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -56,7 +56,6 @@ #interrupt-cells = <2>; compatible = "atmel,at91rm9200-aic"; interrupt-controller; - interrupt-parent; reg = <0xfffff000 0x200>; }; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 70ab3a4..dd4ed74 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -54,7 +54,6 @@ #interrupt-cells = <2>; compatible = "atmel,at91rm9200-aic"; interrupt-controller; - interrupt-parent; reg = <0xfffff000 0x200>; }; diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi index d73dce6..14bc307 100644 --- a/arch/arm/boot/dts/db8500.dtsi +++ b/arch/arm/boot/dts/db8500.dtsi @@ -24,7 +24,6 @@ #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; - interrupt-parent; reg = <0xa0411000 0x1000>, <0xa0410100 0x100>; }; diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 37c0ff9c..83e7229 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -89,7 +89,6 @@ #size-cells = <0>; #address-cells = <1>; interrupt-controller; - interrupt-parent; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; -- cgit v0.10.2 From 47d9e44d1dbabc53500e86d5597f2737a40f1f42 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 13 Apr 2012 13:52:15 -0700 Subject: ARM: OMAP: clock: cleanup CPUfreq leftovers, fix build errors Now that we have OPP layer, and OMAP CPUfreq driver is using it, we no longer need/use the clock framework code for filling up CPUfreq tables. Remove it. Removing this code also eliminates build errors when CPU_FREQ_TABLE support is not enabled. Thanks to Russell King for pointing out the parts I missed under plat-omap in the original version and also pointing out the build errors when CPUFREQ_TABLE support was not enabled. Cc: Russell King Signed-off-by: Kevin Hilman Acked-by: Paul Walmsley Acked-by: Tony Lindgren Signed-off-by: Olof Johansson diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c index 7072e0d..3d9d746 100644 --- a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c +++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c @@ -165,83 +165,3 @@ int omap2_select_table_rate(struct clk *clk, unsigned long rate) return 0; } - -#ifdef CONFIG_CPU_FREQ -/* - * Walk PRCM rate table and fillout cpufreq freq_table - * XXX This should be replaced by an OPP layer in the near future - */ -static struct cpufreq_frequency_table *freq_table; - -void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) -{ - const struct prcm_config *prcm; - int i = 0; - int tbl_sz = 0; - - if (!cpu_is_omap24xx()) - return; - - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - if (prcm->xtal_speed != sclk->rate) - continue; - - /* don't put bypass rates in table */ - if (prcm->dpll_speed == prcm->xtal_speed) - continue; - - tbl_sz++; - } - - /* - * XXX Ensure that we're doing what CPUFreq expects for this error - * case and the following one - */ - if (tbl_sz == 0) { - pr_warning("%s: no matching entries in rate_table\n", - __func__); - return; - } - - /* Include the CPUFREQ_TABLE_END terminator entry */ - tbl_sz++; - - freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * tbl_sz, - GFP_ATOMIC); - if (!freq_table) { - pr_err("%s: could not kzalloc frequency table\n", __func__); - return; - } - - for (prcm = rate_table; prcm->mpu_speed; prcm++) { - if (!(prcm->flags & cpu_mask)) - continue; - if (prcm->xtal_speed != sclk->rate) - continue; - - /* don't put bypass rates in table */ - if (prcm->dpll_speed == prcm->xtal_speed) - continue; - - freq_table[i].index = i; - freq_table[i].frequency = prcm->mpu_speed / 1000; - i++; - } - - freq_table[i].index = i; - freq_table[i].frequency = CPUFREQ_TABLE_END; - - *table = &freq_table[0]; -} - -void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) -{ - if (!cpu_is_omap24xx()) - return; - - kfree(freq_table); -} - -#endif diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index f57ed5b..d9f4931 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -536,10 +536,5 @@ struct clk_functions omap2_clk_functions = { .clk_set_rate = omap2_clk_set_rate, .clk_set_parent = omap2_clk_set_parent, .clk_disable_unused = omap2_clk_disable_unused, -#ifdef CONFIG_CPU_FREQ - /* These will be removed when the OPP code is integrated */ - .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, - .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, -#endif }; diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index b8c2a68..a1bb23a 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -146,14 +146,6 @@ extern const struct clksel_rate gpt_sys_rates[]; extern const struct clksel_rate gfx_l3_rates[]; extern const struct clksel_rate dsp_ick_rates[]; -#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) -extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); -extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); -#else -#define omap2_clk_init_cpufreq_table 0 -#define omap2_clk_exit_cpufreq_table 0 -#endif - extern const struct clkops clkops_omap2_iclk_dflt_wait; extern const struct clkops clkops_omap2_iclk_dflt; extern const struct clkops clkops_omap2_iclk_idle_only; diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 8506cbb..62ec5c4 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -398,32 +398,6 @@ struct clk dummy_ck = { .ops = &clkops_null, }; -#ifdef CONFIG_CPU_FREQ -void clk_init_cpufreq_table(struct cpufreq_frequency_table **table) -{ - unsigned long flags; - - if (!arch_clock || !arch_clock->clk_init_cpufreq_table) - return; - - spin_lock_irqsave(&clockfw_lock, flags); - arch_clock->clk_init_cpufreq_table(table); - spin_unlock_irqrestore(&clockfw_lock, flags); -} - -void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) -{ - unsigned long flags; - - if (!arch_clock || !arch_clock->clk_exit_cpufreq_table) - return; - - spin_lock_irqsave(&clockfw_lock, flags); - arch_clock->clk_exit_cpufreq_table(table); - spin_unlock_irqrestore(&clockfw_lock, flags); -} -#endif - /* * */ diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 240a7b9..d0ef57c 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -272,8 +272,6 @@ struct clk { #endif }; -struct cpufreq_frequency_table; - struct clk_functions { int (*clk_enable)(struct clk *clk); void (*clk_disable)(struct clk *clk); @@ -283,10 +281,6 @@ struct clk_functions { void (*clk_allow_idle)(struct clk *clk); void (*clk_deny_idle)(struct clk *clk); void (*clk_disable_unused)(struct clk *clk); -#ifdef CONFIG_CPU_FREQ - void (*clk_init_cpufreq_table)(struct cpufreq_frequency_table **); - void (*clk_exit_cpufreq_table)(struct cpufreq_frequency_table **); -#endif }; extern int mpurate; @@ -301,10 +295,6 @@ extern void recalculate_root_clocks(void); extern unsigned long followparent_recalc(struct clk *clk); extern void clk_enable_init_clocks(void); unsigned long omap_fixed_divisor_recalc(struct clk *clk); -#ifdef CONFIG_CPU_FREQ -extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); -extern void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); -#endif extern struct clk *omap_clk_get_by_name(const char *name); extern int omap_clk_enable_autoidle_all(void); extern int omap_clk_disable_autoidle_all(void); -- cgit v0.10.2 From d1e61e7fc4456c4cb9a33ed182edf40e34ddedea Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 10 Apr 2012 17:00:41 +0100 Subject: drm/i915: Trigger hangcheck if we detect more a repeating missed IRQ On the first instance we just wish to kick the waiters and see if that terminates the wait conditions. If it does not, then we do not want to keep retrying without ever making any forward progress and becoming stuck in a hangcheck loop. Reported-and-tested-by: Lukas Hejtmanek Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48209 Reviewed-by: Ben Widawsky Signed-off-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index febddc2..39663f5 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1875,6 +1875,36 @@ static bool kick_ring(struct intel_ring_buffer *ring) return false; } +static bool i915_hangcheck_hung(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (dev_priv->hangcheck_count++ > 1) { + DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); + i915_handle_error(dev, true); + + if (!IS_GEN2(dev)) { + /* Is the chip hanging on a WAIT_FOR_EVENT? + * If so we can simply poke the RB_WAIT bit + * and break the hang. This should work on + * all but the second generation chipsets. + */ + if (kick_ring(&dev_priv->ring[RCS])) + return false; + + if (HAS_BSD(dev) && kick_ring(&dev_priv->ring[VCS])) + return false; + + if (HAS_BLT(dev) && kick_ring(&dev_priv->ring[BCS])) + return false; + } + + return true; + } + + return false; +} + /** * This is called when the chip hasn't reported back with completed * batchbuffers in a long time. The first time this is called we simply record @@ -1895,9 +1925,14 @@ void i915_hangcheck_elapsed(unsigned long data) if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) && i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) && i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) { - dev_priv->hangcheck_count = 0; - if (err) + if (err) { + if (i915_hangcheck_hung(dev)) + return; + goto repeat; + } + + dev_priv->hangcheck_count = 0; return; } @@ -1919,30 +1954,8 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->last_acthd_blt == acthd_blt && dev_priv->last_instdone == instdone && dev_priv->last_instdone1 == instdone1) { - if (dev_priv->hangcheck_count++ > 1) { - DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); - i915_handle_error(dev, true); - - if (!IS_GEN2(dev)) { - /* Is the chip hanging on a WAIT_FOR_EVENT? - * If so we can simply poke the RB_WAIT bit - * and break the hang. This should work on - * all but the second generation chipsets. - */ - if (kick_ring(&dev_priv->ring[RCS])) - goto repeat; - - if (HAS_BSD(dev) && - kick_ring(&dev_priv->ring[VCS])) - goto repeat; - - if (HAS_BLT(dev) && - kick_ring(&dev_priv->ring[BCS])) - goto repeat; - } - + if (i915_hangcheck_hung(dev)) return; - } } else { dev_priv->hangcheck_count = 0; -- cgit v0.10.2 From c07496fa61f4c5cb2addd1c57f6b22fcaeea2eeb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 13 Apr 2012 15:51:51 +0200 Subject: drm/i915: don't pwrite tiled objects through the gtt ... we will botch up the bit17 swizzling. Furthermore tiled pwrite is a (now) unused slowpath, so no one really cares. This fixes the last swizzling issues I have with i-g-t on my bit17 swizzling i915G. No regression, it's been broken since the dawn of gem, but it's nice for regression tracking when really _all_ i-g-t tests work. Actually this is not true, Chris Wilson noticed while reviewing this patch that the commit commit d9e86c0ee60f323e890484628f351bf50fa9a15d Author: Chris Wilson Date: Wed Nov 10 16:40:20 2010 +0000 drm/i915: Pipelined fencing [infrastructure] contained a functional change that broke things. Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 71934dd..9415c07 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -876,6 +876,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj->gtt_space && obj->cache_level == I915_CACHE_NONE && + obj->tiling_mode == I915_TILING_NONE && obj->map_and_fenceable && obj->base.write_domain != I915_GEM_DOMAIN_CPU) { ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file); -- cgit v0.10.2 From fc6826d1dcd65f3d1e9a5377678882e4e08f02be Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 15 Apr 2012 11:56:03 +0100 Subject: drm/i915: Refactor the deferred PM_IIR handling into a single function This function, along with the registers and deferred work hander, are all shared with SandyBridge, IvyBridge and their variants. So remove the duplicate code into a single function. Signed-off-by: Chris Wilson Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 39663f5..967b92e 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -451,6 +451,31 @@ static void snb_gt_irq_handler(struct drm_device *dev, } } +static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, + u32 pm_iir) +{ + unsigned long flags; + + /* + * IIR bits should never already be set because IMR should + * prevent an interrupt from being shown in IIR. The warning + * displays a case where we've unsafely cleared + * dev_priv->pm_iir. Although missing an interrupt of the same + * type is not a problem, it displays a problem in the logic. + * + * The mask bit in IMR is cleared by rps_work. + */ + + spin_lock_irqsave(&dev_priv->rps_lock, flags); + WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); + dev_priv->pm_iir |= pm_iir; + I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); + POSTING_READ(GEN6_PMIMR); + spin_unlock_irqrestore(&dev_priv->rps_lock, flags); + + queue_work(dev_priv->wq, &dev_priv->rps_work); +} + static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -532,16 +557,8 @@ static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS) if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) blc_event = true; - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { - unsigned long flags; - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); - } + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(GEN6_PMIIR, pm_iir); @@ -655,16 +672,8 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS) pch_irq_handler(dev); } - if (pm_iir & GEN6_PM_DEFERRED_EVENTS) { - unsigned long flags; - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); - } + if (pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); @@ -764,25 +773,8 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS) i915_handle_rps_change(dev); } - if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) { - /* - * IIR bits should never already be set because IMR should - * prevent an interrupt from being shown in IIR. The warning - * displays a case where we've unsafely cleared - * dev_priv->pm_iir. Although missing an interrupt of the same - * type is not a problem, it displays a problem in the logic. - * - * The mask bit in IMR is cleared by rps_work. - */ - unsigned long flags; - spin_lock_irqsave(&dev_priv->rps_lock, flags); - WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n"); - dev_priv->pm_iir |= pm_iir; - I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir); - POSTING_READ(GEN6_PMIMR); - spin_unlock_irqrestore(&dev_priv->rps_lock, flags); - queue_work(dev_priv->wq, &dev_priv->rps_work); - } + if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) + gen6_queue_rps_work(dev_priv, pm_iir); /* should clear PCH hotplug event before clear CPU irq */ I915_WRITE(SDEIIR, pch_iir); -- cgit v0.10.2 From 919f797a4c9c22ff5ec059744dba364dc600ece2 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Sat, 14 Apr 2012 23:01:28 -0400 Subject: SCSI: Fix error handling when no ULD is attached Commit 18a4d0a22ed6 ("[SCSI] Handle disk devices which can not process medium access commands") introduced a bug in which we would attempt to dereference the scsi driver even when the device had no ULD attached. Ensure that a driver is registered and make the driver accessor function more resilient to errors during device discovery. Reported-by: Elric Fu Reported-by: Bart Van Assche Signed-off-by: Martin K. Petersen Signed-off-by: Linus Torvalds diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 2cfcbff..386f0c5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -835,7 +835,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, scsi_eh_restore_cmnd(scmd, &ses); - if (sdrv->eh_action) + if (sdrv && sdrv->eh_action) rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); return rtn; diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 377df4a..1e11985 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -134,6 +134,9 @@ struct scsi_cmnd { static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) { + if (!cmd->request->rq_disk) + return NULL; + return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } -- cgit v0.10.2 From ebfc5b802fa76baeb4371311ff9fc27a2258d90d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 15 Apr 2012 21:40:40 +0200 Subject: PCI: Fix regression in pci_restore_state(), v3 Commit 26f41062f28d ("PCI: check for pci bar restore completion and retry") attempted to address problems with PCI BAR restoration on systems where FLR had not been completed before pci_restore_state() was called, but it did that in an utterly wrong way. First off, instead of retrying the writes for the BAR registers only, it did that for all of the PCI config space of the device, including the status register (whose value after the write quite obviously need not be the same as the written one). Second, it added arbitrary delay to pci_restore_state() even for systems where the PCI config space restoration was successful at first attempt. Finally, the mdelay(10) it added to every iteration of the writing loop was way too much of a delay for any reasonable device. All of this actually caused resume failures for some devices on Mikko's system. To fix the regression, make pci_restore_state() only retry the writes for BAR registers and only wait if the first read from the register doesn't return the written value. Additionaly, make it wait for 1 ms, instead of 10 ms, after every failing attempt to write into config space. Reported-by: Mikko Vinni Signed-off-by: Rafael J. Wysocki Signed-off-by: Linus Torvalds diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8156744..d20f133 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -967,16 +967,47 @@ pci_save_state(struct pci_dev *dev) return 0; } +static void pci_restore_config_dword(struct pci_dev *pdev, int offset, + u32 saved_val, int retry) +{ + u32 val; + + pci_read_config_dword(pdev, offset, &val); + if (val == saved_val) + return; + + for (;;) { + dev_dbg(&pdev->dev, "restoring config space at offset " + "%#x (was %#x, writing %#x)\n", offset, val, saved_val); + pci_write_config_dword(pdev, offset, saved_val); + if (retry-- <= 0) + return; + + pci_read_config_dword(pdev, offset, &val); + if (val == saved_val) + return; + + mdelay(1); + } +} + +static void pci_restore_config_space(struct pci_dev *pdev, int start, int end, + int retry) +{ + int index; + + for (index = end; index >= start; index--) + pci_restore_config_dword(pdev, 4 * index, + pdev->saved_config_space[index], + retry); +} + /** * pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with */ void pci_restore_state(struct pci_dev *dev) { - int i; - u32 val; - int tries; - if (!dev->state_saved) return; @@ -984,24 +1015,14 @@ void pci_restore_state(struct pci_dev *dev) pci_restore_pcie_state(dev); pci_restore_ats_state(dev); + pci_restore_config_space(dev, 10, 15, 0); /* * The Base Address register should be programmed before the command * register(s) */ - for (i = 15; i >= 0; i--) { - pci_read_config_dword(dev, i * 4, &val); - tries = 10; - while (tries && val != dev->saved_config_space[i]) { - dev_dbg(&dev->dev, "restoring config " - "space at offset %#x (was %#x, writing %#x)\n", - i, val, (int)dev->saved_config_space[i]); - pci_write_config_dword(dev,i * 4, - dev->saved_config_space[i]); - pci_read_config_dword(dev, i * 4, &val); - mdelay(10); - tries--; - } - } + pci_restore_config_space(dev, 4, 9, 10); + pci_restore_config_space(dev, 0, 3, 0); + pci_restore_pcix_state(dev); pci_restore_msi_state(dev); pci_restore_iov_state(dev); -- cgit v0.10.2 From 9f85550347f51c79a917b2aec04c90691c11e20a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 10 Apr 2012 12:37:42 +0100 Subject: ARM: 7359/2: smp_twd: Only wait for reprogramming on active cpus During booting of cpu1, there is a short window where cpu1 is online, but not active where cpu1 is occupied by waiting to become active. If cpu0 then decides to schedule something on cpu1 and wait for it to complete, before cpu0 has set cpu1 active, we have a deadlock. Typically it's this CPU frequency transition that happens at this time, so let's just not wait for it to happen, it will happen whenever the CPU eventually comes online instead. Cc: Peter Zijlstra Cc: stable@kernel.org Signed-off-by: Jonas Aaberg Reviewed-by: Rickard Andersson Signed-off-by: Linus Walleij Signed-off-by: Russell King diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index fef42b2..5b150af 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -118,10 +118,14 @@ static int twd_cpufreq_transition(struct notifier_block *nb, * The twd clock events must be reprogrammed to account for the new * frequency. The timer is local to a cpu, so cross-call to the * changing cpu. + * + * Only wait for it to finish, if the cpu is active to avoid + * deadlock when cpu1 is spinning on while(!cpu_active(cpu1)) during + * booting of that cpu. */ if (state == CPUFREQ_POSTCHANGE || state == CPUFREQ_RESUMECHANGE) smp_call_function_single(freqs->cpu, twd_update_frequency, - NULL, 1); + NULL, cpu_active(freqs->cpu)); return NOTIFY_OK; } -- cgit v0.10.2 From e5ab85800820edd907d3f43f285e1232f84d5a41 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 12 Apr 2012 17:15:08 +0100 Subject: ARM: 7382/1: mm: truncate memory banks to fit in 4GB space for classic MMU If a bank of memory spanning the 4GB boundary is added on a !CONFIG_LPAE kernel then we will hang early during boot since the memory bank will have wrapped around to zero. This patch truncates memory banks for !LPAE configurations when the end address is not representable in 32 bits. Acked-by: Nicolas Pitre Signed-off-by: Will Deacon Signed-off-by: Russell King diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b914113..ebfac78 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -523,7 +523,21 @@ int __init arm_add_memory(phys_addr_t start, unsigned long size) */ size -= start & ~PAGE_MASK; bank->start = PAGE_ALIGN(start); - bank->size = size & PAGE_MASK; + +#ifndef CONFIG_LPAE + if (bank->start + size < bank->start) { + printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in " + "32-bit physical address space\n", (long long)start); + /* + * To ensure bank->start + bank->size is representable in + * 32 bits, we use ULONG_MAX as the upper limit rather than 4GB. + * This means we lose a page after masking. + */ + size = ULONG_MAX - bank->start; + } +#endif + + bank->size = size & PAGE_MASK; /* * Check whether this memory region has non-zero size or -- cgit v0.10.2 From 078c04545ba56da21567728a909a496df5ff730d Mon Sep 17 00:00:00 2001 From: Jonathan Austin Date: Thu, 12 Apr 2012 17:45:25 +0100 Subject: ARM: 7384/1: ThumbEE: Disable userspace TEEHBR access for !CONFIG_ARM_THUMBEE Currently when ThumbEE is not enabled (!CONFIG_ARM_THUMBEE) the ThumbEE register states are not saved/restored at context switch. The default state of the ThumbEE Ctrl register (TEECR) allows userspace accesses to the ThumbEE Base Handler register (TEEHBR). This can cause unexpected behaviour when people use ThumbEE on !CONFIG_ARM_THUMBEE kernels, as well as allowing covert communication - eg between userspace tasks running inside chroot jails. This patch sets up TEECR in order to prevent user-space access to TEEHBR when !CONFIG_ARM_THUMBEE. In this case, tasks are sent SIGILL if they try to access TEEHBR. Cc: stable@vger.kernel.org Reviewed-by: Will Deacon Signed-off-by: Jonathan Austin Signed-off-by: Russell King diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index f1c8486..c2e2b66 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -255,6 +255,18 @@ __v7_setup: mcr p15, 0, r5, c10, c2, 0 @ write PRRR mcr p15, 0, r6, c10, c2, 1 @ write NMRR #endif +#ifndef CONFIG_ARM_THUMBEE + mrc p15, 0, r0, c0, c1, 0 @ read ID_PFR0 for ThumbEE + and r0, r0, #(0xf << 12) @ ThumbEE enabled field + teq r0, #(1 << 12) @ check if ThumbEE is present + bne 1f + mov r5, #0 + mcr p14, 6, r5, c1, c0, 0 @ Initialize TEEHBR to 0 + mrc p14, 6, r0, c0, c0, 0 @ load TEECR + orr r0, r0, #1 @ set the 1st bit in order to + mcr p14, 6, r0, c0, c0, 0 @ stop userspace TEEHBR access +1: +#endif adr r5, v7_crval ldmia r5, {r5, r6} #ifdef CONFIG_CPU_ENDIAN_BE8 -- cgit v0.10.2 From 708e5978dfee0090a27c5531ce3b017dd6d190a2 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 14 Apr 2012 21:51:32 +0100 Subject: ARM: 7386/1: jump_label: fixup for rename to static_key c5905afb0 ("static keys: Introduce 'struct static_key'...") renamed struct jump_label_key to struct static_key. Fixup ARM for this to eliminate these build warnings: include/linux/jump_label.h:113:2: warning: passing argument 1 of 'arch_static_branch' from incompatible pointer type include/asm/jump_label.h:17:82: note: expected 'struct jump_label_key *' but argument is of type 'struct static_key *' Signed-off-by: Rabin Vincent Signed-off-by: Russell King diff --git a/arch/arm/include/asm/jump_label.h b/arch/arm/include/asm/jump_label.h index 5c5ca2e..bfc198c 100644 --- a/arch/arm/include/asm/jump_label.h +++ b/arch/arm/include/asm/jump_label.h @@ -14,7 +14,7 @@ #define JUMP_LABEL_NOP "nop" #endif -static __always_inline bool arch_static_branch(struct jump_label_key *key) +static __always_inline bool arch_static_branch(struct static_key *key) { asm goto("1:\n\t" JUMP_LABEL_NOP "\n\t" -- cgit v0.10.2 From 12e993b89464707398e4209bd99983e376454985 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 15 Apr 2012 17:23:00 -0700 Subject: x86-32: fix up strncpy_from_user() sign error The 'max' range needs to be unsigned, since the size of the user address space is bigger than 2GB. We know that 'count' is positive in 'long' (that is checked in the caller), so we will truncate 'max' down to something that fits in a signed long, but before we actually do that, that comparison needs to be done in unsigned. Bug introduced in commit 92ae03f2ef99 ("x86: merge 32/64-bit versions of 'strncpy_from_user()' and speed it up"). On x86-64 you can't trigger this, since the user address space is much smaller than 63 bits, and on x86-32 it works in practice, since you would seldom hit the strncpy limits anyway. I had actually tested the corner-cases, I had only tested them on x86-64. Besides, I had only worried about the case of a pointer *close* to the end of the address space, rather than really far away from it ;) This also changes the "we hit the user-specified maximum" to return 'res', for the trivial reason that gcc seems to generate better code that way. 'res' and 'count' are the same in that case, so it really doesn't matter which one we return. Signed-off-by: Linus Torvalds diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index 57252c9..d6ae30b 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c @@ -57,7 +57,7 @@ static inline unsigned long count_bytes(unsigned long mask) * hit it), 'max' is the address space maximum (and we return * -EFAULT if we hit it). */ -static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, long max) +static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max) { long res = 0; @@ -100,7 +100,7 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long * too? If so, that's ok - we got as much as the user asked for. */ if (res >= count) - return count; + return res; /* * Nope: we hit the address space limit, and we still had more -- cgit v0.10.2 From e816b57a337ea3b755de72bec38c10c864f23015 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 15 Apr 2012 18:28:29 -0700 Subject: Linux 3.4-rc3 diff --git a/Makefile b/Makefile index 0df3d00..f6578f4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -rc2 +EXTRAVERSION = -rc3 NAME = Saber-toothed Squirrel # *DOCUMENTATION* -- cgit v0.10.2 From f681fa235f931bcf41f6c8fa22aadde9d8833eec Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Apr 2012 21:56:08 +0100 Subject: drm/i915: Export the generic, not arch specific, intel_update_watermarks() Rather than export every single architecture specific update_wm, just export the wrapper around the display vtable. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 33aaad3..fdf8c9f5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -45,7 +45,6 @@ #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) bool intel_pipe_has_type(struct drm_crtc *crtc, int type); -static void intel_update_watermarks(struct drm_device *dev); static void intel_increase_pllclock(struct drm_crtc *crtc); static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on); @@ -4820,7 +4819,7 @@ static void ironlake_update_wm(struct drm_device *dev) */ } -void sandybridge_update_wm(struct drm_device *dev) +static void sandybridge_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ @@ -5125,7 +5124,7 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, * We don't use the sprite, so we can ignore that. And on Crestline we have * to set the non-SR watermarks to 8. */ -static void intel_update_watermarks(struct drm_device *dev) +void intel_update_watermarks(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 79cabf5..8748e5e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -422,7 +422,7 @@ extern void intel_write_eld(struct drm_encoder *encoder, extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe); /* For use by IVB LP watermark workaround in intel_sprite.c */ -extern void sandybridge_update_wm(struct drm_device *dev); +extern void intel_update_watermarks(struct drm_device *dev); extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index da525b6..10dd1b6 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -112,13 +112,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, */ if (crtc_w != src_w || crtc_h != src_h) { dev_priv->sprite_scaling_enabled = true; - sandybridge_update_wm(dev); + intel_update_watermarks(dev); intel_wait_for_vblank(dev, pipe); sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; } else { dev_priv->sprite_scaling_enabled = false; /* potentially re-enable LP watermarks */ - sandybridge_update_wm(dev); + intel_update_watermarks(dev); } I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); -- cgit v0.10.2 From 8aaa81a166d80ac9bf2813984e5b4c2503d0fe08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Apr 2012 22:14:26 +0100 Subject: drm/i915/sprite: Always enable the scaler on IronLake As I do not see the output update without the scaler enabled on my i3-330m, always enable it. Signed-off-by: Chris Wilson Acked-by: Jesse Barnes Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 10dd1b6..749d043 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -219,7 +219,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe, pixel_size; - u32 dvscntr, dvsscale = 0; + u32 dvscntr, dvsscale; dvscntr = I915_READ(DVSCNTR(pipe)); @@ -275,7 +275,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size); - if (crtc_w != src_w || crtc_h != src_h) + dvsscale = 0; + if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h) dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h; I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); -- cgit v0.10.2 From 17038de5f16569a25343cf68668f3b657eafb00e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Apr 2012 22:43:42 +0100 Subject: drm/i915/dp: Flush any outstanding work to turn the VDD off As we may kick off a delayed workqueue task to switch of the VDD lines, we need to complete that task prior to turning off the panel (which itself depends upon VDD being off). v2: Don't cancel the outstanding work as this may trigger a deadlock Signed-off-by: Chris Wilson Cc: Keith Packard Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6346b29..38d097d 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1128,6 +1128,7 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); + ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */ pp = ironlake_get_pp_control(dev_priv); pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); -- cgit v0.10.2 From de4a8bd16205283e9cb746e8fbfa7f9735c039b5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 20:42:38 +0200 Subject: drm/i915: implement a media hang w/a Contrary to the other clock gating w/a in GEN6_UCGCTL1, this one is actually documented in Bspec, vol1g "GT Interface Registers [SNB]", Section 1.5.1 "UCGCTL1 - Unit Level Clock Gating Control 1". Supposedly this can prevent hangs on the media ring. Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3f7fc46..1124e4f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3893,6 +3893,7 @@ #define GEN6_UCGCTL1 0x9400 # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) +# define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) #define GEN6_UCGCTL2 0x9404 # define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2d0dc27..813cc3c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8880,7 +8880,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) | - GEN6_BLBUNIT_CLOCK_GATE_DISABLE); + GEN6_BLBUNIT_CLOCK_GATE_DISABLE | + GEN6_CSUNIT_CLOCK_GATE_DISABLE); /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock * gating disable must be set. Failure to set it results in -- cgit v0.10.2 From be901a5a1bdb13c3390110d4b9780c03018d96a0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 20:42:39 +0200 Subject: drm/i915: set w/a bit for snb pagefaults Bspec says that we need to set this: vol1c.3 "Blitter Command Streamer", Section 1.1.2.1 "GAB_CTL_REG - GAB Unit Control Register". We don't really rely on pagefaults, but who knows what this all affects. Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ac8bc1d..92acc5f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3669,7 +3669,12 @@ void i915_gem_init_ppgtt(struct drm_device *dev) pd_offset <<= 16; if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk = I915_READ(GAM_ECOCHK); + uint32_t ecochk, gab_ctl; + + gab_ctl = I915_READ(GAB_CTL); + I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); + + ecochk = I915_READ(GAM_ECOCHK); I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B); I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1124e4f..d875fb1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -127,6 +127,9 @@ #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define GAB_CTL 0x24000 +#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) + /* VGA stuff */ #define VGA_ST01_MDA 0x3ba -- cgit v0.10.2 From 48ecfa1090b65390b1cfa4c693ece6b171a407e4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 20:42:40 +0200 Subject: drm/i915: properly set ppgtt cacheability on snb For some reason snb has 2 fields to set ppgtt cacheability. This one here does not exist on gen7. This might explain why ppgtt wasn't a win on snb like on ivb - not enough pte caching. v2: Fixup rebase fail. Reviewed-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 92acc5f..aa44ff2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3669,7 +3669,10 @@ void i915_gem_init_ppgtt(struct drm_device *dev) pd_offset <<= 16; if (INTEL_INFO(dev)->gen == 6) { - uint32_t ecochk, gab_ctl; + uint32_t ecochk, gab_ctl, ecobits; + + ecobits = I915_READ(GAC_ECO_BITS); + I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B); gab_ctl = I915_READ(GAB_CTL); I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d875fb1..a9030f8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -127,6 +127,10 @@ #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) +#define GAC_ECO_BITS 0x14090 +#define ECOBITS_PPGTT_CACHE64B (3<<8) +#define ECOBITS_PPGTT_CACHE4B (0<<8) + #define GAB_CTL 0x24000 #define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) -- cgit v0.10.2 From bf97b276ca04cee9ab65ffd378fa8e6aedd71ff6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 20:42:41 +0200 Subject: drm/i915: implement w/a for incorrect guarband clipping According to Bsepc, this should be set by default, but isn't. See vo1c.4 "Render Engine Command Streamer", Section 1.1.14.3 "3D_CHICKEN3" Bspec also says that we always need to set all mask bits. v2: Add comment about the mask bits wtf. Reviewed-by: Ben Widawsky Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a9030f8..6d92054 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -497,6 +497,7 @@ */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) #define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL (1 << 5) #define MI_MODE 0x0209c # define VS_TIMER_DISPATCH (1 << 6) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 813cc3c..1a6bb61 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8897,6 +8897,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + /* Bspec says we need to always set all mask bits. */ + I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) | + _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL); + /* * According to the spec the following bits should be * set in order to enable memory self-refresh and fbc: -- cgit v0.10.2 From 009be664ecc77d58d3c27fb22347b969745a329a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 11 Apr 2012 20:42:42 +0200 Subject: drm/i915: set stc evict disable lra evict w/a Our workaround list kindly lists that this new default value needs to be updated in Bspec. Naturally, this did not happen. Acked-by: Ben Widawsky Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6d92054..02124a5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -639,6 +639,7 @@ #define CM0_MASK_SHIFT 16 #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) +#define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5) #define CM0_DEPTH_EVICT_DISABLE (1<<4) #define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_DEPTH_WRITE_DISABLE (1<<1) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1a6bb61..7506a72 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8878,6 +8878,10 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); + /* clear masked bit */ + I915_WRITE(CACHE_MODE_0, + CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT); + I915_WRITE(GEN6_UCGCTL1, I915_READ(GEN6_UCGCTL1) | GEN6_BLBUNIT_CLOCK_GATE_DISABLE | -- cgit v0.10.2 From dc04a61a0503613e17bc1405538fec52e74d4b43 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:37 -0300 Subject: drm/i915: add definition of LPT FDI port width registers v2: change bits names to align better with other bits style Reviewed-by: Rodrigo Vivi Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 02124a5..bc1a5c6 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3657,6 +3657,9 @@ #define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8) #define FDI_LINK_TRAIN_NORMAL_CPT (3<<8) #define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8) +/* LPT */ +#define FDI_PORT_WIDTH_2X_LPT (1<<19) +#define FDI_PORT_WIDTH_1X_LPT (0<<19) #define _FDI_RXA_MISC 0xf0010 #define _FDI_RXB_MISC 0xf1010 -- cgit v0.10.2 From ef4d084fae9d4719bc52f97e15e41e1602e3bc6e Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:38 -0300 Subject: drm/i915: add WRPLL divider programming bits Those are used to program the WRPLL dividers correctly for each gives frequency. Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bc1a5c6..0668815 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4191,6 +4191,10 @@ #define WRPLL_PLL_SELECT_SSC (0x01<<28) #define WRPLL_PLL_SELECT_NON_SCC (0x02<<28) #define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28) +/* WRPLL divider programming */ +#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0) +#define WRPLL_DIVIDER_POST(x) ((x)<<8) +#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16) /* Port clock selection */ #define PORT_CLK_SEL_A 0x46100 -- cgit v0.10.2 From 246bdbeb0f0fb14c4c085b6ed7edbab11afccd33 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:44 -0300 Subject: drm/i915: share forcewaking code between IVB and HSW Reviewed-by: Rodrigo Vivi Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7506a72..0ef4472 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9312,7 +9312,7 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; /* IVB configs may use multi-threaded forcewake */ - if (IS_IVYBRIDGE(dev)) { + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { u32 ecobus; /* A small trick here - if the bios hasn't configured MT forcewake, -- cgit v0.10.2 From c51ed787f6c49de7c2180c0f78e1d0e1360c7e86 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:45 -0300 Subject: drm/i915: haswell has 3 pipes as well They work differently, but the count is the same. Reviewed-by: Rodrigo Vivi Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 333b746..a813f65 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2115,7 +2115,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->error_lock); spin_lock_init(&dev_priv->rps_lock); - if (IS_IVYBRIDGE(dev)) + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; else if (IS_MOBILE(dev) || !IS_GEN2(dev)) dev_priv->num_pipe = 2; -- cgit v0.10.2 From 0cd83aa9a6aba8fec7d94d4fd5302172e14cebf7 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:48 -0300 Subject: drm/i915: share IVB cursor routine with Haswell Reviewed-by: Rodrigo Vivi Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0ef4472..c67eb77 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6770,7 +6770,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, if (!visible && !intel_crtc->cursor_visible) return; - if (IS_IVYBRIDGE(dev)) { + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { I915_WRITE(CURPOS_IVB(pipe), pos); ivb_update_cursor(crtc, base); } else { -- cgit v0.10.2 From 83de97c885b633ab6d12346a406911fadeb85f8c Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Fri, 13 Apr 2012 17:08:54 -0300 Subject: drm/i915: disable rc6 on haswell for now This needs proper enablement to avoid machine hangs, so let's just avoid it for now. Reviewed-by: Rodrigo Vivi Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c67eb77..02e9932 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8585,6 +8585,10 @@ int intel_enable_rc6(const struct drm_device *dev) if (INTEL_INFO(dev)->gen == 5) return 0; + /* Sorry Haswell, no RC6 for you for now. */ + if (IS_HASWELL(dev)) + return 0; + /* * Disable rc6 on Sandybridge */ -- cgit v0.10.2 From 446f254566ea8911c9e19c7bc8a162fc0e53cf31 Mon Sep 17 00:00:00 2001 From: Armin Reese Date: Fri, 30 Mar 2012 16:20:16 -0700 Subject: drm/i915: Mask reserved bits in display/sprite address registers The purpose of this patch is to avoid zeroing the lower 12 reserved bits of surface base address registers (framebuffer & sprite). There are bits in that range that may occasionally be set by BIOS or by other components. Signed-off-by: Armin Reese Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 967b92e..ab023ca 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1368,7 +1368,8 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) obj = work->pending_flip_obj; if (INTEL_INFO(dev)->gen >= 4) { int dspsurf = DSPSURF(intel_crtc->plane); - stall_detected = I915_READ(dspsurf) == obj->gtt_offset; + stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) == + obj->gtt_offset; } else { int dspaddr = DSPADDR(intel_crtc->plane); stall_detected = I915_READ(dspaddr) == (obj->gtt_offset + diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0668815..d093dba 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2869,6 +2869,13 @@ #define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF) #define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF) +/* Display/Sprite base address macros */ +#define DISP_BASEADDR_MASK (0xfffff000) +#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK) +#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK) +#define I915_MODIFY_DISPBASE(reg, gfx_addr) \ + (I915_WRITE(reg, gfx_addr | I915_LO_DISPBASE(I915_READ(reg)))) + /* VBIOS flags */ #define SWF00 0x71410 #define SWF01 0x71414 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 02e9932..eb7ebf4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2236,7 +2236,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb, Start, Offset, x, y, fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(DSPSURF(plane), Start); + I915_MODIFY_DISPBASE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); } else @@ -2316,7 +2316,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc, DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n", Start, Offset, x, y, fb->pitches[0]); I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); - I915_WRITE(DSPSURF(plane), Start); + I915_MODIFY_DISPBASE(DSPSURF(plane), Start); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPADDR(plane), Offset); POSTING_READ(reg); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 987800a..fbf03b9 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -133,7 +133,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); - I915_WRITE(SPRSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset); POSTING_READ(SPRSURF(pipe)); } @@ -149,7 +149,7 @@ ivb_disable_plane(struct drm_plane *plane) /* Can't leave the scaler enabled... */ I915_WRITE(SPRSCALE(pipe), 0); /* Activate double buffered register update */ - I915_WRITE(SPRSURF(pipe), 0); + I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); } @@ -291,7 +291,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w); I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); - I915_WRITE(DVSSURF(pipe), obj->gtt_offset); + I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset); POSTING_READ(DVSSURF(pipe)); } @@ -307,7 +307,7 @@ ilk_disable_plane(struct drm_plane *plane) /* Disable the scaler */ I915_WRITE(DVSSCALE(pipe), 0); /* Flush double buffered register updates */ - I915_WRITE(DVSSURF(pipe), 0); + I915_MODIFY_DISPBASE(DVSSURF(pipe), 0); POSTING_READ(DVSSURF(pipe)); } -- cgit v0.10.2 From df0323c42ac35f81b49e25fe04e8e52b9c6f6467 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Tue, 17 Apr 2012 15:06:33 -0700 Subject: drm/i915: IBX+ doesn't have separate vsync/hsync controls on the VGA DAC When the PCH split occurred, hw dropped support for separate hsync and vsync disable in the VGA DAC. So add a PCH specific DPMS function that just uses the port enable bit for controlling DPMS states. Before this fix, when anything other than a full DPMS off occurred, the VGA port would be left enabled and scanning out while all the other heads would turn off as expected. v2: duplicate encoder helper vtable into pch and gmch versions (Daniel) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48491 Reviewed-by: Chris Wilson Signed-off-by: Jesse Barnes [danvet: s/intel_crt_dpms/gmch_crt_dpms as suggested by Chris.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 70b0f1a..0976137 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -55,18 +55,36 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector) struct intel_crt, base); } -static void intel_crt_dpms(struct drm_encoder *encoder, int mode) +static void pch_crt_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 temp, reg; + u32 temp; - if (HAS_PCH_SPLIT(dev)) - reg = PCH_ADPA; - else - reg = ADPA; + temp = I915_READ(PCH_ADPA); + temp &= ~ADPA_DAC_ENABLE; + + switch (mode) { + case DRM_MODE_DPMS_ON: + temp |= ADPA_DAC_ENABLE; + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + /* Just leave port enable cleared */ + break; + } + + I915_WRITE(PCH_ADPA, temp); +} - temp = I915_READ(reg); +static void gmch_crt_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 temp; + + temp = I915_READ(ADPA); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp &= ~ADPA_DAC_ENABLE; @@ -85,7 +103,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) break; } - I915_WRITE(reg, temp); + I915_WRITE(ADPA, temp); } static int intel_crt_mode_valid(struct drm_connector *connector, @@ -516,12 +534,20 @@ static void intel_crt_reset(struct drm_connector *connector) * Routines for controlling stuff on the analog port */ -static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = { - .dpms = intel_crt_dpms, +static const struct drm_encoder_helper_funcs pch_encoder_funcs = { + .mode_fixup = intel_crt_mode_fixup, + .prepare = intel_encoder_prepare, + .commit = intel_encoder_commit, + .mode_set = intel_crt_mode_set, + .dpms = pch_crt_dpms, +}; + +static const struct drm_encoder_helper_funcs gmch_encoder_funcs = { .mode_fixup = intel_crt_mode_fixup, .prepare = intel_encoder_prepare, .commit = intel_encoder_commit, .mode_set = intel_crt_mode_set, + .dpms = gmch_crt_dpms, }; static const struct drm_connector_funcs intel_crt_connector_funcs = { @@ -567,6 +593,7 @@ void intel_crt_init(struct drm_device *dev) struct intel_crt *crt; struct intel_connector *intel_connector; struct drm_i915_private *dev_priv = dev->dev_private; + const struct drm_encoder_helper_funcs *encoder_helper_funcs; /* Skip machines without VGA that falsely report hotplug events */ if (dmi_check_system(intel_no_crt)) @@ -602,7 +629,12 @@ void intel_crt_init(struct drm_device *dev) connector->interlace_allowed = 1; connector->doublescan_allowed = 0; - drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs); + if (HAS_PCH_SPLIT(dev)) + encoder_helper_funcs = &pch_encoder_funcs; + else + encoder_helper_funcs = &gmch_encoder_funcs; + + drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_sysfs_connector_add(connector); -- cgit v0.10.2 From c43b5634037ff00c83cde4ab7fc5e46831c846ef Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 16 Apr 2012 14:07:40 -0700 Subject: drm/i915: [sparse] trivial sparse fixes This should contain all the changes which require no thought to make sparse happy. Signed-off-by: Ben Widawsky Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 97c9630..35462df 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1832,7 +1832,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) return 0; } -int i915_forcewake_release(struct inode *inode, struct file *file) +static int i915_forcewake_release(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 422f424..303cee7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1128,8 +1128,10 @@ extern void i915_driver_preclose(struct drm_device *dev, extern void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv); extern int i915_driver_device_is_agp(struct drm_device * dev); +#ifdef CONFIG_COMPAT extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif extern int i915_emit_box(struct drm_device *dev, struct drm_clip_rect *box, int DR1, int DR4); diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 13b0289..0e72abb 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -34,6 +34,7 @@ #include "drmP.h" #include "drm.h" #include "i915_drm.h" +#include "i915_drv.h" typedef struct _drm_i915_batchbuffer32 { int start; /* agp offset */ @@ -181,7 +182,7 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd, (unsigned long)request); } -drm_ioctl_compat_t *i915_compat_ioctls[] = { +static drm_ioctl_compat_t *i915_compat_ioctls[] = { [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, [DRM_I915_GETPARAM] = compat_i915_getparam, @@ -189,6 +190,7 @@ drm_ioctl_compat_t *i915_compat_ioctls[] = { [DRM_I915_ALLOC] = compat_i915_alloc }; +#ifdef CONFIG_COMPAT /** * Called whenever a 32-bit process running under a 64-bit kernel * performs an ioctl on /dev/dri/card. @@ -217,3 +219,4 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; } +#endif diff --git a/drivers/gpu/drm/i915/i915_trace_points.c b/drivers/gpu/drm/i915/i915_trace_points.c index ead876e..f1df2bd 100644 --- a/drivers/gpu/drm/i915/i915_trace_points.c +++ b/drivers/gpu/drm/i915/i915_trace_points.c @@ -7,5 +7,7 @@ #include "i915_drv.h" +#ifndef __CHECKER__ #define CREATE_TRACE_POINTS #include "i915_trace.h" +#endif diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index f152b2a..f413899 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -9,6 +9,7 @@ #include #include "drmP.h" +#include "i915_drv.h" #define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb7ebf4..78179e0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -9503,7 +9503,7 @@ struct intel_quirk { void (*hook)(struct drm_device *dev); }; -struct intel_quirk intel_quirks[] = { +static struct intel_quirk intel_quirks[] = { /* HP Mini needs pipe A force quirk (LP: #322104) */ { 0x27ae, 0x103c, 0x361a, quirk_pipea_force }, diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 19ecd78..71ef289 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -94,7 +94,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mutex_lock(&dev->struct_mutex); /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, false); + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9d4e5f0..492812d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -891,8 +891,8 @@ err: return ret; } -int intel_init_ring_buffer(struct drm_device *dev, - struct intel_ring_buffer *ring) +static int intel_init_ring_buffer(struct drm_device *dev, + struct intel_ring_buffer *ring) { struct drm_i915_gem_object *obj; int ret; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 6898145..aa1a0d5 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1258,7 +1258,7 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector) dev_priv->crt_ddc_pin)); } -enum drm_connector_status +static enum drm_connector_status intel_sdvo_tmds_sink_detect(struct drm_connector *connector) { struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); -- cgit v0.10.2 From 3bf3f452362841404fe6d4589883f9471842ef8b Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Mon, 16 Apr 2012 14:07:41 -0700 Subject: drm/i915: [sparse] don't use variable size arrays Sparse doesn't like: "error: bad constant expression" Signed-off-by: Ben Widawsky [danvet: apply s/drm_malloc_ab/kcalloc bikeshed. If it's small enough for the stack, it's small enough for kmalloc.] Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index aa1a0d5..c330efd 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -443,9 +443,17 @@ static const char *cmd_status_names[] = { static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) { - u8 buf[args_len*2 + 2], status; - struct i2c_msg msgs[args_len + 3]; - int i, ret; + u8 *buf, status; + struct i2c_msg *msgs; + int i, ret = true; + + buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL); + if (!buf) + return false; + + msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL); + if (!msgs) + return false; intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len); @@ -479,15 +487,19 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd, ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3); if (ret < 0) { DRM_DEBUG_KMS("I2c transfer returned %d\n", ret); - return false; + ret = false; + goto out; } if (ret != i+3) { /* failure in I2C transfer */ DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3); - return false; + ret = false; } - return true; +out: + kfree(msgs); + kfree(buf); + return ret; } static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, -- cgit v0.10.2 From 7b09638f45379fd1f8cbcb0a95ea2b11f0c8b850 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Apr 2012 09:55:51 +0100 Subject: drm/i915: Always flush tiling changes before accessing through the GTT As we defer updating the fence register from set-tiling to the point of use, we need to declare every access through the GTT as either fenced or unfenced. This patches fixes an old bug in the execbuffer relocation processing which could conceivably be hit by a pathological userspace. Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2a24d0c..1a0d54f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -381,7 +381,11 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, uint32_t __iomem *reloc_entry; void __iomem *reloc_page; - ret = i915_gem_object_set_to_gtt_domain(obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + return ret; + + ret = i915_gem_object_put_fence(obj); if (ret) return ret; -- cgit v0.10.2 From 65f5687603ea6ede1cb01b3d6c16a8c1fac88541 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 16:38:12 +0100 Subject: drm/i915: Replace open coded MI_BATCH_GTT The (2<<6) virtual memory space selector harks back to gen3 and is mandatory given our use of GTT space for batchbuffers. On gen4+, use of the GTT became mandatory and bit6 marked reserved. However the code must now explicitly set (1<<7), which conveniently is also (2<<6). To clarify the meaning for future readers, replace the open coded (2<<6) with MI_BATCH_GTT. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d093dba..0d3b97f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -231,6 +231,7 @@ #define MI_BATCH_NON_SECURE (1) #define MI_BATCH_NON_SECURE_I965 (1<<8) #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) +#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */ #define MI_SEMAPHORE_GLOBAL_GTT (1<<22) #define MI_SEMAPHORE_UPDATE (1<<21) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 492812d..4ae651b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -786,7 +786,8 @@ i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length) return ret; intel_ring_emit(ring, - MI_BATCH_BUFFER_START | (2 << 6) | + MI_BATCH_BUFFER_START | + MI_BATCH_GTT | MI_BATCH_NON_SECURE_I965); intel_ring_emit(ring, offset); intel_ring_advance(ring); @@ -823,7 +824,7 @@ i915_dispatch_execbuffer(struct intel_ring_buffer *ring, if (ret) return ret; - intel_ring_emit(ring, MI_BATCH_BUFFER_START | (2 << 6)); + intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT); intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE); intel_ring_advance(ring); -- cgit v0.10.2 From a1e969e0332de7a430e62822cee8f2ec8d83cd7c Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Sat, 14 Apr 2012 18:41:32 -0700 Subject: drm/i915: [GEN7] Use HW scheduler for fixed function shaders This originally started as a patch from Bernard as a way of simply setting the VS scheduler. After submitting the RFC patch, we decided to also modify the DS scheduler. To be most explicit, I've made the patch explicitly set all scheduler modes, and included the defines for other modes (in case someone feels frisky later). The rest of the story gets a bit weird. The first version of the patch showed an almost unbelievable performance improvement. Since rebasing my branch it appears the performance improvement has gone, unfortunately. But setting these bits seem to be the right thing to do given that the docs describe corruption that can occur with the default settings. In summary, I am seeing no more perf improvements (or regressions) in my limited testing, but we believe this should be set to prevent rendering corruption, therefore cc stable. v1: Clear bit 4 also (Ken + Eugeni) Do a full clear + set of the bits we want (Me). Cc: Bernard Kilarski Cc: stable Reviewed-by (RFC): Kenneth Graunke Signed-off-by: Ben Widawsky Reviewed-by: Eugeni Dodonov Reviewed-by: Kenneth Graunke Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0d3b97f..5ac9837 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -692,6 +692,21 @@ #define GEN6_BSD_RNCID 0x12198 +#define GEN7_FF_THREAD_MODE 0x20a0 +#define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN7_FF_TS_SCHED_HS1 (0x5<<16) +#define GEN7_FF_TS_SCHED_HS0 (0x3<<16) +#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) +#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_SCHED_HS1 (0x5<<12) +#define GEN7_FF_VS_SCHED_HS0 (0x3<<12) +#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ +#define GEN7_FF_VS_SCHED_HW (0x0<<12) +#define GEN7_FF_DS_SCHED_HS1 (0x5<<4) +#define GEN7_FF_DS_SCHED_HS0 (0x3<<4) +#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */ +#define GEN7_FF_DS_SCHED_HW (0x0<<4) + /* * Framebuffer compression (915+ only) */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 78179e0..96fc467 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8937,6 +8937,18 @@ static void gen6_init_clock_gating(struct drm_device *dev) } } +static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) +{ + uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); + + reg &= ~GEN7_FF_SCHED_MASK; + reg |= GEN7_FF_TS_SCHED_HW; + reg |= GEN7_FF_VS_SCHED_HW; + reg |= GEN7_FF_DS_SCHED_HW; + + I915_WRITE(GEN7_FF_THREAD_MODE, reg); +} + static void ivybridge_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -8981,6 +8993,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) DISPPLANE_TRICKLE_FEED_DISABLE); intel_flush_display_plane(dev_priv, pipe); } + + gen7_setup_fixed_func_scheduler(dev_priv); } static void valleyview_init_clock_gating(struct drm_device *dev) -- cgit v0.10.2 From 83d4092b0381e5dd6f312b2ec57121dcf0fcbade Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 19:35:53 +0100 Subject: drm/i915: Unpin the flip target if we fail to queue the flip Signed-off-by: Chris Wilson Cc: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 96fc467..16930c5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7658,14 +7658,14 @@ static int intel_gen2_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) - goto out; + goto err_unpin; /* Can't queue multiple flips, so wait for the previous * one to finish before executing the next. @@ -7682,7 +7682,11 @@ static int intel_gen2_queue_flip(struct drm_device *dev, OUT_RING(obj->gtt_offset + offset); OUT_RING(0); /* aux display base address, unused */ ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7699,14 +7703,14 @@ static int intel_gen3_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; /* Offset into the new buffer for cases of shared fbs between CRTCs */ offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8; ret = BEGIN_LP_RING(6); if (ret) - goto out; + goto err_unpin; if (intel_crtc->plane) flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; @@ -7721,7 +7725,11 @@ static int intel_gen3_queue_flip(struct drm_device *dev, OUT_RING(MI_NOOP); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7737,11 +7745,11 @@ static int intel_gen4_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; ret = BEGIN_LP_RING(4); if (ret) - goto out; + goto err_unpin; /* i965+ uses the linear or tiled offsets from the * Display Registers (which do not change across a page-flip) @@ -7760,7 +7768,11 @@ static int intel_gen4_queue_flip(struct drm_device *dev, pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7776,11 +7788,11 @@ static int intel_gen6_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv)); if (ret) - goto out; + goto err; ret = BEGIN_LP_RING(4); if (ret) - goto out; + goto err_unpin; OUT_RING(MI_DISPLAY_FLIP | MI_DISPLAY_FLIP_PLANE(intel_crtc->plane)); @@ -7791,7 +7803,11 @@ static int intel_gen6_queue_flip(struct drm_device *dev, pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff; OUT_RING(pf | pipesrc); ADVANCE_LP_RING(); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } @@ -7813,18 +7829,22 @@ static int intel_gen7_queue_flip(struct drm_device *dev, ret = intel_pin_and_fence_fb_obj(dev, obj, ring); if (ret) - goto out; + goto err; ret = intel_ring_begin(ring, 4); if (ret) - goto out; + goto err_unpin; intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19)); intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode)); intel_ring_emit(ring, (obj->gtt_offset)); intel_ring_emit(ring, (MI_NOOP)); intel_ring_advance(ring); -out: + return 0; + +err_unpin: + intel_unpin_fb_obj(obj); +err: return ret; } -- cgit v0.10.2 From 6b8e6ed02a5b06435a6b1c7ddff08c11f3e2d5d1 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:08:19 +0100 Subject: drm/i915: intel_update_fbc() requires struct_mutex, so no longer atomic As we need to manipulate our device structure and allocate queue a task, it is no longer a simple atomic operation and cannot be performed along the atomic modeset paths. Instead make sure that we disable FBC (which must be therefore kept as a set of simple register writes) when performing the atomic modeset and leave the heavy-weight intel_update_fbc() for the normal modeset. Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16930c5..a1a8080 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2331,16 +2331,12 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - ret = dev_priv->display.update_plane(crtc, fb, x, y); - if (ret) - return ret; - intel_update_fbc(dev); + if (dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); intel_increase_pllclock(crtc); - return 0; + return dev_priv->display.update_plane(crtc, fb, x, y); } static int @@ -2375,6 +2371,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_master_private *master_priv; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -2411,8 +2408,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (old_fb) intel_finish_fb(old_fb); - ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, - LEAVE_ATOMIC_MODE_SET); + ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); @@ -2425,6 +2421,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj); } + intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); if (!dev->primary->master) -- cgit v0.10.2 From 46f0f8d120c4afae53a5670bf3ac80a928340ff3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 18 Apr 2012 11:12:11 +0100 Subject: drm/i915: Don't set a MBZ bit in gen2/3 MI_FLUSH On gen2 MI_EXE_FLUSH is actually an AGP flush bit and on gen3 marked as reserved. On both it is documented as being must-be-zero. So obey the documentation, and separate the gen2 flush into its own little routine and share with gen3. This means that we can rename the existing render_ring_flush() to reflect the generation from which it first applies and remove the code for handling earlier generations from it. v2: Applies to gen3 as well v3: Make it compile and improve the commit message. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 4ae651b..6f610f2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -53,9 +53,35 @@ static inline int ring_space(struct intel_ring_buffer *ring) } static int -render_ring_flush(struct intel_ring_buffer *ring, - u32 invalidate_domains, - u32 flush_domains) +gen2_render_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + u32 cmd; + int ret; + + cmd = MI_FLUSH; + if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + cmd |= MI_NO_WRITE_FLUSH; + + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= MI_READ_FLUSH; + + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; + + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); + + return 0; +} + +static int +gen4_render_ring_flush(struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) { struct drm_device *dev = ring->dev; u32 cmd; @@ -90,17 +116,8 @@ render_ring_flush(struct intel_ring_buffer *ring, */ cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) + if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) cmd &= ~MI_NO_WRITE_FLUSH; - if (INTEL_INFO(dev)->gen < 4) { - /* - * On the 965, the sampler cache always gets flushed - * and this bit is reserved. - */ - if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) - cmd |= MI_READ_FLUSH; - } if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) cmd |= MI_EXE_FLUSH; @@ -1281,14 +1298,17 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->signal_mbox[1] = GEN6_BRSYNC; } else if (IS_GEN5(dev)) { ring->add_request = pc_render_add_request; - ring->flush = render_ring_flush; + ring->flush = gen4_render_ring_flush; ring->get_seqno = pc_render_get_seqno; ring->irq_get = gen5_ring_get_irq; ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; } else { ring->add_request = i9xx_add_request; - ring->flush = render_ring_flush; + if (INTEL_INFO(dev)->gen < 4) + ring->flush = gen2_render_ring_flush; + else + ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; ring->irq_get = i9xx_ring_get_irq; ring->irq_put = i9xx_ring_put_irq; @@ -1333,7 +1353,10 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) * gem_init ioctl returns with -ENODEV). Hence we do not need to set up * the special gen5 functions. */ ring->add_request = i9xx_add_request; - ring->flush = render_ring_flush; + if (INTEL_INFO(dev)->gen < 4) + ring->flush = gen2_render_ring_flush; + else + ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; ring->irq_get = i9xx_ring_get_irq; ring->irq_put = i9xx_ring_put_irq; -- cgit v0.10.2 From 0f91128d88bbb8b0a8e7bb93df2c40680871d45a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 10:05:38 +0100 Subject: drm/i915: Wait for all pending operations to the fb before disabling the pipe During modeset we have to disable the pipe to reconfigure its timings and maybe its size. Userspace may have queued up command buffers that depend upon the pipe running in a certain configuration and so the commands may become confused across the modeset. At the moment, we use a less than satisfactory kick-scanline-waits should the GPU hang during the modeset. It should be more reliable to wait for the pending operations to complete first, even though we still have a window for userspace to submit a broken command buffer during the modeset. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a1a8080..39eb3e8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3014,16 +3014,14 @@ static void intel_clear_scanline_wait(struct drm_device *dev) static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { - struct drm_i915_gem_object *obj; - struct drm_i915_private *dev_priv; + struct drm_device *dev = crtc->dev; if (crtc->fb == NULL) return; - obj = to_intel_framebuffer(crtc->fb)->obj; - dev_priv = crtc->dev->dev_private; - wait_event(dev_priv->pending_flip_queue, - atomic_read(&obj->pending_flip) == 0); + mutex_lock(&dev->struct_mutex); + intel_finish_fb(crtc->fb); + mutex_unlock(&dev->struct_mutex); } static bool intel_crtc_driving_pch(struct drm_crtc *crtc) @@ -3485,23 +3483,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; struct drm_device *dev = crtc->dev; - /* Flush any pending WAITs before we disable the pipe. Note that - * we need to drop the struct_mutex in order to acquire it again - * during the lowlevel dpms routines around a couple of the - * operations. It does not look trivial nor desirable to move - * that locking higher. So instead we leave a window for the - * submission of further commands on the fb before we can actually - * disable it. This race with userspace exists anyway, and we can - * only rely on the pipe being disabled by userspace after it - * receives the hotplug notification and has flushed any pending - * batches. - */ - if (crtc->fb) { - mutex_lock(&dev->struct_mutex); - intel_finish_fb(crtc->fb); - mutex_unlock(&dev->struct_mutex); - } - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); -- cgit v0.10.2 From 06d9813157cca181e3ca0aff769767669afe8adf Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:24 +0100 Subject: drm/i915: Remove the pipelined parameter from get_fence() We never succeeded in getting pipelined fencing to work (unresolved spurious GPU hangs), so begin the process of dismantling and removal the broken code. Step 1 is the removal of the pipeline parameter to get_fence(). Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 303cee7..016ebc9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1257,8 +1257,7 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring); -int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined); +int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); static inline bool diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index aa44ff2..40e0808 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1079,7 +1079,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(obj, obj->cache_level); - ret = i915_gem_object_get_fence(obj, NULL); + ret = i915_gem_object_get_fence(obj); if (ret) goto unlock; @@ -2453,7 +2453,6 @@ i915_find_fence_reg(struct drm_device *dev, /** * i915_gem_object_get_fence - set up fencing for an object * @obj: object to map through a fence reg - * @pipelined: ring on which to queue the change, or NULL for CPU access * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. @@ -2466,11 +2465,11 @@ i915_find_fence_reg(struct drm_device *dev, * For an untiled surface, this removes any existing fence. */ int -i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +i915_gem_object_get_fence(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ring_buffer *pipelined; struct drm_i915_fence_reg *reg; int ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1a0d54f..68ec013 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -534,7 +534,7 @@ pin_and_fence_object(struct drm_i915_gem_object *obj, if (has_fenced_gpu_access) { if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) { - ret = i915_gem_object_get_fence(obj, ring); + ret = i915_gem_object_get_fence(obj); if (ret) goto err_unpin; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 39eb3e8..1f844c5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2151,7 +2151,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, * framebuffer compression. For simplicity, we always install * a fence as the cost is not that onerous. */ - ret = i915_gem_object_get_fence(obj, pipelined); + ret = i915_gem_object_get_fence(obj); if (ret) goto err_unpin; -- cgit v0.10.2 From a360bb1a83279243a0945a0e646fd6c66521864e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:25 +0100 Subject: drm/i915: Remove fence pipelining Step 2 is then to replace the pipelined parameter with NULL and perform constant folding to remove dead code. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 40e0808..5a9d90f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2166,8 +2166,7 @@ int i915_gpu_idle(struct drm_device *dev, bool do_retire) return 0; } -static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2185,26 +2184,12 @@ static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj, val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 6); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8); - intel_ring_emit(pipelined, (u32)val); - intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8 + 4); - intel_ring_emit(pipelined, (u32)(val >> 32)); - intel_ring_advance(pipelined); - } else - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val); + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val); return 0; } -static int i965_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static int i965_write_fence_reg(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2220,26 +2205,12 @@ static int i965_write_fence_reg(struct drm_i915_gem_object *obj, val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 6); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8); - intel_ring_emit(pipelined, (u32)val); - intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8 + 4); - intel_ring_emit(pipelined, (u32)(val >> 32)); - intel_ring_advance(pipelined); - } else - I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val); + I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val); return 0; } -static int i915_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static int i915_write_fence_reg(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2276,24 +2247,12 @@ static int i915_write_fence_reg(struct drm_i915_gem_object *obj, else fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 4); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(pipelined, fence_reg); - intel_ring_emit(pipelined, val); - intel_ring_advance(pipelined); - } else - I915_WRITE(fence_reg, val); + I915_WRITE(fence_reg, val); return 0; } -static int i830_write_fence_reg(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +static int i830_write_fence_reg(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; @@ -2319,18 +2278,7 @@ static int i830_write_fence_reg(struct drm_i915_gem_object *obj, val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; - if (pipelined) { - int ret = intel_ring_begin(pipelined, 4); - if (ret) - return ret; - - intel_ring_emit(pipelined, MI_NOOP); - intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(pipelined, FENCE_REG_830_0 + regnum*4); - intel_ring_emit(pipelined, val); - intel_ring_advance(pipelined); - } else - I915_WRITE(FENCE_REG_830_0 + regnum * 4, val); + I915_WRITE(FENCE_REG_830_0 + regnum * 4, val); return 0; } @@ -2341,8 +2289,7 @@ static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno) } static int -i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined) +i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) { int ret; @@ -2357,7 +2304,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj, obj->fenced_gpu_access = false; } - if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) { + if (obj->last_fenced_seqno && NULL != obj->last_fenced_ring) { if (!ring_passed_seqno(obj->last_fenced_ring, obj->last_fenced_seqno)) { ret = i915_wait_request(obj->last_fenced_ring, @@ -2388,7 +2335,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) if (obj->tiling_mode) i915_gem_release_mmap(obj); - ret = i915_gem_object_flush_fence(obj, NULL); + ret = i915_gem_object_flush_fence(obj); if (ret) return ret; @@ -2406,8 +2353,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) } static struct drm_i915_fence_reg * -i915_find_fence_reg(struct drm_device *dev, - struct intel_ring_buffer *pipelined) +i915_find_fence_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_fence_reg *reg, *first, *avail; @@ -2436,9 +2382,7 @@ i915_find_fence_reg(struct drm_device *dev, if (first == NULL) first = reg; - if (!pipelined || - !reg->obj->last_fenced_ring || - reg->obj->last_fenced_ring == pipelined) { + if (reg->obj->last_fenced_ring == NULL) { avail = reg; break; } @@ -2469,67 +2413,46 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *pipelined; struct drm_i915_fence_reg *reg; int ret; if (obj->tiling_mode == I915_TILING_NONE) return i915_gem_object_put_fence(obj); - /* XXX disable pipelining. There are bugs. Shocking. */ - pipelined = NULL; - /* Just update our place in the LRU if our fence is getting reused. */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); if (obj->tiling_changed) { - ret = i915_gem_object_flush_fence(obj, pipelined); + ret = i915_gem_object_flush_fence(obj); if (ret) return ret; - if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) - pipelined = NULL; - - if (pipelined) { - reg->setup_seqno = - i915_gem_next_request_seqno(pipelined); - obj->last_fenced_seqno = reg->setup_seqno; - obj->last_fenced_ring = pipelined; - } - goto update; } - if (!pipelined) { - if (reg->setup_seqno) { - if (!ring_passed_seqno(obj->last_fenced_ring, - reg->setup_seqno)) { - ret = i915_wait_request(obj->last_fenced_ring, - reg->setup_seqno, - true); - if (ret) - return ret; - } - - reg->setup_seqno = 0; + if (reg->setup_seqno) { + if (!ring_passed_seqno(obj->last_fenced_ring, + reg->setup_seqno)) { + ret = i915_wait_request(obj->last_fenced_ring, + reg->setup_seqno, + true); + if (ret) + return ret; } - } else if (obj->last_fenced_ring && - obj->last_fenced_ring != pipelined) { - ret = i915_gem_object_flush_fence(obj, pipelined); - if (ret) - return ret; + + reg->setup_seqno = 0; } return 0; } - reg = i915_find_fence_reg(dev, pipelined); + reg = i915_find_fence_reg(dev); if (reg == NULL) return -EDEADLK; - ret = i915_gem_object_flush_fence(obj, pipelined); + ret = i915_gem_object_flush_fence(obj); if (ret) return ret; @@ -2541,31 +2464,25 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) if (old->tiling_mode) i915_gem_release_mmap(old); - ret = i915_gem_object_flush_fence(old, pipelined); + ret = i915_gem_object_flush_fence(old); if (ret) { drm_gem_object_unreference(&old->base); return ret; } - if (old->last_fenced_seqno == 0 && obj->last_fenced_seqno == 0) - pipelined = NULL; - old->fence_reg = I915_FENCE_REG_NONE; - old->last_fenced_ring = pipelined; - old->last_fenced_seqno = - pipelined ? i915_gem_next_request_seqno(pipelined) : 0; + old->last_fenced_ring = NULL; + old->last_fenced_seqno = 0; drm_gem_object_unreference(&old->base); - } else if (obj->last_fenced_seqno == 0) - pipelined = NULL; + } reg->obj = obj; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); obj->fence_reg = reg - dev_priv->fence_regs; - obj->last_fenced_ring = pipelined; + obj->last_fenced_ring = NULL; - reg->setup_seqno = - pipelined ? i915_gem_next_request_seqno(pipelined) : 0; + reg->setup_seqno = 0; obj->last_fenced_seqno = reg->setup_seqno; update: @@ -2573,17 +2490,17 @@ update: switch (INTEL_INFO(dev)->gen) { case 7: case 6: - ret = sandybridge_write_fence_reg(obj, pipelined); + ret = sandybridge_write_fence_reg(obj); break; case 5: case 4: - ret = i965_write_fence_reg(obj, pipelined); + ret = i965_write_fence_reg(obj); break; case 3: - ret = i915_write_fence_reg(obj, pipelined); + ret = i915_write_fence_reg(obj); break; case 2: - ret = i830_write_fence_reg(obj, pipelined); + ret = i830_write_fence_reg(obj); break; } -- cgit v0.10.2 From 69963e7c76743bd9e8ef559f955165dd85d9ba72 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:26 +0100 Subject: drm/i915: Remove unused ring->setup_seqno As we now no longer track a pipelined fence change, we never use ring->setup_seqno and can kill it. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 016ebc9..6a504f9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -146,7 +146,6 @@ struct drm_i915_master_private { struct drm_i915_fence_reg { struct list_head lru_list; struct drm_i915_gem_object *obj; - uint32_t setup_seqno; int pin_count; }; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5a9d90f..3a091f5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2432,19 +2432,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) goto update; } - if (reg->setup_seqno) { - if (!ring_passed_seqno(obj->last_fenced_ring, - reg->setup_seqno)) { - ret = i915_wait_request(obj->last_fenced_ring, - reg->setup_seqno, - true); - if (ret) - return ret; - } - - reg->setup_seqno = 0; - } - return 0; } @@ -2482,9 +2469,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) obj->fence_reg = reg - dev_priv->fence_regs; obj->last_fenced_ring = NULL; - reg->setup_seqno = 0; - obj->last_fenced_seqno = reg->setup_seqno; - update: obj->tiling_changed = false; switch (INTEL_INFO(dev)->gen) { @@ -2543,7 +2527,6 @@ i915_gem_clear_fence_reg(struct drm_device *dev, list_del_init(®->lru_list); reg->obj = NULL; - reg->setup_seqno = 0; reg->pin_count = 0; } -- cgit v0.10.2 From 1c293ea3b1d1c72f1fc5f398e03232d8d302bd23 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:27 +0100 Subject: drm/i915: Discard the unused obj->last_fenced_ring As we now never pipeline a fence update, obj->last_fenced_ring is always the same as the obj->ring whenever obj->last_fenced_seqno is active, so remove it. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6a504f9..69e1539 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -930,13 +930,12 @@ struct drm_i915_gem_object { */ uint32_t gtt_offset; - /** Breadcrumb of last rendering to the buffer. */ - uint32_t last_rendering_seqno; struct intel_ring_buffer *ring; + /** Breadcrumb of last rendering to the buffer. */ + uint32_t last_rendering_seqno; /** Breadcrumb of last fenced GPU access to the buffer. */ uint32_t last_fenced_seqno; - struct intel_ring_buffer *last_fenced_ring; /** Current tiling stride for the object, if it's tiled. */ uint32_t stride; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3a091f5..b25d229 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1398,7 +1398,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, if (obj->fenced_gpu_access) { obj->last_fenced_seqno = seqno; - obj->last_fenced_ring = ring; /* Bump MRU to take account of the delayed flush */ if (obj->fence_reg != I915_FENCE_REG_NONE) { @@ -1445,7 +1444,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) BUG_ON(!list_empty(&obj->gpu_write_list)); BUG_ON(!obj->active); obj->ring = NULL; - obj->last_fenced_ring = NULL; i915_gem_object_move_off_active(obj); obj->fenced_gpu_access = false; @@ -1650,7 +1648,6 @@ static void i915_gem_reset_fences(struct drm_device *dev) reg->obj->fence_reg = I915_FENCE_REG_NONE; reg->obj->fenced_gpu_access = false; reg->obj->last_fenced_seqno = 0; - reg->obj->last_fenced_ring = NULL; i915_gem_clear_fence_reg(dev, reg); } } @@ -2295,7 +2292,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) if (obj->fenced_gpu_access) { if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(obj->last_fenced_ring, + ret = i915_gem_flush_ring(obj->ring, 0, obj->base.write_domain); if (ret) return ret; @@ -2304,10 +2301,10 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) obj->fenced_gpu_access = false; } - if (obj->last_fenced_seqno && NULL != obj->last_fenced_ring) { - if (!ring_passed_seqno(obj->last_fenced_ring, + if (obj->last_fenced_seqno) { + if (!ring_passed_seqno(obj->ring, obj->last_fenced_seqno)) { - ret = i915_wait_request(obj->last_fenced_ring, + ret = i915_wait_request(obj->ring, obj->last_fenced_seqno, true); if (ret) @@ -2315,7 +2312,6 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) } obj->last_fenced_seqno = 0; - obj->last_fenced_ring = NULL; } /* Ensure that all CPU reads are completed before installing a fence @@ -2382,7 +2378,7 @@ i915_find_fence_reg(struct drm_device *dev) if (first == NULL) first = reg; - if (reg->obj->last_fenced_ring == NULL) { + if (reg->obj->last_fenced_seqno == 0) { avail = reg; break; } @@ -2458,7 +2454,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) } old->fence_reg = I915_FENCE_REG_NONE; - old->last_fenced_ring = NULL; old->last_fenced_seqno = 0; drm_gem_object_unreference(&old->base); @@ -2467,7 +2462,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) reg->obj = obj; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); obj->fence_reg = reg - dev_priv->fence_regs; - obj->last_fenced_ring = NULL; update: obj->tiling_changed = false; -- cgit v0.10.2 From 8fe301add51206ca53576471059393b925f30124 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:28 +0100 Subject: drm/i915: Simplify fence finding As the fences are stored in LRU order, we can simply reuse the oldest if we do not have an unused register. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b25d229..f7cd3461 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2352,7 +2352,7 @@ static struct drm_i915_fence_reg * i915_find_fence_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg, *first, *avail; + struct drm_i915_fence_reg *reg, *avail; int i; /* First try to find a free reg */ @@ -2370,24 +2370,14 @@ i915_find_fence_reg(struct drm_device *dev) return NULL; /* None available, try to steal one or wait for a user to finish */ - avail = first = NULL; list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { if (reg->pin_count) continue; - if (first == NULL) - first = reg; - - if (reg->obj->last_fenced_seqno == 0) { - avail = reg; - break; - } + return reg; } - if (avail == NULL) - avail = first; - - return avail; + return NULL; } /** -- cgit v0.10.2 From 1899184547dec95ec8b7eb00e202d9b3a3b1c87b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:29 +0100 Subject: drm/i915: Remove the unsightly "optimisation" from flush_fence() As i915_wait_request() will first check for an already passed seqno, doing it also in the caller is a waste of space for a cold path. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f7cd3461..bac3570 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2280,11 +2280,6 @@ static int i830_write_fence_reg(struct drm_i915_gem_object *obj) return 0; } -static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno) -{ - return i915_seqno_passed(ring->get_seqno(ring), seqno); -} - static int i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) { @@ -2302,14 +2297,11 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) } if (obj->last_fenced_seqno) { - if (!ring_passed_seqno(obj->ring, - obj->last_fenced_seqno)) { - ret = i915_wait_request(obj->ring, - obj->last_fenced_seqno, - true); - if (ret) - return ret; - } + ret = i915_wait_request(obj->ring, + obj->last_fenced_seqno, + true); + if (ret) + return ret; obj->last_fenced_seqno = 0; } -- cgit v0.10.2 From 9ce079e4812c41c5f4ee9ea116c768b8939197d6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:30 +0100 Subject: drm/i915: Prepare to consolidate fence writing Update the existing architecture specific fence writing routines to either update the fence to point to a tiled object or to clear them in preparation to remove the other fence writing routes. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index bac3570..199306d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2163,121 +2163,142 @@ int i915_gpu_idle(struct drm_device *dev, bool do_retire) return 0; } -static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj) +static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint64_t val; - val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << - SANDYBRIDGE_FENCE_PITCH_SHIFT; + if (obj) { + u32 size = obj->gtt_space->size; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; + val = (uint64_t)((obj->gtt_offset + size - 4096) & + 0xfffff000) << 32; + val |= obj->gtt_offset & 0xfffff000; + val |= (uint64_t)((obj->stride / 128) - 1) << + SANDYBRIDGE_FENCE_PITCH_SHIFT; - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; + } else + val = 0; - return 0; + I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); + POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); } -static int i965_write_fence_reg(struct drm_i915_gem_object *obj) +static void i965_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint64_t val; - val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; - val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; + if (obj) { + u32 size = obj->gtt_space->size; - I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val); + val = (uint64_t)((obj->gtt_offset + size - 4096) & + 0xfffff000) << 32; + val |= obj->gtt_offset & 0xfffff000; + val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; + } else + val = 0; - return 0; + I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); + POSTING_READ(FENCE_REG_965_0 + reg * 8); } -static int i915_write_fence_reg(struct drm_i915_gem_object *obj) +static void i915_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - u32 fence_reg, val, pitch_val; - int tile_width; - - if (WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) || - (size & -size) != size || - (obj->gtt_offset & (size - 1)), - "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", - obj->gtt_offset, obj->map_and_fenceable, size)) - return -EINVAL; + u32 val; - if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) - tile_width = 128; - else - tile_width = 512; - - /* Note: pitch better be a power of two tile widths */ - pitch_val = obj->stride / tile_width; - pitch_val = ffs(pitch_val) - 1; - - val = obj->gtt_offset; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I915_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; - - fence_reg = obj->fence_reg; - if (fence_reg < 8) - fence_reg = FENCE_REG_830_0 + fence_reg * 4; - else - fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; + if (obj) { + u32 size = obj->gtt_space->size; + int pitch_val; + int tile_width; - I915_WRITE(fence_reg, val); + WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) || + (size & -size) != size || + (obj->gtt_offset & (size - 1)), + "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + obj->gtt_offset, obj->map_and_fenceable, size); - return 0; + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) + tile_width = 128; + else + tile_width = 512; + + /* Note: pitch better be a power of two tile widths */ + pitch_val = obj->stride / tile_width; + pitch_val = ffs(pitch_val) - 1; + + val = obj->gtt_offset; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I915_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + if (reg < 8) + reg = FENCE_REG_830_0 + reg * 4; + else + reg = FENCE_REG_945_8 + (reg - 8) * 4; + + I915_WRITE(reg, val); + POSTING_READ(reg); } -static int i830_write_fence_reg(struct drm_i915_gem_object *obj) +static void i830_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 size = obj->gtt_space->size; - int regnum = obj->fence_reg; uint32_t val; - uint32_t pitch_val; - - if (WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) || - (size & -size) != size || - (obj->gtt_offset & (size - 1)), - "object 0x%08x not 512K or pot-size 0x%08x aligned\n", - obj->gtt_offset, size)) - return -EINVAL; - pitch_val = obj->stride / 128; - pitch_val = ffs(pitch_val) - 1; - - val = obj->gtt_offset; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I830_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; + if (obj) { + u32 size = obj->gtt_space->size; + uint32_t pitch_val; + + WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) || + (size & -size) != size || + (obj->gtt_offset & (size - 1)), + "object 0x%08x not 512K or pot-size 0x%08x aligned\n", + obj->gtt_offset, size); + + pitch_val = obj->stride / 128; + pitch_val = ffs(pitch_val) - 1; + + val = obj->gtt_offset; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I830_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; - I915_WRITE(FENCE_REG_830_0 + regnum * 4, val); + I915_WRITE(FENCE_REG_830_0 + reg * 4, val); + POSTING_READ(FENCE_REG_830_0 + reg * 4); +} - return 0; +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + switch (INTEL_INFO(dev)->gen) { + case 7: + case 6: sandybridge_write_fence_reg(dev, reg, obj); break; + case 5: + case 4: i965_write_fence_reg(dev, reg, obj); break; + case 3: i915_write_fence_reg(dev, reg, obj); break; + case 2: i830_write_fence_reg(dev, reg, obj); break; + default: break; + } } static int @@ -2447,24 +2468,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) update: obj->tiling_changed = false; - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - ret = sandybridge_write_fence_reg(obj); - break; - case 5: - case 4: - ret = i965_write_fence_reg(obj); - break; - case 3: - ret = i915_write_fence_reg(obj); - break; - case 2: - ret = i830_write_fence_reg(obj); - break; - } - - return ret; + i915_gem_write_fence(dev, reg - dev_priv->fence_regs, obj); + return 0; } /** -- cgit v0.10.2 From 61050808bb019ebea966b7b5bfd357aaf219fb51 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:31 +0100 Subject: drm/i915: Refactor put_fence() to use the common fence writing routine One clarification that we make is to the existing semantics of obj->tiling_changed to only mean that we need to update an associated fence register (including the NO_FENCE when executing an untiled but fenced GPU command). If we do not have a fence register or pending fenced GPU access for the object (after put_fence() for example), then we can clear the tiling_changed flag as any fence will necessarily be rewritten upon acquisition. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 199306d..3601b8b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -50,10 +50,28 @@ static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_file *file); static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj); +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj); +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable); + static int i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); +static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) +{ + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + /* As we do not have an associated fence register, we will force + * a tiling change if we ever need to acquire one. + */ + obj->tiling_changed = false; + obj->fence_reg = I915_FENCE_REG_NONE; +} + /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size) @@ -2301,6 +2319,32 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg, } } +static inline int fence_number(struct drm_i915_private *dev_priv, + struct drm_i915_fence_reg *fence) +{ + return fence - dev_priv->fence_regs; +} + +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { + obj->fence_reg = reg; + fence->obj = obj; + list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); + } else { + obj->fence_reg = I915_FENCE_REG_NONE; + fence->obj = NULL; + list_del_init(&fence->lru_list); + } +} + static int i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) { @@ -2339,24 +2383,20 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) int i915_gem_object_put_fence(struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; int ret; - if (obj->tiling_mode) - i915_gem_release_mmap(obj); - ret = i915_gem_object_flush_fence(obj); if (ret) return ret; - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - - WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count); - i915_gem_clear_fence_reg(obj->base.dev, - &dev_priv->fence_regs[obj->fence_reg]); + if (obj->fence_reg == I915_FENCE_REG_NONE) + return 0; - obj->fence_reg = I915_FENCE_REG_NONE; - } + i915_gem_object_update_fence(obj, + &dev_priv->fence_regs[obj->fence_reg], + false); + i915_gem_object_fence_lost(obj); return 0; } -- cgit v0.10.2 From ada726c734e79c83f72676c02b5d68d4f9faead0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:32 +0100 Subject: drm/i915: Refactor fence clearing to use the common fence writing routine Now that we have a routine that is able to clear the fences as well as setup up the register for a tiled object, remove the surplus routines to clear the fences. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3601b8b..e09ac3a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -42,8 +42,6 @@ static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *o static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, unsigned alignment, bool map_and_fenceable); -static void i915_gem_clear_fence_reg(struct drm_device *dev, - struct drm_i915_fence_reg *reg); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, @@ -1655,19 +1653,18 @@ static void i915_gem_reset_fences(struct drm_device *dev) for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - struct drm_i915_gem_object *obj = reg->obj; - if (!obj) - continue; + i915_gem_write_fence(dev, i, NULL); - if (obj->tiling_mode) - i915_gem_release_mmap(obj); + if (reg->obj) + i915_gem_object_fence_lost(reg->obj); - reg->obj->fence_reg = I915_FENCE_REG_NONE; - reg->obj->fenced_gpu_access = false; - reg->obj->last_fenced_seqno = 0; - i915_gem_clear_fence_reg(dev, reg); + reg->pin_count = 0; + reg->obj = NULL; + INIT_LIST_HEAD(®->lru_list); } + + INIT_LIST_HEAD(&dev_priv->mm.fence_list); } void i915_gem_reset(struct drm_device *dev) @@ -2513,45 +2510,6 @@ update: } /** - * i915_gem_clear_fence_reg - clear out fence register info - * @obj: object to clear - * - * Zeroes out the fence register itself and clears out the associated - * data structures in dev_priv and obj. - */ -static void -i915_gem_clear_fence_reg(struct drm_device *dev, - struct drm_i915_fence_reg *reg) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t fence_reg = reg - dev_priv->fence_regs; - - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0); - break; - case 5: - case 4: - I915_WRITE64(FENCE_REG_965_0 + fence_reg*8, 0); - break; - case 3: - if (fence_reg >= 8) - fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4; - else - case 2: - fence_reg = FENCE_REG_830_0 + fence_reg * 4; - - I915_WRITE(fence_reg, 0); - break; - } - - list_del_init(®->lru_list); - reg->obj = NULL; - reg->pin_count = 0; -} - -/** * Finds free space in the GTT aperture and binds the object there. */ static int @@ -3788,9 +3746,7 @@ i915_gem_load(struct drm_device *dev) dev_priv->num_fence_regs = 8; /* Initialize fence registers to zero */ - for (i = 0; i < dev_priv->num_fence_regs; i++) { - i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]); - } + i915_gem_reset_fences(dev); i915_gem_detect_bit_6_swizzle(dev); init_waitqueue_head(&dev_priv->pending_flip_queue); -- cgit v0.10.2 From 14415745b2518fc7309616a33ce8e656e79a4e05 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 17 Apr 2012 15:31:33 +0100 Subject: drm/i915: Refactor get_fence() to use the common fence writing routine We can also take advantage of the new 'no retire' mode for seqno waiting to avoid having to take a reference on the old fence object whilst flushing an existing fence. Signed-off-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e09ac3a..7bc4a40 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2361,7 +2361,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) if (obj->last_fenced_seqno) { ret = i915_wait_request(obj->ring, obj->last_fenced_seqno, - true); + false); if (ret) return ret; @@ -2449,63 +2449,47 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = obj->tiling_mode != I915_TILING_NONE; struct drm_i915_fence_reg *reg; int ret; - if (obj->tiling_mode == I915_TILING_NONE) - return i915_gem_object_put_fence(obj); + /* Have we updated the tiling parameters upon the object and so + * will need to serialise the write to the associated fence register? + */ + if (obj->tiling_changed) { + ret = i915_gem_object_flush_fence(obj); + if (ret) + return ret; + } /* Just update our place in the LRU if our fence is getting reused. */ if (obj->fence_reg != I915_FENCE_REG_NONE) { reg = &dev_priv->fence_regs[obj->fence_reg]; - list_move_tail(®->lru_list, &dev_priv->mm.fence_list); + if (!obj->tiling_changed) { + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + return 0; + } + } else if (enable) { + reg = i915_find_fence_reg(dev); + if (reg == NULL) + return -EDEADLK; + + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; - if (obj->tiling_changed) { - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_flush_fence(old); if (ret) return ret; - goto update; + i915_gem_object_fence_lost(old); } - + } else return 0; - } - - reg = i915_find_fence_reg(dev); - if (reg == NULL) - return -EDEADLK; - - ret = i915_gem_object_flush_fence(obj); - if (ret) - return ret; - - if (reg->obj) { - struct drm_i915_gem_object *old = reg->obj; - drm_gem_object_reference(&old->base); - - if (old->tiling_mode) - i915_gem_release_mmap(old); - - ret = i915_gem_object_flush_fence(old); - if (ret) { - drm_gem_object_unreference(&old->base); - return ret; - } - - old->fence_reg = I915_FENCE_REG_NONE; - old->last_fenced_seqno = 0; - - drm_gem_object_unreference(&old->base); - } - - reg->obj = obj; - list_move_tail(®->lru_list, &dev_priv->mm.fence_list); - obj->fence_reg = reg - dev_priv->fence_regs; - -update: + i915_gem_object_update_fence(obj, reg, enable); obj->tiling_changed = false; - i915_gem_write_fence(dev, reg - dev_priv->fence_regs, obj); + return 0; } -- cgit v0.10.2 From 85208be0154e73c8c902eb5bfb625f9188c87901 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Mon, 16 Apr 2012 22:20:34 -0300 Subject: drm/i915: move fbc-related functionality into intel_pm module This commit moves Frame Buffer Compression-related operations and support functions into the new intel_pm module. Signed-off-by: Eugeni Dodonov Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index f801330..b65c06f 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -23,6 +23,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ intel_sdvo.o \ intel_modes.o \ intel_panel.o \ + intel_pm.o \ intel_i2c.o \ intel_fb.o \ intel_tv.o \ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1f844c5..6768d75 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1627,490 +1627,6 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, disable_pch_hdmi(dev_priv, pipe, HDMID); } -static void i8xx_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 fbc_ctl; - - /* Disable compression */ - fbc_ctl = I915_READ(FBC_CONTROL); - if ((fbc_ctl & FBC_CTL_EN) == 0) - return; - - fbc_ctl &= ~FBC_CTL_EN; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - /* Wait for compressing bit to clear */ - if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { - DRM_DEBUG_KMS("FBC idle timed out\n"); - return; - } - - DRM_DEBUG_KMS("disabled FBC\n"); -} - -static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int cfb_pitch; - int plane, i; - u32 fbc_ctl, fbc_ctl2; - - cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; - if (fb->pitches[0] < cfb_pitch) - cfb_pitch = fb->pitches[0]; - - /* FBC_CTL wants 64B units */ - cfb_pitch = (cfb_pitch / 64) - 1; - plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; - - /* Clear old tags */ - for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) - I915_WRITE(FBC_TAG + (i * 4), 0); - - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); - - /* enable it... */ - fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; - if (IS_I945GM(dev)) - fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ - fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; - fbc_ctl |= obj->fence_reg; - I915_WRITE(FBC_CONTROL, fbc_ctl); - - DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", - cfb_pitch, crtc->y, intel_crtc->plane); -} - -static bool i8xx_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(FBC_CONTROL) & FBC_CTL_EN; -} - -static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; - u32 dpfc_ctl; - - dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; - dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; - I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); - - I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); - I915_WRITE(DPFC_FENCE_YOFF, crtc->y); - - /* enable it... */ - I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); - - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); -} - -static void g4x_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - /* Disable compression */ - dpfc_ctl = I915_READ(DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool g4x_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; -} - -static void sandybridge_blit_fbc_update(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 blt_ecoskpd; - - /* Make sure blitter notifies FBC of writes */ - gen6_gt_force_wake_get(dev_priv); - blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << - GEN6_BLITTER_LOCK_SHIFT); - I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); - POSTING_READ(GEN6_BLITTER_ECOSKPD); - gen6_gt_force_wake_put(dev_priv); -} - -static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; - struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); - struct drm_i915_gem_object *obj = intel_fb->obj; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; - u32 dpfc_ctl; - - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - dpfc_ctl &= DPFC_RESERVED; - dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); - /* Set persistent mode for front-buffer rendering, ala X. */ - dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; - dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); - I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); - - I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); - I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); - I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); - /* enable it... */ - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - - if (IS_GEN6(dev)) { - I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); - sandybridge_blit_fbc_update(dev); - } - - DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); -} - -static void ironlake_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpfc_ctl; - - /* Disable compression */ - dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); - if (dpfc_ctl & DPFC_CTL_EN) { - dpfc_ctl &= ~DPFC_CTL_EN; - I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); - - DRM_DEBUG_KMS("disabled FBC\n"); - } -} - -static bool ironlake_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; -} - -bool intel_fbc_enabled(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev_priv->display.fbc_enabled) - return false; - - return dev_priv->display.fbc_enabled(dev); -} - -static void intel_fbc_work_fn(struct work_struct *__work) -{ - struct intel_fbc_work *work = - container_of(to_delayed_work(__work), - struct intel_fbc_work, work); - struct drm_device *dev = work->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - mutex_lock(&dev->struct_mutex); - if (work == dev_priv->fbc_work) { - /* Double check that we haven't switched fb without cancelling - * the prior work. - */ - if (work->crtc->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc, - work->interval); - - dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane; - dev_priv->cfb_fb = work->crtc->fb->base.id; - dev_priv->cfb_y = work->crtc->y; - } - - dev_priv->fbc_work = NULL; - } - mutex_unlock(&dev->struct_mutex); - - kfree(work); -} - -static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) -{ - if (dev_priv->fbc_work == NULL) - return; - - DRM_DEBUG_KMS("cancelling pending FBC enable\n"); - - /* Synchronisation is provided by struct_mutex and checking of - * dev_priv->fbc_work, so we can perform the cancellation - * entirely asynchronously. - */ - if (cancel_delayed_work(&dev_priv->fbc_work->work)) - /* tasklet was killed before being run, clean up */ - kfree(dev_priv->fbc_work); - - /* Mark the work as no longer wanted so that if it does - * wake-up (because the work was already running and waiting - * for our mutex), it will discover that is no longer - * necessary to run. - */ - dev_priv->fbc_work = NULL; -} - -static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) -{ - struct intel_fbc_work *work; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!dev_priv->display.enable_fbc) - return; - - intel_cancel_fbc_work(dev_priv); - - work = kzalloc(sizeof *work, GFP_KERNEL); - if (work == NULL) { - dev_priv->display.enable_fbc(crtc, interval); - return; - } - - work->crtc = crtc; - work->fb = crtc->fb; - work->interval = interval; - INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); - - dev_priv->fbc_work = work; - - DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); - - /* Delay the actual enabling to let pageflipping cease and the - * display to settle before starting the compression. Note that - * this delay also serves a second purpose: it allows for a - * vblank to pass after disabling the FBC before we attempt - * to modify the control registers. - * - * A more complicated solution would involve tracking vblanks - * following the termination of the page-flipping sequence - * and indeed performing the enable as a co-routine and not - * waiting synchronously upon the vblank. - */ - schedule_delayed_work(&work->work, msecs_to_jiffies(50)); -} - -void intel_disable_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - intel_cancel_fbc_work(dev_priv); - - if (!dev_priv->display.disable_fbc) - return; - - dev_priv->display.disable_fbc(dev); - dev_priv->cfb_plane = -1; -} - -/** - * intel_update_fbc - enable/disable FBC as needed - * @dev: the drm_device - * - * Set up the framebuffer compression hardware at mode set time. We - * enable it if possible: - * - plane A only (on pre-965) - * - no pixel mulitply/line duplication - * - no alpha buffer discard - * - no dual wide - * - framebuffer <= 2048 in width, 1536 in height - * - * We can't assume that any compression will take place (worst case), - * so the compressed buffer has to be the same size as the uncompressed - * one. It also must reside (along with the line length buffer) in - * stolen memory. - * - * We need to enable/disable FBC on a global basis. - */ -static void intel_update_fbc(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc = NULL, *tmp_crtc; - struct intel_crtc *intel_crtc; - struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; - struct drm_i915_gem_object *obj; - int enable_fbc; - - DRM_DEBUG_KMS("\n"); - - if (!i915_powersave) - return; - - if (!I915_HAS_FBC(dev)) - return; - - /* - * If FBC is already on, we just have to verify that we can - * keep it that way... - * Need to disable if: - * - more than one pipe is active - * - changing FBC params (stride, fence, mode) - * - new fb is too large to fit in compressed buffer - * - going to an unsupported config (interlace, pixel multiply, etc.) - */ - list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { - if (tmp_crtc->enabled && tmp_crtc->fb) { - if (crtc) { - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; - goto out_disable; - } - crtc = tmp_crtc; - } - } - - if (!crtc || crtc->fb == NULL) { - DRM_DEBUG_KMS("no output, disabling\n"); - dev_priv->no_fbc_reason = FBC_NO_OUTPUT; - goto out_disable; - } - - intel_crtc = to_intel_crtc(crtc); - fb = crtc->fb; - intel_fb = to_intel_framebuffer(fb); - obj = intel_fb->obj; - - 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 <= 6) - 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; - } - if (intel_fb->obj->base.size > dev_priv->cfb_size) { - DRM_DEBUG_KMS("framebuffer too large, disabling " - "compression\n"); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - goto out_disable; - } - if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || - (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { - DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); - dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; - goto out_disable; - } - if ((crtc->mode.hdisplay > 2048) || - (crtc->mode.vdisplay > 1536)) { - DRM_DEBUG_KMS("mode too large for compression, disabling\n"); - dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; - goto out_disable; - } - if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { - DRM_DEBUG_KMS("plane not 0, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_BAD_PLANE; - goto out_disable; - } - - /* The use of a CPU fence is mandatory in order to detect writes - * by the CPU to the scanout and trigger updates to the FBC. - */ - if (obj->tiling_mode != I915_TILING_X || - obj->fence_reg == I915_FENCE_REG_NONE) { - DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); - dev_priv->no_fbc_reason = FBC_NOT_TILED; - goto out_disable; - } - - /* If the kernel debugger is active, always disable compression */ - if (in_dbg_master()) - goto out_disable; - - /* If the scanout has not changed, don't modify the FBC settings. - * Note that we make the fundamental assumption that the fb->obj - * cannot be unpinned (and have its GTT offset and fence revoked) - * without first being decoupled from the scanout and FBC disabled. - */ - if (dev_priv->cfb_plane == intel_crtc->plane && - dev_priv->cfb_fb == fb->base.id && - dev_priv->cfb_y == crtc->y) - return; - - if (intel_fbc_enabled(dev)) { - /* We update FBC along two paths, after changing fb/crtc - * configuration (modeswitching) and after page-flipping - * finishes. For the latter, we know that not only did - * we disable the FBC at the start of the page-flip - * sequence, but also more than one vblank has passed. - * - * For the former case of modeswitching, it is possible - * to switch between two FBC valid configurations - * instantaneously so we do need to disable the FBC - * before we can modify its control registers. We also - * have to wait for the next vblank for that to take - * effect. However, since we delay enabling FBC we can - * assume that a vblank has passed since disabling and - * that we can safely alter the registers in the deferred - * callback. - * - * In the scenario that we go from a valid to invalid - * and then back to valid FBC configuration we have - * no strict enforcement that a vblank occurred since - * disabling the FBC. However, along all current pipe - * disabling paths we do need to wait for a vblank at - * some point. And we wait before enabling FBC anyway. - */ - DRM_DEBUG_KMS("disabling active FBC for update\n"); - intel_disable_fbc(dev); - } - - intel_enable_fbc(crtc, 500); - return; - -out_disable: - /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) { - DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - intel_disable_fbc(dev); - } -} - int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8748e5e..def112e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -434,4 +434,19 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); +/* Power-related functions, located in intel_pm.c */ +/* FBC */ +extern void i8xx_disable_fbc(struct drm_device *dev); +extern void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval); +extern bool i8xx_fbc_enabled(struct drm_device *dev); +extern void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval); +extern void g4x_disable_fbc(struct drm_device *dev); +extern bool g4x_fbc_enabled(struct drm_device *dev); +extern void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval); +extern void ironlake_disable_fbc(struct drm_device *dev); +extern bool ironlake_fbc_enabled(struct drm_device *dev); +extern bool intel_fbc_enabled(struct drm_device *dev); +extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); +extern void intel_update_fbc(struct drm_device *dev); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c new file mode 100644 index 0000000..7fbd305 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -0,0 +1,521 @@ +/* + * Copyright © 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eugeni Dodonov + * + */ + +#include "i915_drv.h" +#include "intel_drv.h" + +/* FBC, or Frame Buffer Compression, is a technique employed to compress the framebuffer contents in-memory, aiming at reducing the required bandwidth during in-memory transfers and, therefore, reduce the power packet. + * + * The benefits of FBC are mostly visible with solid backgrounds and variation-less patterns. + * + * FBC-related functionality can be enabled by the means of the i915.i915_enable_fbc parameter + */ + +void i8xx_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 fbc_ctl; + + /* Disable compression */ + fbc_ctl = I915_READ(FBC_CONTROL); + if ((fbc_ctl & FBC_CTL_EN) == 0) + return; + + fbc_ctl &= ~FBC_CTL_EN; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + /* Wait for compressing bit to clear */ + if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) { + DRM_DEBUG_KMS("FBC idle timed out\n"); + return; + } + + DRM_DEBUG_KMS("disabled FBC\n"); +} + +void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int cfb_pitch; + int plane, i; + u32 fbc_ctl, fbc_ctl2; + + cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE; + if (fb->pitches[0] < cfb_pitch) + cfb_pitch = fb->pitches[0]; + + /* FBC_CTL wants 64B units */ + cfb_pitch = (cfb_pitch / 64) - 1; + plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; + + /* Clear old tags */ + for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) + I915_WRITE(FBC_TAG + (i * 4), 0); + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= plane; + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + + /* enable it... */ + fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + if (IS_I945GM(dev)) + fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ + fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; + fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= obj->fence_reg; + I915_WRITE(FBC_CONTROL, fbc_ctl); + + DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ", + cfb_pitch, crtc->y, intel_crtc->plane); +} + +bool i8xx_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(FBC_CONTROL) & FBC_CTL_EN; +} + +void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; + unsigned long stall_watermark = 200; + u32 dpfc_ctl; + + dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; + dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; + I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); + + I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | + (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | + (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); + I915_WRITE(DPFC_FENCE_YOFF, crtc->y); + + /* enable it... */ + I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN); + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + +void g4x_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + /* Disable compression */ + dpfc_ctl = I915_READ(DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +bool g4x_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; +} + +static void sandybridge_blit_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 blt_ecoskpd; + + /* Make sure blitter notifies FBC of writes */ + gen6_gt_force_wake_get(dev_priv); + blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY; + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY << + GEN6_BLITTER_LOCK_SHIFT); + I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd); + POSTING_READ(GEN6_BLITTER_ECOSKPD); + gen6_gt_force_wake_put(dev_priv); +} + +void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; + unsigned long stall_watermark = 200; + u32 dpfc_ctl; + + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + dpfc_ctl &= DPFC_RESERVED; + dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); + /* Set persistent mode for front-buffer rendering, ala X. */ + dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE; + dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg); + I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); + + I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | + (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | + (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID); + /* enable it... */ + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); + + if (IS_GEN6(dev)) { + I915_WRITE(SNB_DPFC_CTL_SA, + SNB_CPU_FENCE_ENABLE | obj->fence_reg); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + sandybridge_blit_fbc_update(dev); + } + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + +void ironlake_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + /* Disable compression */ + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + if (dpfc_ctl & DPFC_CTL_EN) { + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + + DRM_DEBUG_KMS("disabled FBC\n"); + } +} + +bool ironlake_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; +} + +bool intel_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev_priv->display.fbc_enabled) + return false; + + return dev_priv->display.fbc_enabled(dev); +} + +static void intel_fbc_work_fn(struct work_struct *__work) +{ + struct intel_fbc_work *work = + container_of(to_delayed_work(__work), + struct intel_fbc_work, work); + struct drm_device *dev = work->crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + if (work == dev_priv->fbc_work) { + /* Double check that we haven't switched fb without cancelling + * the prior work. + */ + if (work->crtc->fb == work->fb) { + dev_priv->display.enable_fbc(work->crtc, + work->interval); + + dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane; + dev_priv->cfb_fb = work->crtc->fb->base.id; + dev_priv->cfb_y = work->crtc->y; + } + + dev_priv->fbc_work = NULL; + } + mutex_unlock(&dev->struct_mutex); + + kfree(work); +} + +static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) +{ + if (dev_priv->fbc_work == NULL) + return; + + DRM_DEBUG_KMS("cancelling pending FBC enable\n"); + + /* Synchronisation is provided by struct_mutex and checking of + * dev_priv->fbc_work, so we can perform the cancellation + * entirely asynchronously. + */ + if (cancel_delayed_work(&dev_priv->fbc_work->work)) + /* tasklet was killed before being run, clean up */ + kfree(dev_priv->fbc_work); + + /* Mark the work as no longer wanted so that if it does + * wake-up (because the work was already running and waiting + * for our mutex), it will discover that is no longer + * necessary to run. + */ + dev_priv->fbc_work = NULL; +} + +void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct intel_fbc_work *work; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!dev_priv->display.enable_fbc) + return; + + intel_cancel_fbc_work(dev_priv); + + work = kzalloc(sizeof *work, GFP_KERNEL); + if (work == NULL) { + dev_priv->display.enable_fbc(crtc, interval); + return; + } + + work->crtc = crtc; + work->fb = crtc->fb; + work->interval = interval; + INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); + + dev_priv->fbc_work = work; + + DRM_DEBUG_KMS("scheduling delayed FBC enable\n"); + + /* Delay the actual enabling to let pageflipping cease and the + * display to settle before starting the compression. Note that + * this delay also serves a second purpose: it allows for a + * vblank to pass after disabling the FBC before we attempt + * to modify the control registers. + * + * A more complicated solution would involve tracking vblanks + * following the termination of the page-flipping sequence + * and indeed performing the enable as a co-routine and not + * waiting synchronously upon the vblank. + */ + schedule_delayed_work(&work->work, msecs_to_jiffies(50)); +} + +void intel_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + intel_cancel_fbc_work(dev_priv); + + if (!dev_priv->display.disable_fbc) + return; + + dev_priv->display.disable_fbc(dev); + dev_priv->cfb_plane = -1; +} + +/** + * intel_update_fbc - enable/disable FBC as needed + * @dev: the drm_device + * + * Set up the framebuffer compression hardware at mode set time. We + * enable it if possible: + * - plane A only (on pre-965) + * - no pixel mulitply/line duplication + * - no alpha buffer discard + * - no dual wide + * - framebuffer <= 2048 in width, 1536 in height + * + * We can't assume that any compression will take place (worst case), + * so the compressed buffer has to be the same size as the uncompressed + * one. It also must reside (along with the line length buffer) in + * stolen memory. + * + * We need to enable/disable FBC on a global basis. + */ +void intel_update_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = NULL, *tmp_crtc; + struct intel_crtc *intel_crtc; + struct drm_framebuffer *fb; + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj; + int enable_fbc; + + DRM_DEBUG_KMS("\n"); + + if (!i915_powersave) + return; + + if (!I915_HAS_FBC(dev)) + return; + + /* + * If FBC is already on, we just have to verify that we can + * keep it that way... + * Need to disable if: + * - more than one pipe is active + * - changing FBC params (stride, fence, mode) + * - new fb is too large to fit in compressed buffer + * - going to an unsupported config (interlace, pixel multiply, etc.) + */ + list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) { + if (tmp_crtc->enabled && tmp_crtc->fb) { + if (crtc) { + DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES; + goto out_disable; + } + crtc = tmp_crtc; + } + } + + if (!crtc || crtc->fb == NULL) { + DRM_DEBUG_KMS("no output, disabling\n"); + dev_priv->no_fbc_reason = FBC_NO_OUTPUT; + goto out_disable; + } + + intel_crtc = to_intel_crtc(crtc); + fb = crtc->fb; + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + + 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 <= 6) + 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; + } + if (intel_fb->obj->base.size > dev_priv->cfb_size) { + DRM_DEBUG_KMS("framebuffer too large, disabling " + "compression\n"); + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + goto out_disable; + } + if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || + (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { + DRM_DEBUG_KMS("mode incompatible with compression, " + "disabling\n"); + dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE; + goto out_disable; + } + if ((crtc->mode.hdisplay > 2048) || + (crtc->mode.vdisplay > 1536)) { + DRM_DEBUG_KMS("mode too large for compression, disabling\n"); + dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE; + goto out_disable; + } + if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) { + DRM_DEBUG_KMS("plane not 0, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_BAD_PLANE; + goto out_disable; + } + + /* The use of a CPU fence is mandatory in order to detect writes + * by the CPU to the scanout and trigger updates to the FBC. + */ + if (obj->tiling_mode != I915_TILING_X || + obj->fence_reg == I915_FENCE_REG_NONE) { + DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_NOT_TILED; + goto out_disable; + } + + /* If the kernel debugger is active, always disable compression */ + if (in_dbg_master()) + goto out_disable; + + /* If the scanout has not changed, don't modify the FBC settings. + * Note that we make the fundamental assumption that the fb->obj + * cannot be unpinned (and have its GTT offset and fence revoked) + * without first being decoupled from the scanout and FBC disabled. + */ + if (dev_priv->cfb_plane == intel_crtc->plane && + dev_priv->cfb_fb == fb->base.id && + dev_priv->cfb_y == crtc->y) + return; + + if (intel_fbc_enabled(dev)) { + /* We update FBC along two paths, after changing fb/crtc + * configuration (modeswitching) and after page-flipping + * finishes. For the latter, we know that not only did + * we disable the FBC at the start of the page-flip + * sequence, but also more than one vblank has passed. + * + * For the former case of modeswitching, it is possible + * to switch between two FBC valid configurations + * instantaneously so we do need to disable the FBC + * before we can modify its control registers. We also + * have to wait for the next vblank for that to take + * effect. However, since we delay enabling FBC we can + * assume that a vblank has passed since disabling and + * that we can safely alter the registers in the deferred + * callback. + * + * In the scenario that we go from a valid to invalid + * and then back to valid FBC configuration we have + * no strict enforcement that a vblank occurred since + * disabling the FBC. However, along all current pipe + * disabling paths we do need to wait for a vblank at + * some point. And we wait before enabling FBC anyway. + */ + DRM_DEBUG_KMS("disabling active FBC for update\n"); + intel_disable_fbc(dev); + } + + intel_enable_fbc(crtc, 500); + return; + +out_disable: + /* Multiple disables should be harmless */ + if (intel_fbc_enabled(dev)) { + DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); + intel_disable_fbc(dev); + } +} + -- cgit v0.10.2 From b445e3b013adfcb05322ebde7fb16488f0644579 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Mon, 16 Apr 2012 22:20:35 -0300 Subject: drm/i915: move watermarks settings into intel_pm module Move watermarks and helper functions (such as cxsr and fifo buffers) into intel_pm module. Signed-off-by: Eugeni Dodonov Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6768d75..03c015c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3187,1482 +3187,6 @@ ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); } - -struct intel_watermark_params { - unsigned long fifo_size; - unsigned long max_wm; - unsigned long default_wm; - unsigned long guard_size; - unsigned long cacheline_size; -}; - -/* Pineview has different values for various configs */ -static const struct intel_watermark_params pineview_display_wm = { - PINEVIEW_DISPLAY_FIFO, - PINEVIEW_MAX_WM, - PINEVIEW_DFT_WM, - PINEVIEW_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params pineview_display_hplloff_wm = { - PINEVIEW_DISPLAY_FIFO, - PINEVIEW_MAX_WM, - PINEVIEW_DFT_HPLLOFF_WM, - PINEVIEW_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params pineview_cursor_wm = { - PINEVIEW_CURSOR_FIFO, - PINEVIEW_CURSOR_MAX_WM, - PINEVIEW_CURSOR_DFT_WM, - PINEVIEW_CURSOR_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params pineview_cursor_hplloff_wm = { - PINEVIEW_CURSOR_FIFO, - PINEVIEW_CURSOR_MAX_WM, - PINEVIEW_CURSOR_DFT_WM, - PINEVIEW_CURSOR_GUARD_WM, - PINEVIEW_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params g4x_wm_info = { - G4X_FIFO_SIZE, - G4X_MAX_WM, - G4X_MAX_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params g4x_cursor_wm_info = { - I965_CURSOR_FIFO, - I965_CURSOR_MAX_WM, - I965_CURSOR_DFT_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params valleyview_wm_info = { - VALLEYVIEW_FIFO_SIZE, - VALLEYVIEW_MAX_WM, - VALLEYVIEW_MAX_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params valleyview_cursor_wm_info = { - I965_CURSOR_FIFO, - VALLEYVIEW_CURSOR_MAX_WM, - I965_CURSOR_DFT_WM, - 2, - G4X_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params i965_cursor_wm_info = { - I965_CURSOR_FIFO, - I965_CURSOR_MAX_WM, - I965_CURSOR_DFT_WM, - 2, - I915_FIFO_LINE_SIZE, -}; -static const struct intel_watermark_params i945_wm_info = { - I945_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I915_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i915_wm_info = { - I915_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I915_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i855_wm_info = { - I855GM_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I830_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params i830_wm_info = { - I830_FIFO_SIZE, - I915_MAX_WM, - 1, - 2, - I830_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params ironlake_display_wm_info = { - ILK_DISPLAY_FIFO, - ILK_DISPLAY_MAXWM, - ILK_DISPLAY_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_wm_info = { - ILK_CURSOR_FIFO, - ILK_CURSOR_MAXWM, - ILK_CURSOR_DFTWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_display_srwm_info = { - ILK_DISPLAY_SR_FIFO, - ILK_DISPLAY_MAX_SRWM, - ILK_DISPLAY_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params ironlake_cursor_srwm_info = { - ILK_CURSOR_SR_FIFO, - ILK_CURSOR_MAX_SRWM, - ILK_CURSOR_DFT_SRWM, - 2, - ILK_FIFO_LINE_SIZE -}; - -static const struct intel_watermark_params sandybridge_display_wm_info = { - SNB_DISPLAY_FIFO, - SNB_DISPLAY_MAXWM, - SNB_DISPLAY_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_wm_info = { - SNB_CURSOR_FIFO, - SNB_CURSOR_MAXWM, - SNB_CURSOR_DFTWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_display_srwm_info = { - SNB_DISPLAY_SR_FIFO, - SNB_DISPLAY_MAX_SRWM, - SNB_DISPLAY_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; -static const struct intel_watermark_params sandybridge_cursor_srwm_info = { - SNB_CURSOR_SR_FIFO, - SNB_CURSOR_MAX_SRWM, - SNB_CURSOR_DFT_SRWM, - 2, - SNB_FIFO_LINE_SIZE -}; - - -/** - * intel_calculate_wm - calculate watermark level - * @clock_in_khz: pixel clock - * @wm: chip FIFO params - * @pixel_size: display pixel size - * @latency_ns: memory latency for the platform - * - * Calculate the watermark level (the level at which the display plane will - * start fetching from memory again). Each chip has a different display - * FIFO size and allocation, so the caller needs to figure that out and pass - * in the correct intel_watermark_params structure. - * - * As the pixel clock runs, the FIFO will be drained at a rate that depends - * on the pixel size. When it reaches the watermark level, it'll start - * fetching FIFO line sized based chunks from memory until the FIFO fills - * past the watermark point. If the FIFO drains completely, a FIFO underrun - * will occur, and a display engine hang could result. - */ -static unsigned long intel_calculate_wm(unsigned long clock_in_khz, - const struct intel_watermark_params *wm, - int fifo_size, - int pixel_size, - unsigned long latency_ns) -{ - long entries_required, wm_size; - - /* - * Note: we need to make sure we don't overflow for various clock & - * latency values. - * clocks go from a few thousand to several hundred thousand. - * latency is usually a few thousand - */ - entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / - 1000; - entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size); - - DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required); - - wm_size = fifo_size - (entries_required + wm->guard_size); - - DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size); - - /* Don't promote wm_size to unsigned... */ - if (wm_size > (long)wm->max_wm) - wm_size = wm->max_wm; - if (wm_size <= 0) - wm_size = wm->default_wm; - return wm_size; -} - -struct cxsr_latency { - int is_desktop; - int is_ddr3; - unsigned long fsb_freq; - unsigned long mem_freq; - unsigned long display_sr; - unsigned long display_hpll_disable; - unsigned long cursor_sr; - unsigned long cursor_hpll_disable; -}; - -static const struct cxsr_latency cxsr_latency_table[] = { - {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ - {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ - {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ - {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ - {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ - - {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ - {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ - {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ - {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ - {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ - - {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ - {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ - {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ - {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ - {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ - - {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ - {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ - {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ - {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ - {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ - - {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ - {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ - {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ - {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ - {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ - - {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ - {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ - {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ - {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ - {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ -}; - -static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, - int is_ddr3, - int fsb, - int mem) -{ - const struct cxsr_latency *latency; - int i; - - if (fsb == 0 || mem == 0) - return NULL; - - for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { - latency = &cxsr_latency_table[i]; - if (is_desktop == latency->is_desktop && - is_ddr3 == latency->is_ddr3 && - fsb == latency->fsb_freq && mem == latency->mem_freq) - return latency; - } - - DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); - - return NULL; -} - -static void pineview_disable_cxsr(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* deactivate cxsr */ - I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); -} - -/* - * Latency for FIFO fetches is dependent on several factors: - * - memory configuration (speed, channels) - * - chipset - * - current MCH state - * It can be fairly high in some situations, so here we assume a fairly - * pessimal value. It's a tradeoff between extra memory fetches (if we - * set this value too high, the FIFO will fetch frequently to stay full) - * and power consumption (set it too low to save power and we might see - * FIFO underruns and display "flicker"). - * - * A value of 5us seems to be a good balance; safe for very low end - * platforms but not overly aggressive on lower latency configs. - */ -static const int latency_ns = 5000; - -static int i9xx_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - if (plane) - size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static int i85x_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x1ff; - if (plane) - size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size; - size >>= 1; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static int i845_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - size >>= 2; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", - size); - - return size; -} - -static int i830_get_fifo_size(struct drm_device *dev, int plane) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dsparb = I915_READ(DSPARB); - int size; - - size = dsparb & 0x7f; - size >>= 1; /* Convert to cachelines */ - - DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, - plane ? "B" : "A", size); - - return size; -} - -static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) -{ - struct drm_crtc *crtc, *enabled = NULL; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->enabled && crtc->fb) { - if (enabled) - return NULL; - enabled = crtc; - } - } - - return enabled; -} - -static void pineview_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - const struct cxsr_latency *latency; - u32 reg; - unsigned long wm; - - latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, - dev_priv->fsb_freq, dev_priv->mem_freq); - if (!latency) { - DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); - pineview_disable_cxsr(dev); - return; - } - - crtc = single_enabled_crtc(dev); - if (crtc) { - int clock = crtc->mode.clock; - int pixel_size = crtc->fb->bits_per_pixel / 8; - - /* Display SR */ - wm = intel_calculate_wm(clock, &pineview_display_wm, - pineview_display_wm.fifo_size, - pixel_size, latency->display_sr); - reg = I915_READ(DSPFW1); - reg &= ~DSPFW_SR_MASK; - reg |= wm << DSPFW_SR_SHIFT; - I915_WRITE(DSPFW1, reg); - DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); - - /* cursor SR */ - wm = intel_calculate_wm(clock, &pineview_cursor_wm, - pineview_display_wm.fifo_size, - pixel_size, latency->cursor_sr); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_CURSOR_SR_MASK; - reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT; - I915_WRITE(DSPFW3, reg); - - /* Display HPLL off SR */ - wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, - pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->display_hpll_disable); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_HPLL_SR_MASK; - reg |= wm & DSPFW_HPLL_SR_MASK; - I915_WRITE(DSPFW3, reg); - - /* cursor HPLL off SR */ - wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, - pineview_display_hplloff_wm.fifo_size, - pixel_size, latency->cursor_hpll_disable); - reg = I915_READ(DSPFW3); - reg &= ~DSPFW_HPLL_CURSOR_MASK; - reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT; - I915_WRITE(DSPFW3, reg); - DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); - - /* activate cxsr */ - I915_WRITE(DSPFW3, - I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); - DRM_DEBUG_KMS("Self-refresh is enabled\n"); - } else { - pineview_disable_cxsr(dev); - DRM_DEBUG_KMS("Self-refresh is disabled\n"); - } -} - -static bool g4x_compute_wm0(struct drm_device *dev, - int plane, - const struct intel_watermark_params *display, - int display_latency_ns, - const struct intel_watermark_params *cursor, - int cursor_latency_ns, - int *plane_wm, - int *cursor_wm) -{ - struct drm_crtc *crtc; - int htotal, hdisplay, clock, pixel_size; - int line_time_us, line_count; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { - *cursor_wm = cursor->guard_size; - *plane_wm = display->guard_size; - return false; - } - - htotal = crtc->mode.htotal; - hdisplay = crtc->mode.hdisplay; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - /* Use the small buffer method to calculate plane watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = DIV_ROUND_UP(entries, display->cacheline_size); - *plane_wm = entries + display->guard_size; - if (*plane_wm > (int)display->max_wm) - *plane_wm = display->max_wm; - - /* Use the large buffer method to calculate cursor watermark */ - line_time_us = ((htotal * 1000) / clock); - line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; - entries = line_count * 64 * pixel_size; - tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = DIV_ROUND_UP(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - if (*cursor_wm > (int)cursor->max_wm) - *cursor_wm = (int)cursor->max_wm; - - return true; -} - -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool g4x_check_srwm(struct drm_device *dev, - int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n", - display_wm, cursor_wm); - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n", - display_wm, display->max_wm); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n", - cursor_wm, cursor->max_wm); - return false; - } - - if (!(display_wm || cursor_wm)) { - DRM_DEBUG_KMS("SR latency is 0, disabling\n"); - return false; - } - - return true; -} - -static bool g4x_compute_srwm(struct drm_device *dev, - int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - int hdisplay, htotal, pixel_size, clock; - unsigned long line_time_us; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - hdisplay = crtc->mode.hdisplay; - htotal = crtc->mode.htotal; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return g4x_check_srwm(dev, - *display_wm, *cursor_wm, - display, cursor); -} - -static bool vlv_compute_drain_latency(struct drm_device *dev, - int plane, - int *plane_prec_mult, - int *plane_dl, - int *cursor_prec_mult, - int *cursor_dl) -{ - struct drm_crtc *crtc; - int clock, pixel_size; - int entries; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) - return false; - - clock = crtc->mode.clock; /* VESA DOT Clock */ - pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */ - - entries = (clock / 1000) * pixel_size; - *plane_prec_mult = (entries > 256) ? - DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; - *plane_dl = (64 * (*plane_prec_mult) * 4) / ((clock / 1000) * - pixel_size); - - entries = (clock / 1000) * 4; /* BPP is always 4 for cursor */ - *cursor_prec_mult = (entries > 256) ? - DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; - *cursor_dl = (64 * (*cursor_prec_mult) * 4) / ((clock / 1000) * 4); - - return true; -} - -/* - * Update drain latency registers of memory arbiter - * - * Valleyview SoC has a new memory arbiter and needs drain latency registers - * to be programmed. Each plane has a drain latency multiplier and a drain - * latency value. - */ - -static void vlv_update_drain_latency(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int planea_prec, planea_dl, planeb_prec, planeb_dl; - int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl; - int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is - either 16 or 32 */ - - /* For plane A, Cursor A */ - if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl, - &cursor_prec_mult, &cursora_dl)) { - cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_16; - planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_16; - - I915_WRITE(VLV_DDL1, cursora_prec | - (cursora_dl << DDL_CURSORA_SHIFT) | - planea_prec | planea_dl); - } - - /* For plane B, Cursor B */ - if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl, - &cursor_prec_mult, &cursorb_dl)) { - cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_16; - planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? - DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_16; - - I915_WRITE(VLV_DDL2, cursorb_prec | - (cursorb_dl << DDL_CURSORB_SHIFT) | - planeb_prec | planeb_dl); - } -} - -#define single_plane_enabled(mask) is_power_of_2(mask) - -static void valleyview_update_wm(struct drm_device *dev) -{ - static const int sr_latency_ns = 12000; - struct drm_i915_private *dev_priv = dev->dev_private; - int planea_wm, planeb_wm, cursora_wm, cursorb_wm; - int plane_sr, cursor_sr; - unsigned int enabled = 0; - - vlv_update_drain_latency(dev); - - if (g4x_compute_wm0(dev, 0, - &valleyview_wm_info, latency_ns, - &valleyview_cursor_wm_info, latency_ns, - &planea_wm, &cursora_wm)) - enabled |= 1; - - if (g4x_compute_wm0(dev, 1, - &valleyview_wm_info, latency_ns, - &valleyview_cursor_wm_info, latency_ns, - &planeb_wm, &cursorb_wm)) - enabled |= 2; - - plane_sr = cursor_sr = 0; - if (single_plane_enabled(enabled) && - g4x_compute_srwm(dev, ffs(enabled) - 1, - sr_latency_ns, - &valleyview_wm_info, - &valleyview_cursor_wm_info, - &plane_sr, &cursor_sr)) - I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); - else - I915_WRITE(FW_BLC_SELF_VLV, - I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN); - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", - planea_wm, cursora_wm, - planeb_wm, cursorb_wm, - plane_sr, cursor_sr); - - I915_WRITE(DSPFW1, - (plane_sr << DSPFW_SR_SHIFT) | - (cursorb_wm << DSPFW_CURSORB_SHIFT) | - (planeb_wm << DSPFW_PLANEB_SHIFT) | - planea_wm); - I915_WRITE(DSPFW2, - (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | - (cursora_wm << DSPFW_CURSORA_SHIFT)); - I915_WRITE(DSPFW3, - (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT))); -} - -static void g4x_update_wm(struct drm_device *dev) -{ - static const int sr_latency_ns = 12000; - struct drm_i915_private *dev_priv = dev->dev_private; - int planea_wm, planeb_wm, cursora_wm, cursorb_wm; - int plane_sr, cursor_sr; - unsigned int enabled = 0; - - if (g4x_compute_wm0(dev, 0, - &g4x_wm_info, latency_ns, - &g4x_cursor_wm_info, latency_ns, - &planea_wm, &cursora_wm)) - enabled |= 1; - - if (g4x_compute_wm0(dev, 1, - &g4x_wm_info, latency_ns, - &g4x_cursor_wm_info, latency_ns, - &planeb_wm, &cursorb_wm)) - enabled |= 2; - - plane_sr = cursor_sr = 0; - if (single_plane_enabled(enabled) && - g4x_compute_srwm(dev, ffs(enabled) - 1, - sr_latency_ns, - &g4x_wm_info, - &g4x_cursor_wm_info, - &plane_sr, &cursor_sr)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - else - I915_WRITE(FW_BLC_SELF, - I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", - planea_wm, cursora_wm, - planeb_wm, cursorb_wm, - plane_sr, cursor_sr); - - I915_WRITE(DSPFW1, - (plane_sr << DSPFW_SR_SHIFT) | - (cursorb_wm << DSPFW_CURSORB_SHIFT) | - (planeb_wm << DSPFW_PLANEB_SHIFT) | - planea_wm); - I915_WRITE(DSPFW2, - (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | - (cursora_wm << DSPFW_CURSORA_SHIFT)); - /* HPLL off in SR has some issues on G4x... disable it */ - I915_WRITE(DSPFW3, - (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | - (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); -} - -static void i965_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - int srwm = 1; - int cursor_sr = 16; - - /* Calc sr entries for one plane configs */ - crtc = single_enabled_crtc(dev); - if (crtc) { - /* self-refresh has much higher latency */ - static const int sr_latency_ns = 12000; - int clock = crtc->mode.clock; - int htotal = crtc->mode.htotal; - int hdisplay = crtc->mode.hdisplay; - int pixel_size = crtc->fb->bits_per_pixel / 8; - unsigned long line_time_us; - int entries; - - line_time_us = ((htotal * 1000) / clock); - - /* Use ns/us then divide to preserve precision */ - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; - entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE); - srwm = I965_FIFO_SIZE - entries; - if (srwm < 0) - srwm = 1; - srwm &= 0x1ff; - DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n", - entries, srwm); - - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * 64; - entries = DIV_ROUND_UP(entries, - i965_cursor_wm_info.cacheline_size); - cursor_sr = i965_cursor_wm_info.fifo_size - - (entries + i965_cursor_wm_info.guard_size); - - if (cursor_sr > i965_cursor_wm_info.max_wm) - cursor_sr = i965_cursor_wm_info.max_wm; - - DRM_DEBUG_KMS("self-refresh watermark: display plane %d " - "cursor %d\n", srwm, cursor_sr); - - if (IS_CRESTLINE(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); - } else { - /* Turn off self refresh if both pipes are enabled */ - if (IS_CRESTLINE(dev)) - I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) - & ~FW_BLC_SELF_EN); - } - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", - srwm); - - /* 965 has limitations... */ - I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | - (8 << 16) | (8 << 8) | (8 << 0)); - I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); - /* update cursor SR watermark */ - I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); -} - -static void i9xx_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - const struct intel_watermark_params *wm_info; - uint32_t fwater_lo; - uint32_t fwater_hi; - int cwm, srwm = 1; - int fifo_size; - int planea_wm, planeb_wm; - struct drm_crtc *crtc, *enabled = NULL; - - if (IS_I945GM(dev)) - wm_info = &i945_wm_info; - else if (!IS_GEN2(dev)) - wm_info = &i915_wm_info; - else - wm_info = &i855_wm_info; - - fifo_size = dev_priv->display.get_fifo_size(dev, 0); - crtc = intel_get_crtc_for_plane(dev, 0); - if (crtc->enabled && crtc->fb) { - planea_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, - latency_ns); - enabled = crtc; - } else - planea_wm = fifo_size - wm_info->guard_size; - - fifo_size = dev_priv->display.get_fifo_size(dev, 1); - crtc = intel_get_crtc_for_plane(dev, 1); - if (crtc->enabled && crtc->fb) { - planeb_wm = intel_calculate_wm(crtc->mode.clock, - wm_info, fifo_size, - crtc->fb->bits_per_pixel / 8, - latency_ns); - if (enabled == NULL) - enabled = crtc; - else - enabled = NULL; - } else - planeb_wm = fifo_size - wm_info->guard_size; - - DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); - - /* - * Overlay gets an aggressive default since video jitter is bad. - */ - cwm = 2; - - /* Play safe and disable self-refresh before adjusting watermarks. */ - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); - else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); - - /* Calc sr entries for one plane configs */ - if (HAS_FW_BLC(dev) && enabled) { - /* self-refresh has much higher latency */ - static const int sr_latency_ns = 6000; - int clock = enabled->mode.clock; - int htotal = enabled->mode.htotal; - int hdisplay = enabled->mode.hdisplay; - int pixel_size = enabled->fb->bits_per_pixel / 8; - unsigned long line_time_us; - int entries; - - line_time_us = (htotal * 1000) / clock; - - /* Use ns/us then divide to preserve precision */ - entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * - pixel_size * hdisplay; - entries = DIV_ROUND_UP(entries, wm_info->cacheline_size); - DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); - srwm = wm_info->fifo_size - entries; - if (srwm < 0) - srwm = 1; - - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, - FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); - else if (IS_I915GM(dev)) - I915_WRITE(FW_BLC_SELF, srwm & 0x3f); - } - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", - planea_wm, planeb_wm, cwm, srwm); - - fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); - fwater_hi = (cwm & 0x1f); - - /* Set request length to 8 cachelines per fetch */ - fwater_lo = fwater_lo | (1 << 24) | (1 << 8); - fwater_hi = fwater_hi | (1 << 8); - - I915_WRITE(FW_BLC, fwater_lo); - I915_WRITE(FW_BLC2, fwater_hi); - - if (HAS_FW_BLC(dev)) { - if (enabled) { - if (IS_I945G(dev) || IS_I945GM(dev)) - I915_WRITE(FW_BLC_SELF, - FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); - else if (IS_I915GM(dev)) - I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); - DRM_DEBUG_KMS("memory self refresh enabled\n"); - } else - DRM_DEBUG_KMS("memory self refresh disabled\n"); - } -} - -static void i830_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - uint32_t fwater_lo; - int planea_wm; - - crtc = single_enabled_crtc(dev); - if (crtc == NULL) - return; - - planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, - dev_priv->display.get_fifo_size(dev, 0), - crtc->fb->bits_per_pixel / 8, - latency_ns); - fwater_lo = I915_READ(FW_BLC) & ~0xfff; - fwater_lo |= (3<<8) | planea_wm; - - DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); - - I915_WRITE(FW_BLC, fwater_lo); -} - -#define ILK_LP0_PLANE_LATENCY 700 -#define ILK_LP0_CURSOR_LATENCY 1300 - -/* - * Check the wm result. - * - * If any calculated watermark values is larger than the maximum value that - * can be programmed into the associated watermark register, that watermark - * must be disabled. - */ -static bool ironlake_check_srwm(struct drm_device *dev, int level, - int fbc_wm, int display_wm, int cursor_wm, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," - " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); - - if (fbc_wm > SNB_FBC_MAX_SRWM) { - DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", - fbc_wm, SNB_FBC_MAX_SRWM, level); - - /* fbc has it's own way to disable FBC WM */ - I915_WRITE(DISP_ARB_CTL, - I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); - return false; - } - - if (display_wm > display->max_wm) { - DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", - display_wm, SNB_DISPLAY_MAX_SRWM, level); - return false; - } - - if (cursor_wm > cursor->max_wm) { - DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", - cursor_wm, SNB_CURSOR_MAX_SRWM, level); - return false; - } - - if (!(fbc_wm || display_wm || cursor_wm)) { - DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); - return false; - } - - return true; -} - -/* - * Compute watermark values of WM[1-3], - */ -static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, - int latency_ns, - const struct intel_watermark_params *display, - const struct intel_watermark_params *cursor, - int *fbc_wm, int *display_wm, int *cursor_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int hdisplay, htotal, pixel_size, clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *fbc_wm = *display_wm = *cursor_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - hdisplay = crtc->mode.hdisplay; - htotal = crtc->mode.htotal; - clock = crtc->mode.clock; - pixel_size = crtc->fb->bits_per_pixel / 8; - - line_time_us = (htotal * 1000) / clock; - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = hdisplay * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *display_wm = entries + display->guard_size; - - /* - * Spec says: - * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 - */ - *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; - - /* calculate the self-refresh watermark for display cursor */ - entries = line_count * pixel_size * 64; - entries = DIV_ROUND_UP(entries, cursor->cacheline_size); - *cursor_wm = entries + cursor->guard_size; - - return ironlake_check_srwm(dev, level, - *fbc_wm, *display_wm, *cursor_wm, - display, cursor); -} - -static void ironlake_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, 0, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEA_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1; - } - - if (g4x_compute_wm0(dev, 1, - &ironlake_display_wm_info, - ILK_LP0_PLANE_LATENCY, - &ironlake_cursor_wm_info, - ILK_LP0_CURSOR_LATENCY, - &plane_wm, &cursor_wm)) { - I915_WRITE(WM0_PIPEB_ILK, - (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 2; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled)) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - ILK_READ_WM1_LATENCY() * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - ILK_READ_WM2_LATENCY() * 500, - &ironlake_display_srwm_info, - &ironlake_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* - * WM3 is unsupported on ILK, probably because we don't have latency - * data for that power state - */ -} - -static void sandybridge_update_wm(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ - u32 val; - int fbc_wm, plane_wm, cursor_wm; - unsigned int enabled; - - enabled = 0; - if (g4x_compute_wm0(dev, 0, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEA_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEA_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe A -" - " plane %d, " "cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 1; - } - - if (g4x_compute_wm0(dev, 1, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEB_ILK); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEB_ILK, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe B -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 2; - } - - /* IVB has 3 pipes */ - if (IS_IVYBRIDGE(dev) && - g4x_compute_wm0(dev, 2, - &sandybridge_display_wm_info, latency, - &sandybridge_cursor_wm_info, latency, - &plane_wm, &cursor_wm)) { - val = I915_READ(WM0_PIPEC_IVB); - val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); - I915_WRITE(WM0_PIPEC_IVB, val | - ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); - DRM_DEBUG_KMS("FIFO watermarks For pipe C -" - " plane %d, cursor: %d\n", - plane_wm, cursor_wm); - enabled |= 3; - } - - /* - * Calculate and update the self-refresh watermark only when one - * display plane is used. - * - * SNB support 3 levels of watermark. - * - * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, - * and disabled in the descending order - * - */ - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - if (!single_plane_enabled(enabled) || - dev_priv->sprite_scaling_enabled) - return; - enabled = ffs(enabled) - 1; - - /* WM1 */ - if (!ironlake_compute_srwm(dev, 1, enabled, - SNB_READ_WM1_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM1_LP_ILK, - WM1_LP_SR_EN | - (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM2 */ - if (!ironlake_compute_srwm(dev, 2, enabled, - SNB_READ_WM2_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM2_LP_ILK, - WM2_LP_EN | - (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); - - /* WM3 */ - if (!ironlake_compute_srwm(dev, 3, enabled, - SNB_READ_WM3_LATENCY() * 500, - &sandybridge_display_srwm_info, - &sandybridge_cursor_srwm_info, - &fbc_wm, &plane_wm, &cursor_wm)) - return; - - I915_WRITE(WM3_LP_ILK, - WM3_LP_EN | - (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | - (fbc_wm << WM1_LP_FBC_SHIFT) | - (plane_wm << WM1_LP_SR_SHIFT) | - cursor_wm); -} - -static bool -sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int display_latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - int clock; - int entries, tlb_miss; - - crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) { - *sprite_wm = display->guard_size; - return false; - } - - clock = crtc->mode.clock; - - /* Use the small buffer method to calculate the sprite watermark */ - entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; - tlb_miss = display->fifo_size*display->cacheline_size - - sprite_width * 8; - if (tlb_miss > 0) - entries += tlb_miss; - entries = DIV_ROUND_UP(entries, display->cacheline_size); - *sprite_wm = entries + display->guard_size; - if (*sprite_wm > (int)display->max_wm) - *sprite_wm = display->max_wm; - - return true; -} - -static bool -sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, - uint32_t sprite_width, int pixel_size, - const struct intel_watermark_params *display, - int latency_ns, int *sprite_wm) -{ - struct drm_crtc *crtc; - unsigned long line_time_us; - int clock; - int line_count, line_size; - int small, large; - int entries; - - if (!latency_ns) { - *sprite_wm = 0; - return false; - } - - crtc = intel_get_crtc_for_plane(dev, plane); - clock = crtc->mode.clock; - if (!clock) { - *sprite_wm = 0; - return false; - } - - line_time_us = (sprite_width * 1000) / clock; - if (!line_time_us) { - *sprite_wm = 0; - return false; - } - - line_count = (latency_ns / line_time_us + 1000) / 1000; - line_size = sprite_width * pixel_size; - - /* Use the minimum of the small and large buffer method for primary */ - small = ((clock * pixel_size / 1000) * latency_ns) / 1000; - large = line_count * line_size; - - entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); - *sprite_wm = entries + display->guard_size; - - return *sprite_wm > 0x3ff ? false : true; -} - -static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ - u32 val; - int sprite_wm, reg; - int ret; - - switch (pipe) { - case 0: - reg = WM0_PIPEA_ILK; - break; - case 1: - reg = WM0_PIPEB_ILK; - break; - case 2: - reg = WM0_PIPEC_IVB; - break; - default: - return; /* bad pipe */ - } - - ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, - &sandybridge_display_wm_info, - latency, &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", - pipe); - return; - } - - val = I915_READ(reg); - val &= ~WM0_PIPE_SPRITE_MASK; - I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); - DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); - - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM1_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM1S_LP_ILK, sprite_wm); - - /* Only IVB has two more LP watermarks for sprite */ - if (!IS_IVYBRIDGE(dev)) - return; - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM2_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM2S_LP_IVB, sprite_wm); - - ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, - pixel_size, - &sandybridge_display_srwm_info, - SNB_READ_WM3_LATENCY() * 500, - &sprite_wm); - if (!ret) { - DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", - pipe); - return; - } - I915_WRITE(WM3S_LP_IVB, sprite_wm); -} - -/** - * intel_update_watermarks - update FIFO watermark values based on current modes - * - * Calculate watermark values for the various WM regs based on current mode - * and plane configuration. - * - * There are several cases to deal with here: - * - normal (i.e. non-self-refresh) - * - self-refresh (SR) mode - * - lines are large relative to FIFO size (buffer can hold up to 2) - * - lines are small relative to FIFO size (buffer can hold more than 2 - * lines), so need to account for TLB latency - * - * The normal calculation is: - * watermark = dotclock * bytes per pixel * latency - * where latency is platform & configuration dependent (we assume pessimal - * values here). - * - * The SR calculation is: - * watermark = (trunc(latency/line time)+1) * surface width * - * bytes per pixel - * where - * line time = htotal / dotclock - * surface width = hdisplay for normal plane and 64 for cursor - * and latency is assumed to be high, as above. - * - * The final value programmed to the register should always be rounded up, - * and include an extra 2 entries to account for clock crossings. - * - * We don't use the sprite, so we can ignore that. And on Crestline we have - * to set the non-SR watermarks to 8. - */ -void intel_update_watermarks(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.update_wm) - dev_priv->display.update_wm(dev); -} - -void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->display.update_sprite_wm) - dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, - pixel_size); -} - static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) { if (i915_panel_use_ssc >= 0) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index def112e..f1e27ce 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -204,6 +204,25 @@ struct intel_plane { struct drm_intel_sprite_colorkey *key); }; +struct intel_watermark_params { + unsigned long fifo_size; + unsigned long max_wm; + unsigned long default_wm; + unsigned long guard_size; + unsigned long cacheline_size; +}; + +struct cxsr_latency { + int is_desktop; + int is_ddr3; + unsigned long fsb_freq; + unsigned long mem_freq; + unsigned long display_sr; + unsigned long display_hpll_disable; + unsigned long cursor_sr; + unsigned long cursor_hpll_disable; +}; + #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) @@ -449,4 +468,25 @@ extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern void intel_update_fbc(struct drm_device *dev); +/* Watermarks */ +extern void pineview_update_wm(struct drm_device *dev); +extern void valleyview_update_wm(struct drm_device *dev); +extern void g4x_update_wm(struct drm_device *dev); +extern void i965_update_wm(struct drm_device *dev); +extern void i9xx_update_wm(struct drm_device *dev); +extern void i830_update_wm(struct drm_device *dev); +extern void ironlake_update_wm(struct drm_device *dev); +extern void sandybridge_update_wm(struct drm_device *dev); +extern void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size); +extern const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, + int is_ddr3, + int fsb, + int mem); +extern void pineview_disable_cxsr(struct drm_device *dev); +extern int i9xx_get_fifo_size(struct drm_device *dev, int plane); +extern int i85x_get_fifo_size(struct drm_device *dev, int plane); +extern int i845_get_fifo_size(struct drm_device *dev, int plane); +extern int i830_get_fifo_size(struct drm_device *dev, int plane); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 7fbd305..b208165 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -519,3 +519,1459 @@ out_disable: } } +static const struct cxsr_latency cxsr_latency_table[] = { + {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */ + {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */ + {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */ + {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */ + {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */ + + {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */ + {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */ + {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */ + {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */ + {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */ + + {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */ + {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */ + {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */ + {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */ + {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */ + + {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */ + {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */ + {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */ + {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */ + {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */ + + {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */ + {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */ + {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */ + {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */ + {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */ + + {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */ + {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */ + {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */ + {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */ + {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */ +}; + +const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, + int is_ddr3, + int fsb, + int mem) +{ + const struct cxsr_latency *latency; + int i; + + if (fsb == 0 || mem == 0) + return NULL; + + for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) { + latency = &cxsr_latency_table[i]; + if (is_desktop == latency->is_desktop && + is_ddr3 == latency->is_ddr3 && + fsb == latency->fsb_freq && mem == latency->mem_freq) + return latency; + } + + DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); + + return NULL; +} + +void pineview_disable_cxsr(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* deactivate cxsr */ + I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN); +} + +/* + * Latency for FIFO fetches is dependent on several factors: + * - memory configuration (speed, channels) + * - chipset + * - current MCH state + * It can be fairly high in some situations, so here we assume a fairly + * pessimal value. It's a tradeoff between extra memory fetches (if we + * set this value too high, the FIFO will fetch frequently to stay full) + * and power consumption (set it too low to save power and we might see + * FIFO underruns and display "flicker"). + * + * A value of 5us seems to be a good balance; safe for very low end + * platforms but not overly aggressive on lower latency configs. + */ +static const int latency_ns = 5000; + +int i9xx_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + if (plane) + size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +int i85x_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x1ff; + if (plane) + size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size; + size >>= 1; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +int i845_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + size >>= 2; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", + size); + + return size; +} + +int i830_get_fifo_size(struct drm_device *dev, int plane) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dsparb = I915_READ(DSPARB); + int size; + + size = dsparb & 0x7f; + size >>= 1; /* Convert to cachelines */ + + DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, + plane ? "B" : "A", size); + + return size; +} + +/* Pineview has different values for various configs */ +static const struct intel_watermark_params pineview_display_wm = { + PINEVIEW_DISPLAY_FIFO, + PINEVIEW_MAX_WM, + PINEVIEW_DFT_WM, + PINEVIEW_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params pineview_display_hplloff_wm = { + PINEVIEW_DISPLAY_FIFO, + PINEVIEW_MAX_WM, + PINEVIEW_DFT_HPLLOFF_WM, + PINEVIEW_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params pineview_cursor_wm = { + PINEVIEW_CURSOR_FIFO, + PINEVIEW_CURSOR_MAX_WM, + PINEVIEW_CURSOR_DFT_WM, + PINEVIEW_CURSOR_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params pineview_cursor_hplloff_wm = { + PINEVIEW_CURSOR_FIFO, + PINEVIEW_CURSOR_MAX_WM, + PINEVIEW_CURSOR_DFT_WM, + PINEVIEW_CURSOR_GUARD_WM, + PINEVIEW_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params g4x_wm_info = { + G4X_FIFO_SIZE, + G4X_MAX_WM, + G4X_MAX_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params g4x_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params valleyview_wm_info = { + VALLEYVIEW_FIFO_SIZE, + VALLEYVIEW_MAX_WM, + VALLEYVIEW_MAX_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params valleyview_cursor_wm_info = { + I965_CURSOR_FIFO, + VALLEYVIEW_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params i965_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + I915_FIFO_LINE_SIZE, +}; +static const struct intel_watermark_params i945_wm_info = { + I945_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I915_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i915_wm_info = { + I915_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I915_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i855_wm_info = { + I855GM_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I830_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params i830_wm_info = { + I830_FIFO_SIZE, + I915_MAX_WM, + 1, + 2, + I830_FIFO_LINE_SIZE +}; + +static const struct intel_watermark_params ironlake_display_wm_info = { + ILK_DISPLAY_FIFO, + ILK_DISPLAY_MAXWM, + ILK_DISPLAY_DFTWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_cursor_wm_info = { + ILK_CURSOR_FIFO, + ILK_CURSOR_MAXWM, + ILK_CURSOR_DFTWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_display_srwm_info = { + ILK_DISPLAY_SR_FIFO, + ILK_DISPLAY_MAX_SRWM, + ILK_DISPLAY_DFT_SRWM, + 2, + ILK_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params ironlake_cursor_srwm_info = { + ILK_CURSOR_SR_FIFO, + ILK_CURSOR_MAX_SRWM, + ILK_CURSOR_DFT_SRWM, + 2, + ILK_FIFO_LINE_SIZE +}; + +static const struct intel_watermark_params sandybridge_display_wm_info = { + SNB_DISPLAY_FIFO, + SNB_DISPLAY_MAXWM, + SNB_DISPLAY_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_cursor_wm_info = { + SNB_CURSOR_FIFO, + SNB_CURSOR_MAXWM, + SNB_CURSOR_DFTWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_display_srwm_info = { + SNB_DISPLAY_SR_FIFO, + SNB_DISPLAY_MAX_SRWM, + SNB_DISPLAY_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; +static const struct intel_watermark_params sandybridge_cursor_srwm_info = { + SNB_CURSOR_SR_FIFO, + SNB_CURSOR_MAX_SRWM, + SNB_CURSOR_DFT_SRWM, + 2, + SNB_FIFO_LINE_SIZE +}; + + +/** + * intel_calculate_wm - calculate watermark level + * @clock_in_khz: pixel clock + * @wm: chip FIFO params + * @pixel_size: display pixel size + * @latency_ns: memory latency for the platform + * + * Calculate the watermark level (the level at which the display plane will + * start fetching from memory again). Each chip has a different display + * FIFO size and allocation, so the caller needs to figure that out and pass + * in the correct intel_watermark_params structure. + * + * As the pixel clock runs, the FIFO will be drained at a rate that depends + * on the pixel size. When it reaches the watermark level, it'll start + * fetching FIFO line sized based chunks from memory until the FIFO fills + * past the watermark point. If the FIFO drains completely, a FIFO underrun + * will occur, and a display engine hang could result. + */ +static unsigned long intel_calculate_wm(unsigned long clock_in_khz, + const struct intel_watermark_params *wm, + int fifo_size, + int pixel_size, + unsigned long latency_ns) +{ + long entries_required, wm_size; + + /* + * Note: we need to make sure we don't overflow for various clock & + * latency values. + * clocks go from a few thousand to several hundred thousand. + * latency is usually a few thousand + */ + entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / + 1000; + entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size); + + DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required); + + wm_size = fifo_size - (entries_required + wm->guard_size); + + DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size); + + /* Don't promote wm_size to unsigned... */ + if (wm_size > (long)wm->max_wm) + wm_size = wm->max_wm; + if (wm_size <= 0) + wm_size = wm->default_wm; + return wm_size; +} + +static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) +{ + struct drm_crtc *crtc, *enabled = NULL; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if (crtc->enabled && crtc->fb) { + if (enabled) + return NULL; + enabled = crtc; + } + } + + return enabled; +} + +void pineview_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + const struct cxsr_latency *latency; + u32 reg; + unsigned long wm; + + latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3, + dev_priv->fsb_freq, dev_priv->mem_freq); + if (!latency) { + DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n"); + pineview_disable_cxsr(dev); + return; + } + + crtc = single_enabled_crtc(dev); + if (crtc) { + int clock = crtc->mode.clock; + int pixel_size = crtc->fb->bits_per_pixel / 8; + + /* Display SR */ + wm = intel_calculate_wm(clock, &pineview_display_wm, + pineview_display_wm.fifo_size, + pixel_size, latency->display_sr); + reg = I915_READ(DSPFW1); + reg &= ~DSPFW_SR_MASK; + reg |= wm << DSPFW_SR_SHIFT; + I915_WRITE(DSPFW1, reg); + DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg); + + /* cursor SR */ + wm = intel_calculate_wm(clock, &pineview_cursor_wm, + pineview_display_wm.fifo_size, + pixel_size, latency->cursor_sr); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_CURSOR_SR_MASK; + reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT; + I915_WRITE(DSPFW3, reg); + + /* Display HPLL off SR */ + wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, + pixel_size, latency->display_hpll_disable); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_HPLL_SR_MASK; + reg |= wm & DSPFW_HPLL_SR_MASK; + I915_WRITE(DSPFW3, reg); + + /* cursor HPLL off SR */ + wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm, + pineview_display_hplloff_wm.fifo_size, + pixel_size, latency->cursor_hpll_disable); + reg = I915_READ(DSPFW3); + reg &= ~DSPFW_HPLL_CURSOR_MASK; + reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT; + I915_WRITE(DSPFW3, reg); + DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg); + + /* activate cxsr */ + I915_WRITE(DSPFW3, + I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN); + DRM_DEBUG_KMS("Self-refresh is enabled\n"); + } else { + pineview_disable_cxsr(dev); + DRM_DEBUG_KMS("Self-refresh is disabled\n"); + } +} + +static bool g4x_compute_wm0(struct drm_device *dev, + int plane, + const struct intel_watermark_params *display, + int display_latency_ns, + const struct intel_watermark_params *cursor, + int cursor_latency_ns, + int *plane_wm, + int *cursor_wm) +{ + struct drm_crtc *crtc; + int htotal, hdisplay, clock, pixel_size; + int line_time_us, line_count; + int entries, tlb_miss; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) { + *cursor_wm = cursor->guard_size; + *plane_wm = display->guard_size; + return false; + } + + htotal = crtc->mode.htotal; + hdisplay = crtc->mode.hdisplay; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + /* Use the small buffer method to calculate plane watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *plane_wm = entries + display->guard_size; + if (*plane_wm > (int)display->max_wm) + *plane_wm = display->max_wm; + + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = ((htotal * 1000) / clock); + line_count = (cursor_latency_ns / line_time_us + 1000) / 1000; + entries = line_count * 64 * pixel_size; + tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + if (*cursor_wm > (int)cursor->max_wm) + *cursor_wm = (int)cursor->max_wm; + + return true; +} + +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + */ +static bool g4x_check_srwm(struct drm_device *dev, + int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) +{ + DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n", + display_wm, cursor_wm); + + if (display_wm > display->max_wm) { + DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n", + display_wm, display->max_wm); + return false; + } + + if (cursor_wm > cursor->max_wm) { + DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n", + cursor_wm, cursor->max_wm); + return false; + } + + if (!(display_wm || cursor_wm)) { + DRM_DEBUG_KMS("SR latency is 0, disabling\n"); + return false; + } + + return true; +} + +static bool g4x_compute_srwm(struct drm_device *dev, + int plane, + int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *display_wm, int *cursor_wm) +{ + struct drm_crtc *crtc; + int hdisplay, htotal, pixel_size, clock; + unsigned long line_time_us; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *display_wm = *cursor_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + + return g4x_check_srwm(dev, + *display_wm, *cursor_wm, + display, cursor); +} + +static bool vlv_compute_drain_latency(struct drm_device *dev, + int plane, + int *plane_prec_mult, + int *plane_dl, + int *cursor_prec_mult, + int *cursor_dl) +{ + struct drm_crtc *crtc; + int clock, pixel_size; + int entries; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) + return false; + + clock = crtc->mode.clock; /* VESA DOT Clock */ + pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */ + + entries = (clock / 1000) * pixel_size; + *plane_prec_mult = (entries > 256) ? + DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; + *plane_dl = (64 * (*plane_prec_mult) * 4) / ((clock / 1000) * + pixel_size); + + entries = (clock / 1000) * 4; /* BPP is always 4 for cursor */ + *cursor_prec_mult = (entries > 256) ? + DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16; + *cursor_dl = (64 * (*cursor_prec_mult) * 4) / ((clock / 1000) * 4); + + return true; +} + +/* + * Update drain latency registers of memory arbiter + * + * Valleyview SoC has a new memory arbiter and needs drain latency registers + * to be programmed. Each plane has a drain latency multiplier and a drain + * latency value. + */ + +static void vlv_update_drain_latency(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_prec, planea_dl, planeb_prec, planeb_dl; + int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl; + int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is + either 16 or 32 */ + + /* For plane A, Cursor A */ + if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl, + &cursor_prec_mult, &cursora_dl)) { + cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_16; + planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_16; + + I915_WRITE(VLV_DDL1, cursora_prec | + (cursora_dl << DDL_CURSORA_SHIFT) | + planea_prec | planea_dl); + } + + /* For plane B, Cursor B */ + if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl, + &cursor_prec_mult, &cursorb_dl)) { + cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_16; + planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ? + DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_16; + + I915_WRITE(VLV_DDL2, cursorb_prec | + (cursorb_dl << DDL_CURSORB_SHIFT) | + planeb_prec | planeb_dl); + } +} + +#define single_plane_enabled(mask) is_power_of_2(mask) + +void valleyview_update_wm(struct drm_device *dev) +{ + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, cursora_wm, cursorb_wm; + int plane_sr, cursor_sr; + unsigned int enabled = 0; + + vlv_update_drain_latency(dev); + + if (g4x_compute_wm0(dev, 0, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1; + + if (g4x_compute_wm0(dev, 1, + &valleyview_wm_info, latency_ns, + &valleyview_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 2; + + plane_sr = cursor_sr = 0; + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &valleyview_wm_info, + &valleyview_cursor_wm_info, + &plane_sr, &cursor_sr)) + I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN); + else + I915_WRITE(FW_BLC_SELF_VLV, + I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN); + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + plane_sr, cursor_sr); + + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | + (cursorb_wm << DSPFW_CURSORB_SHIFT) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + planea_wm); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (cursora_wm << DSPFW_CURSORA_SHIFT)); + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT))); +} + +void g4x_update_wm(struct drm_device *dev) +{ + static const int sr_latency_ns = 12000; + struct drm_i915_private *dev_priv = dev->dev_private; + int planea_wm, planeb_wm, cursora_wm, cursorb_wm; + int plane_sr, cursor_sr; + unsigned int enabled = 0; + + if (g4x_compute_wm0(dev, 0, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planea_wm, &cursora_wm)) + enabled |= 1; + + if (g4x_compute_wm0(dev, 1, + &g4x_wm_info, latency_ns, + &g4x_cursor_wm_info, latency_ns, + &planeb_wm, &cursorb_wm)) + enabled |= 2; + + plane_sr = cursor_sr = 0; + if (single_plane_enabled(enabled) && + g4x_compute_srwm(dev, ffs(enabled) - 1, + sr_latency_ns, + &g4x_wm_info, + &g4x_cursor_wm_info, + &plane_sr, &cursor_sr)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + else + I915_WRITE(FW_BLC_SELF, + I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN); + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n", + planea_wm, cursora_wm, + planeb_wm, cursorb_wm, + plane_sr, cursor_sr); + + I915_WRITE(DSPFW1, + (plane_sr << DSPFW_SR_SHIFT) | + (cursorb_wm << DSPFW_CURSORB_SHIFT) | + (planeb_wm << DSPFW_PLANEB_SHIFT) | + planea_wm); + I915_WRITE(DSPFW2, + (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) | + (cursora_wm << DSPFW_CURSORA_SHIFT)); + /* HPLL off in SR has some issues on G4x... disable it */ + I915_WRITE(DSPFW3, + (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) | + (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); +} + +void i965_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + int srwm = 1; + int cursor_sr = 16; + + /* Calc sr entries for one plane configs */ + crtc = single_enabled_crtc(dev); + if (crtc) { + /* self-refresh has much higher latency */ + static const int sr_latency_ns = 12000; + int clock = crtc->mode.clock; + int htotal = crtc->mode.htotal; + int hdisplay = crtc->mode.hdisplay; + int pixel_size = crtc->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; + + line_time_us = ((htotal * 1000) / clock); + + /* Use ns/us then divide to preserve precision */ + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE); + srwm = I965_FIFO_SIZE - entries; + if (srwm < 0) + srwm = 1; + srwm &= 0x1ff; + DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n", + entries, srwm); + + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * 64; + entries = DIV_ROUND_UP(entries, + i965_cursor_wm_info.cacheline_size); + cursor_sr = i965_cursor_wm_info.fifo_size - + (entries + i965_cursor_wm_info.guard_size); + + if (cursor_sr > i965_cursor_wm_info.max_wm) + cursor_sr = i965_cursor_wm_info.max_wm; + + DRM_DEBUG_KMS("self-refresh watermark: display plane %d " + "cursor %d\n", srwm, cursor_sr); + + if (IS_CRESTLINE(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); + } else { + /* Turn off self refresh if both pipes are enabled */ + if (IS_CRESTLINE(dev)) + I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF) + & ~FW_BLC_SELF_EN); + } + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n", + srwm); + + /* 965 has limitations... */ + I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | + (8 << 16) | (8 << 8) | (8 << 0)); + I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); + /* update cursor SR watermark */ + I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); +} + +void i9xx_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct intel_watermark_params *wm_info; + uint32_t fwater_lo; + uint32_t fwater_hi; + int cwm, srwm = 1; + int fifo_size; + int planea_wm, planeb_wm; + struct drm_crtc *crtc, *enabled = NULL; + + if (IS_I945GM(dev)) + wm_info = &i945_wm_info; + else if (!IS_GEN2(dev)) + wm_info = &i915_wm_info; + else + wm_info = &i855_wm_info; + + fifo_size = dev_priv->display.get_fifo_size(dev, 0); + crtc = intel_get_crtc_for_plane(dev, 0); + if (crtc->enabled && crtc->fb) { + planea_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + enabled = crtc; + } else + planea_wm = fifo_size - wm_info->guard_size; + + fifo_size = dev_priv->display.get_fifo_size(dev, 1); + crtc = intel_get_crtc_for_plane(dev, 1); + if (crtc->enabled && crtc->fb) { + planeb_wm = intel_calculate_wm(crtc->mode.clock, + wm_info, fifo_size, + crtc->fb->bits_per_pixel / 8, + latency_ns); + if (enabled == NULL) + enabled = crtc; + else + enabled = NULL; + } else + planeb_wm = fifo_size - wm_info->guard_size; + + DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); + + /* + * Overlay gets an aggressive default since video jitter is bad. + */ + cwm = 2; + + /* Play safe and disable self-refresh before adjusting watermarks. */ + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN); + + /* Calc sr entries for one plane configs */ + if (HAS_FW_BLC(dev) && enabled) { + /* self-refresh has much higher latency */ + static const int sr_latency_ns = 6000; + int clock = enabled->mode.clock; + int htotal = enabled->mode.htotal; + int hdisplay = enabled->mode.hdisplay; + int pixel_size = enabled->fb->bits_per_pixel / 8; + unsigned long line_time_us; + int entries; + + line_time_us = (htotal * 1000) / clock; + + /* Use ns/us then divide to preserve precision */ + entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * hdisplay; + entries = DIV_ROUND_UP(entries, wm_info->cacheline_size); + DRM_DEBUG_KMS("self-refresh entries: %d\n", entries); + srwm = wm_info->fifo_size - entries; + if (srwm < 0) + srwm = 1; + + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_FIFO_MASK | (srwm & 0xff)); + else if (IS_I915GM(dev)) + I915_WRITE(FW_BLC_SELF, srwm & 0x3f); + } + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", + planea_wm, planeb_wm, cwm, srwm); + + fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f); + fwater_hi = (cwm & 0x1f); + + /* Set request length to 8 cachelines per fetch */ + fwater_lo = fwater_lo | (1 << 24) | (1 << 8); + fwater_hi = fwater_hi | (1 << 8); + + I915_WRITE(FW_BLC, fwater_lo); + I915_WRITE(FW_BLC2, fwater_hi); + + if (HAS_FW_BLC(dev)) { + if (enabled) { + if (IS_I945G(dev) || IS_I945GM(dev)) + I915_WRITE(FW_BLC_SELF, + FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN); + else if (IS_I915GM(dev)) + I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN); + DRM_DEBUG_KMS("memory self refresh enabled\n"); + } else + DRM_DEBUG_KMS("memory self refresh disabled\n"); + } +} + +void i830_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + uint32_t fwater_lo; + int planea_wm; + + crtc = single_enabled_crtc(dev); + if (crtc == NULL) + return; + + planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info, + dev_priv->display.get_fifo_size(dev, 0), + crtc->fb->bits_per_pixel / 8, + latency_ns); + fwater_lo = I915_READ(FW_BLC) & ~0xfff; + fwater_lo |= (3<<8) | planea_wm; + + DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm); + + I915_WRITE(FW_BLC, fwater_lo); +} + +#define ILK_LP0_PLANE_LATENCY 700 +#define ILK_LP0_CURSOR_LATENCY 1300 + +/* + * Check the wm result. + * + * If any calculated watermark values is larger than the maximum value that + * can be programmed into the associated watermark register, that watermark + * must be disabled. + */ +static bool ironlake_check_srwm(struct drm_device *dev, int level, + int fbc_wm, int display_wm, int cursor_wm, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d," + " cursor %d\n", level, display_wm, fbc_wm, cursor_wm); + + if (fbc_wm > SNB_FBC_MAX_SRWM) { + DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n", + fbc_wm, SNB_FBC_MAX_SRWM, level); + + /* fbc has it's own way to disable FBC WM */ + I915_WRITE(DISP_ARB_CTL, + I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS); + return false; + } + + if (display_wm > display->max_wm) { + DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n", + display_wm, SNB_DISPLAY_MAX_SRWM, level); + return false; + } + + if (cursor_wm > cursor->max_wm) { + DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n", + cursor_wm, SNB_CURSOR_MAX_SRWM, level); + return false; + } + + if (!(fbc_wm || display_wm || cursor_wm)) { + DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level); + return false; + } + + return true; +} + +/* + * Compute watermark values of WM[1-3], + */ +static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, + int latency_ns, + const struct intel_watermark_params *display, + const struct intel_watermark_params *cursor, + int *fbc_wm, int *display_wm, int *cursor_wm) +{ + struct drm_crtc *crtc; + unsigned long line_time_us; + int hdisplay, htotal, pixel_size, clock; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *fbc_wm = *display_wm = *cursor_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + hdisplay = crtc->mode.hdisplay; + htotal = crtc->mode.htotal; + clock = crtc->mode.clock; + pixel_size = crtc->fb->bits_per_pixel / 8; + + line_time_us = (htotal * 1000) / clock; + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = hdisplay * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *display_wm = entries + display->guard_size; + + /* + * Spec says: + * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2 + */ + *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2; + + /* calculate the self-refresh watermark for display cursor */ + entries = line_count * pixel_size * 64; + entries = DIV_ROUND_UP(entries, cursor->cacheline_size); + *cursor_wm = entries + cursor->guard_size; + + return ironlake_check_srwm(dev, level, + *fbc_wm, *display_wm, *cursor_wm, + display, cursor); +} + +void ironlake_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; + + enabled = 0; + if (g4x_compute_wm0(dev, 0, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEA_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 1; + } + + if (g4x_compute_wm0(dev, 1, + &ironlake_display_wm_info, + ILK_LP0_PLANE_LATENCY, + &ironlake_cursor_wm_info, + ILK_LP0_CURSOR_LATENCY, + &plane_wm, &cursor_wm)) { + I915_WRITE(WM0_PIPEB_ILK, + (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 2; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (!single_plane_enabled(enabled)) + return; + enabled = ffs(enabled) - 1; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, enabled, + ILK_READ_WM1_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, enabled, + ILK_READ_WM2_LATENCY() * 500, + &ironlake_display_srwm_info, + &ironlake_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* + * WM3 is unsupported on ILK, probably because we don't have latency + * data for that power state + */ +} + +void sandybridge_update_wm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + u32 val; + int fbc_wm, plane_wm, cursor_wm; + unsigned int enabled; + + enabled = 0; + if (g4x_compute_wm0(dev, 0, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEA_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEA_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe A -" + " plane %d, " "cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 1; + } + + if (g4x_compute_wm0(dev, 1, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEB_ILK); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEB_ILK, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe B -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 2; + } + + /* IVB has 3 pipes */ + if (IS_IVYBRIDGE(dev) && + g4x_compute_wm0(dev, 2, + &sandybridge_display_wm_info, latency, + &sandybridge_cursor_wm_info, latency, + &plane_wm, &cursor_wm)) { + val = I915_READ(WM0_PIPEC_IVB); + val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); + I915_WRITE(WM0_PIPEC_IVB, val | + ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm)); + DRM_DEBUG_KMS("FIFO watermarks For pipe C -" + " plane %d, cursor: %d\n", + plane_wm, cursor_wm); + enabled |= 3; + } + + /* + * Calculate and update the self-refresh watermark only when one + * display plane is used. + * + * SNB support 3 levels of watermark. + * + * WM1/WM2/WM2 watermarks have to be enabled in the ascending order, + * and disabled in the descending order + * + */ + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + if (!single_plane_enabled(enabled) || + dev_priv->sprite_scaling_enabled) + return; + enabled = ffs(enabled) - 1; + + /* WM1 */ + if (!ironlake_compute_srwm(dev, 1, enabled, + SNB_READ_WM1_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM1_LP_ILK, + WM1_LP_SR_EN | + (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM2 */ + if (!ironlake_compute_srwm(dev, 2, enabled, + SNB_READ_WM2_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM2_LP_ILK, + WM2_LP_EN | + (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); + + /* WM3 */ + if (!ironlake_compute_srwm(dev, 3, enabled, + SNB_READ_WM3_LATENCY() * 500, + &sandybridge_display_srwm_info, + &sandybridge_cursor_srwm_info, + &fbc_wm, &plane_wm, &cursor_wm)) + return; + + I915_WRITE(WM3_LP_ILK, + WM3_LP_EN | + (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) | + (fbc_wm << WM1_LP_FBC_SHIFT) | + (plane_wm << WM1_LP_SR_SHIFT) | + cursor_wm); +} + +static bool +sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int display_latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + int clock; + int entries, tlb_miss; + + crtc = intel_get_crtc_for_plane(dev, plane); + if (crtc->fb == NULL || !crtc->enabled) { + *sprite_wm = display->guard_size; + return false; + } + + clock = crtc->mode.clock; + + /* Use the small buffer method to calculate the sprite watermark */ + entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; + tlb_miss = display->fifo_size*display->cacheline_size - + sprite_width * 8; + if (tlb_miss > 0) + entries += tlb_miss; + entries = DIV_ROUND_UP(entries, display->cacheline_size); + *sprite_wm = entries + display->guard_size; + if (*sprite_wm > (int)display->max_wm) + *sprite_wm = display->max_wm; + + return true; +} + +static bool +sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, + uint32_t sprite_width, int pixel_size, + const struct intel_watermark_params *display, + int latency_ns, int *sprite_wm) +{ + struct drm_crtc *crtc; + unsigned long line_time_us; + int clock; + int line_count, line_size; + int small, large; + int entries; + + if (!latency_ns) { + *sprite_wm = 0; + return false; + } + + crtc = intel_get_crtc_for_plane(dev, plane); + clock = crtc->mode.clock; + if (!clock) { + *sprite_wm = 0; + return false; + } + + line_time_us = (sprite_width * 1000) / clock; + if (!line_time_us) { + *sprite_wm = 0; + return false; + } + + line_count = (latency_ns / line_time_us + 1000) / 1000; + line_size = sprite_width * pixel_size; + + /* Use the minimum of the small and large buffer method for primary */ + small = ((clock * pixel_size / 1000) * latency_ns) / 1000; + large = line_count * line_size; + + entries = DIV_ROUND_UP(min(small, large), display->cacheline_size); + *sprite_wm = entries + display->guard_size; + + return *sprite_wm > 0x3ff ? false : true; +} + +void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ + u32 val; + int sprite_wm, reg; + int ret; + + switch (pipe) { + case 0: + reg = WM0_PIPEA_ILK; + break; + case 1: + reg = WM0_PIPEB_ILK; + break; + case 2: + reg = WM0_PIPEC_IVB; + break; + default: + return; /* bad pipe */ + } + + ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size, + &sandybridge_display_wm_info, + latency, &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n", + pipe); + return; + } + + val = I915_READ(reg); + val &= ~WM0_PIPE_SPRITE_MASK; + I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT)); + DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm); + + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM1_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM1S_LP_ILK, sprite_wm); + + /* Only IVB has two more LP watermarks for sprite */ + if (!IS_IVYBRIDGE(dev)) + return; + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM2_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM2S_LP_IVB, sprite_wm); + + ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width, + pixel_size, + &sandybridge_display_srwm_info, + SNB_READ_WM3_LATENCY() * 500, + &sprite_wm); + if (!ret) { + DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n", + pipe); + return; + } + I915_WRITE(WM3S_LP_IVB, sprite_wm); +} + +/** + * intel_update_watermarks - update FIFO watermark values based on current modes + * + * Calculate watermark values for the various WM regs based on current mode + * and plane configuration. + * + * There are several cases to deal with here: + * - normal (i.e. non-self-refresh) + * - self-refresh (SR) mode + * - lines are large relative to FIFO size (buffer can hold up to 2) + * - lines are small relative to FIFO size (buffer can hold more than 2 + * lines), so need to account for TLB latency + * + * The normal calculation is: + * watermark = dotclock * bytes per pixel * latency + * where latency is platform & configuration dependent (we assume pessimal + * values here). + * + * The SR calculation is: + * watermark = (trunc(latency/line time)+1) * surface width * + * bytes per pixel + * where + * line time = htotal / dotclock + * surface width = hdisplay for normal plane and 64 for cursor + * and latency is assumed to be high, as above. + * + * The final value programmed to the register should always be rounded up, + * and include an extra 2 entries to account for clock crossings. + * + * We don't use the sprite, so we can ignore that. And on Crestline we have + * to set the non-SR watermarks to 8. + */ +void intel_update_watermarks(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_wm) + dev_priv->display.update_wm(dev); +} + +void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, + uint32_t sprite_width, int pixel_size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.update_sprite_wm) + dev_priv->display.update_sprite_wm(dev, pipe, sprite_width, + pixel_size); +} + -- cgit v0.10.2 From f6750b3cc6e9284f373a2fd155ec0bba38d02ad0 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 18 Apr 2012 11:51:14 -0300 Subject: drm/i915: fix line breaks in intel_pm The previous patch had way too long lines, this fixes them to fit into a reasonable screen space. Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index b208165..c5bc4c4 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -28,11 +28,15 @@ #include "i915_drv.h" #include "intel_drv.h" -/* FBC, or Frame Buffer Compression, is a technique employed to compress the framebuffer contents in-memory, aiming at reducing the required bandwidth during in-memory transfers and, therefore, reduce the power packet. +/* FBC, or Frame Buffer Compression, is a technique employed to compress the + * framebuffer contents in-memory, aiming at reducing the required bandwidth + * during in-memory transfers and, therefore, reduce the power packet. * - * The benefits of FBC are mostly visible with solid backgrounds and variation-less patterns. + * The benefits of FBC are mostly visible with solid backgrounds and + * variation-less patterns. * - * FBC-related functionality can be enabled by the means of the i915.i915_enable_fbc parameter + * FBC-related functionality can be enabled by the means of the + * i915.i915_enable_fbc parameter */ void i8xx_disable_fbc(struct drm_device *dev) -- cgit v0.10.2 From 2b4e57bd7a6a855dd1229f8cfbbdebfbc3f933be Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 18 Apr 2012 15:29:23 -0300 Subject: drm/i915: move drps, rps and rc6-related functions to intel_pm This moves DRPS, RPS and RC6-related functionality into intel_pm module. It also removes the linux/cpufreq.h include from intel_display, as its only user was the GPU turbo-related functionality in Gen6+ code path. v2: rebase on top of latest drm-intel-next-queued adding the bits that shifted around since the last patch. Acked-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 03c015c..d3982e9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -25,7 +25,6 @@ */ #include -#include #include #include #include @@ -6352,177 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fb_output_poll_changed, }; -static struct drm_i915_gem_object * -intel_alloc_context_page(struct drm_device *dev) -{ - struct drm_i915_gem_object *ctx; - int ret; - - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - - ctx = i915_gem_alloc_object(dev, 4096); - if (!ctx) { - DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); - return NULL; - } - - ret = i915_gem_object_pin(ctx, 4096, true); - if (ret) { - DRM_ERROR("failed to pin power context: %d\n", ret); - goto err_unref; - } - - ret = i915_gem_object_set_to_gtt_domain(ctx, 1); - if (ret) { - DRM_ERROR("failed to set-domain on power context: %d\n", ret); - goto err_unpin; - } - - return ctx; - -err_unpin: - i915_gem_object_unpin(ctx); -err_unref: - drm_gem_object_unreference(&ctx->base); - mutex_unlock(&dev->struct_mutex); - return NULL; -} - -bool ironlake_set_drps(struct drm_device *dev, u8 val) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u16 rgvswctl; - - rgvswctl = I915_READ16(MEMSWCTL); - if (rgvswctl & MEMCTL_CMD_STS) { - DRM_DEBUG("gpu busy, RCS change rejected\n"); - return false; /* still busy with another command */ - } - - rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | - (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; - I915_WRITE16(MEMSWCTL, rgvswctl); - POSTING_READ16(MEMSWCTL); - - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE16(MEMSWCTL, rgvswctl); - - return true; -} - -void ironlake_enable_drps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 rgvmodectl = I915_READ(MEMMODECTL); - u8 fmax, fmin, fstart, vstart; - - /* Enable temp reporting */ - I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); - I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); - - /* 100ms RC evaluation intervals */ - I915_WRITE(RCUPEI, 100000); - I915_WRITE(RCDNEI, 100000); - - /* Set max/min thresholds to 90ms and 80ms respectively */ - I915_WRITE(RCBMAXAVG, 90000); - I915_WRITE(RCBMINAVG, 80000); - - I915_WRITE(MEMIHYST, 1); - - /* Set up min, max, and cur for interrupt handling */ - fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT; - fmin = (rgvmodectl & MEMMODE_FMIN_MASK); - fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> - MEMMODE_FSTART_SHIFT; - - vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> - PXVFREQ_PX_SHIFT; - - dev_priv->fmax = fmax; /* IPS callback will increase this */ - dev_priv->fstart = fstart; - - dev_priv->max_delay = fstart; - dev_priv->min_delay = fmin; - dev_priv->cur_delay = fstart; - - DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", - fmax, fmin, fstart); - - I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); - - /* - * Interrupts will be enabled in ironlake_irq_postinstall - */ - - I915_WRITE(VIDSTART, vstart); - POSTING_READ(VIDSTART); - - rgvmodectl |= MEMMODE_SWMODE_EN; - I915_WRITE(MEMMODECTL, rgvmodectl); - - if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) - DRM_ERROR("stuck trying to change perf mode\n"); - msleep(1); - - ironlake_set_drps(dev, fstart); - - dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + - I915_READ(0x112e0); - dev_priv->last_time1 = jiffies_to_msecs(jiffies); - dev_priv->last_count2 = I915_READ(0x112f4); - getrawmonotonic(&dev_priv->last_time2); -} - -void ironlake_disable_drps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u16 rgvswctl = I915_READ16(MEMSWCTL); - - /* Ack interrupts, disable EFC interrupt */ - I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); - I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG); - I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT); - I915_WRITE(DEIIR, DE_PCU_EVENT); - I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); - - /* Go back to the starting frequency */ - ironlake_set_drps(dev, dev_priv->fstart); - msleep(1); - rgvswctl |= MEMCTL_CMD_STS; - I915_WRITE(MEMSWCTL, rgvswctl); - msleep(1); - -} - -void gen6_set_rps(struct drm_device *dev, u8 val) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 swreq; - - swreq = (val & 0x3ff) << 25; - I915_WRITE(GEN6_RPNSWREQ, swreq); -} - -void gen6_disable_rps(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(GEN6_RPNSWREQ, 1 << 31); - I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); - I915_WRITE(GEN6_PMIER, 0); - /* Complete PM interrupt masking here doesn't race with the rps work - * item again unmasking PM interrupts because that is using a different - * register (PMIMR) to mask PM interrupts. The only risk is in leaving - * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ - - spin_lock_irq(&dev_priv->rps_lock); - dev_priv->pm_iir = 0; - spin_unlock_irq(&dev_priv->rps_lock); - - I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); -} - static unsigned long intel_pxfreq(u32 vidfreq) { unsigned long freq; @@ -6609,232 +6437,6 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -int intel_enable_rc6(const struct drm_device *dev) -{ - /* - * Respect the kernel parameter if it is set - */ - if (i915_enable_rc6 >= 0) - return i915_enable_rc6; - - /* - * Disable RC6 on Ironlake - */ - if (INTEL_INFO(dev)->gen == 5) - return 0; - - /* Sorry Haswell, no RC6 for you for now. */ - if (IS_HASWELL(dev)) - return 0; - - /* - * Disable rc6 on Sandybridge - */ - if (INTEL_INFO(dev)->gen == 6) { - DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n"); - return INTEL_RC6_ENABLE; - } - DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n"); - return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); -} - -void gen6_enable_rps(struct drm_i915_private *dev_priv) -{ - u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); - u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - u32 pcu_mbox, rc6_mask = 0; - u32 gtfifodbg; - int cur_freq, min_freq, max_freq; - int rc6_mode; - int i; - - /* Here begins a magic sequence of register writes to enable - * auto-downclocking. - * - * Perhaps there might be some value in exposing these to - * userspace... - */ - I915_WRITE(GEN6_RC_STATE, 0); - mutex_lock(&dev_priv->dev->struct_mutex); - - /* Clear the DBG now so we don't confuse earlier errors */ - if ((gtfifodbg = I915_READ(GTFIFODBG))) { - DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg); - I915_WRITE(GTFIFODBG, gtfifodbg); - } - - gen6_gt_force_wake_get(dev_priv); - - /* disable the counters and set deterministic thresholds */ - I915_WRITE(GEN6_RC_CONTROL, 0); - - I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); - I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); - I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30); - I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); - I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); - - for (i = 0; i < I915_NUM_RINGS; i++) - I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10); - - I915_WRITE(GEN6_RC_SLEEP, 0); - I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); - I915_WRITE(GEN6_RC6_THRESHOLD, 50000); - I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); - I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ - - rc6_mode = intel_enable_rc6(dev_priv->dev); - if (rc6_mode & INTEL_RC6_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6_ENABLE; - - if (rc6_mode & INTEL_RC6p_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE; - - if (rc6_mode & INTEL_RC6pp_ENABLE) - rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE; - - DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", - (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off", - (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off", - (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off"); - - I915_WRITE(GEN6_RC_CONTROL, - rc6_mask | - GEN6_RC_CTL_EI_MODE(1) | - GEN6_RC_CTL_HW_ENABLE); - - I915_WRITE(GEN6_RPNSWREQ, - GEN6_FREQUENCY(10) | - GEN6_OFFSET(0) | - GEN6_AGGRESSIVE_TURBO); - I915_WRITE(GEN6_RC_VIDEO_FREQ, - GEN6_FREQUENCY(12)); - - I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - 18 << 24 | - 6 << 16); - I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); - I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); - I915_WRITE(GEN6_RP_UP_EI, 100000); - I915_WRITE(GEN6_RP_DOWN_EI, 5000000); - I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); - I915_WRITE(GEN6_RP_CONTROL, - GEN6_RP_MEDIA_TURBO | - GEN6_RP_MEDIA_HW_MODE | - GEN6_RP_MEDIA_IS_GFX | - GEN6_RP_ENABLE | - GEN6_RP_UP_BUSY_AVG | - GEN6_RP_DOWN_IDLE_CONT); - - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - - I915_WRITE(GEN6_PCODE_DATA, 0); - I915_WRITE(GEN6_PCODE_MAILBOX, - GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - - min_freq = (rp_state_cap & 0xff0000) >> 16; - max_freq = rp_state_cap & 0xff; - cur_freq = (gt_perf_status & 0xff00) >> 8; - - /* Check for overclock support */ - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); - pcu_mbox = I915_READ(GEN6_PCODE_DATA); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, - 500)) - DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); - if (pcu_mbox & (1<<31)) { /* OC supported */ - max_freq = pcu_mbox & 0xff; - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); - } - - /* In units of 100MHz */ - dev_priv->max_delay = max_freq; - dev_priv->min_delay = min_freq; - dev_priv->cur_delay = cur_freq; - - /* requires MSI enabled */ - I915_WRITE(GEN6_PMIER, - GEN6_PM_MBOX_EVENT | - GEN6_PM_THERMAL_EVENT | - GEN6_PM_RP_DOWN_TIMEOUT | - GEN6_PM_RP_UP_THRESHOLD | - GEN6_PM_RP_DOWN_THRESHOLD | - GEN6_PM_RP_UP_EI_EXPIRED | - GEN6_PM_RP_DOWN_EI_EXPIRED); - spin_lock_irq(&dev_priv->rps_lock); - WARN_ON(dev_priv->pm_iir != 0); - I915_WRITE(GEN6_PMIMR, 0); - spin_unlock_irq(&dev_priv->rps_lock); - /* enable all PM interrupts */ - I915_WRITE(GEN6_PMINTRMSK, 0); - - gen6_gt_force_wake_put(dev_priv); - mutex_unlock(&dev_priv->dev->struct_mutex); -} - -void gen6_update_ring_freq(struct drm_i915_private *dev_priv) -{ - int min_freq = 15; - int gpu_freq, ia_freq, max_ia_freq; - int scaling_factor = 180; - - max_ia_freq = cpufreq_quick_get_max(0); - /* - * Default to measured freq if none found, PCU will ensure we don't go - * over - */ - if (!max_ia_freq) - max_ia_freq = tsc_khz; - - /* Convert from kHz to MHz */ - max_ia_freq /= 1000; - - mutex_lock(&dev_priv->dev->struct_mutex); - - /* - * For each potential GPU frequency, load a ring frequency we'd like - * to use for memory access. We do this by specifying the IA frequency - * the PCU should use as a reference to determine the ring frequency. - */ - for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay; - gpu_freq--) { - int diff = dev_priv->max_delay - gpu_freq; - - /* - * For GPU frequencies less than 750MHz, just use the lowest - * ring freq. - */ - if (gpu_freq < min_freq) - ia_freq = 800; - else - ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); - ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); - - I915_WRITE(GEN6_PCODE_DATA, - (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) | - gpu_freq); - I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | - GEN6_PCODE_WRITE_MIN_FREQ_TABLE); - if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & - GEN6_PCODE_READY) == 0, 10)) { - DRM_ERROR("pcode write of freq table timed out\n"); - continue; - } - } - - mutex_unlock(&dev_priv->dev->struct_mutex); -} - static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -7178,121 +6780,6 @@ static void cpt_init_clock_gating(struct drm_device *dev) I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); } -static void ironlake_teardown_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->renderctx) { - i915_gem_object_unpin(dev_priv->renderctx); - drm_gem_object_unreference(&dev_priv->renderctx->base); - dev_priv->renderctx = NULL; - } - - if (dev_priv->pwrctx) { - i915_gem_object_unpin(dev_priv->pwrctx); - drm_gem_object_unreference(&dev_priv->pwrctx->base); - dev_priv->pwrctx = NULL; - } -} - -static void ironlake_disable_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (I915_READ(PWRCTXA)) { - /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); - wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), - 50); - - I915_WRITE(PWRCTXA, 0); - POSTING_READ(PWRCTXA); - - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - POSTING_READ(RSTDBYCTL); - } - - ironlake_teardown_rc6(dev); -} - -static int ironlake_setup_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->renderctx == NULL) - dev_priv->renderctx = intel_alloc_context_page(dev); - if (!dev_priv->renderctx) - return -ENOMEM; - - if (dev_priv->pwrctx == NULL) - dev_priv->pwrctx = intel_alloc_context_page(dev); - if (!dev_priv->pwrctx) { - ironlake_teardown_rc6(dev); - return -ENOMEM; - } - - return 0; -} - -void ironlake_enable_rc6(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - - /* rc6 disabled by default due to repeated reports of hanging during - * boot and resume. - */ - if (!intel_enable_rc6(dev)) - return; - - mutex_lock(&dev->struct_mutex); - ret = ironlake_setup_rc6(dev); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return; - } - - /* - * GPU can automatically power down the render unit if given a page - * to save state. - */ - ret = BEGIN_LP_RING(6); - if (ret) { - ironlake_teardown_rc6(dev); - mutex_unlock(&dev->struct_mutex); - return; - } - - OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); - OUT_RING(MI_SET_CONTEXT); - OUT_RING(dev_priv->renderctx->gtt_offset | - MI_MM_SPACE_GTT | - MI_SAVE_EXT_STATE_EN | - MI_RESTORE_EXT_STATE_EN | - MI_RESTORE_INHIBIT); - OUT_RING(MI_SUSPEND_FLUSH); - OUT_RING(MI_NOOP); - OUT_RING(MI_FLUSH); - ADVANCE_LP_RING(); - - /* - * Wait for the command parser to advance past MI_SET_CONTEXT. The HW - * does an implicit flush, combined with MI_FLUSH above, it should be - * safe to assume that renderctx is valid - */ - ret = intel_wait_ring_idle(LP_RING(dev_priv)); - if (ret) { - DRM_ERROR("failed to enable ironlake power power savings\n"); - ironlake_teardown_rc6(dev); - mutex_unlock(&dev->struct_mutex); - return; - } - - I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); - I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); - mutex_unlock(&dev->struct_mutex); -} - void intel_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f1e27ce..c87f29a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -396,6 +396,7 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, u16 *blue, int regno); extern void intel_enable_clock_gating(struct drm_device *dev); +extern void ironlake_disable_rc6(struct drm_device *dev); extern void ironlake_enable_drps(struct drm_device *dev); extern void ironlake_disable_drps(struct drm_device *dev); extern void gen6_enable_rps(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index c5bc4c4..2f45de3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -25,6 +25,7 @@ * */ +#include #include "i915_drv.h" #include "intel_drv.h" @@ -1979,3 +1980,515 @@ void intel_update_sprite_watermarks(struct drm_device *dev, int pipe, pixel_size); } +static struct drm_i915_gem_object * +intel_alloc_context_page(struct drm_device *dev) +{ + struct drm_i915_gem_object *ctx; + int ret; + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + ctx = i915_gem_alloc_object(dev, 4096); + if (!ctx) { + DRM_DEBUG("failed to alloc power context, RC6 disabled\n"); + return NULL; + } + + ret = i915_gem_object_pin(ctx, 4096, true); + if (ret) { + DRM_ERROR("failed to pin power context: %d\n", ret); + goto err_unref; + } + + ret = i915_gem_object_set_to_gtt_domain(ctx, 1); + if (ret) { + DRM_ERROR("failed to set-domain on power context: %d\n", ret); + goto err_unpin; + } + + return ctx; + +err_unpin: + i915_gem_object_unpin(ctx); +err_unref: + drm_gem_object_unreference(&ctx->base); + mutex_unlock(&dev->struct_mutex); + return NULL; +} + +bool ironlake_set_drps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl; + + rgvswctl = I915_READ16(MEMSWCTL); + if (rgvswctl & MEMCTL_CMD_STS) { + DRM_DEBUG("gpu busy, RCS change rejected\n"); + return false; /* still busy with another command */ + } + + rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) | + (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM; + I915_WRITE16(MEMSWCTL, rgvswctl); + POSTING_READ16(MEMSWCTL); + + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE16(MEMSWCTL, rgvswctl); + + return true; +} + +void ironlake_enable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 rgvmodectl = I915_READ(MEMMODECTL); + u8 fmax, fmin, fstart, vstart; + + /* Enable temp reporting */ + I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN); + I915_WRITE16(TSC1, I915_READ(TSC1) | TSE); + + /* 100ms RC evaluation intervals */ + I915_WRITE(RCUPEI, 100000); + I915_WRITE(RCDNEI, 100000); + + /* Set max/min thresholds to 90ms and 80ms respectively */ + I915_WRITE(RCBMAXAVG, 90000); + I915_WRITE(RCBMINAVG, 80000); + + I915_WRITE(MEMIHYST, 1); + + /* Set up min, max, and cur for interrupt handling */ + fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT; + fmin = (rgvmodectl & MEMMODE_FMIN_MASK); + fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >> + MEMMODE_FSTART_SHIFT; + + vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + + dev_priv->fmax = fmax; /* IPS callback will increase this */ + dev_priv->fstart = fstart; + + dev_priv->max_delay = fstart; + dev_priv->min_delay = fmin; + dev_priv->cur_delay = fstart; + + DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", + fmax, fmin, fstart); + + I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN); + + /* + * Interrupts will be enabled in ironlake_irq_postinstall + */ + + I915_WRITE(VIDSTART, vstart); + POSTING_READ(VIDSTART); + + rgvmodectl |= MEMMODE_SWMODE_EN; + I915_WRITE(MEMMODECTL, rgvmodectl); + + if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) + DRM_ERROR("stuck trying to change perf mode\n"); + msleep(1); + + ironlake_set_drps(dev, fstart); + + dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) + + I915_READ(0x112e0); + dev_priv->last_time1 = jiffies_to_msecs(jiffies); + dev_priv->last_count2 = I915_READ(0x112f4); + getrawmonotonic(&dev_priv->last_time2); +} + +void ironlake_disable_drps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u16 rgvswctl = I915_READ16(MEMSWCTL); + + /* Ack interrupts, disable EFC interrupt */ + I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN); + I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG); + I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT); + I915_WRITE(DEIIR, DE_PCU_EVENT); + I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT); + + /* Go back to the starting frequency */ + ironlake_set_drps(dev, dev_priv->fstart); + msleep(1); + rgvswctl |= MEMCTL_CMD_STS; + I915_WRITE(MEMSWCTL, rgvswctl); + msleep(1); + +} + +void gen6_set_rps(struct drm_device *dev, u8 val) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 swreq; + + swreq = (val & 0x3ff) << 25; + I915_WRITE(GEN6_RPNSWREQ, swreq); +} + +void gen6_disable_rps(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(GEN6_RPNSWREQ, 1 << 31); + I915_WRITE(GEN6_PMINTRMSK, 0xffffffff); + I915_WRITE(GEN6_PMIER, 0); + /* Complete PM interrupt masking here doesn't race with the rps work + * item again unmasking PM interrupts because that is using a different + * register (PMIMR) to mask PM interrupts. The only risk is in leaving + * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */ + + spin_lock_irq(&dev_priv->rps_lock); + dev_priv->pm_iir = 0; + spin_unlock_irq(&dev_priv->rps_lock); + + I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR)); +} + +int intel_enable_rc6(const struct drm_device *dev) +{ + /* + * Respect the kernel parameter if it is set + */ + if (i915_enable_rc6 >= 0) + return i915_enable_rc6; + + /* + * Disable RC6 on Ironlake + */ + if (INTEL_INFO(dev)->gen == 5) + return 0; + + /* Sorry Haswell, no RC6 for you for now. */ + if (IS_HASWELL(dev)) + return 0; + + /* + * Disable rc6 on Sandybridge + */ + if (INTEL_INFO(dev)->gen == 6) { + DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n"); + return INTEL_RC6_ENABLE; + } + DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n"); + return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); +} + +void gen6_enable_rps(struct drm_i915_private *dev_priv) +{ + u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + u32 pcu_mbox, rc6_mask = 0; + u32 gtfifodbg; + int cur_freq, min_freq, max_freq; + int rc6_mode; + int i; + + /* Here begins a magic sequence of register writes to enable + * auto-downclocking. + * + * Perhaps there might be some value in exposing these to + * userspace... + */ + I915_WRITE(GEN6_RC_STATE, 0); + mutex_lock(&dev_priv->dev->struct_mutex); + + /* Clear the DBG now so we don't confuse earlier errors */ + if ((gtfifodbg = I915_READ(GTFIFODBG))) { + DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg); + I915_WRITE(GTFIFODBG, gtfifodbg); + } + + gen6_gt_force_wake_get(dev_priv); + + /* disable the counters and set deterministic thresholds */ + I915_WRITE(GEN6_RC_CONTROL, 0); + + I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16); + I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); + I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30); + I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000); + I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25); + + for (i = 0; i < I915_NUM_RINGS; i++) + I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10); + + I915_WRITE(GEN6_RC_SLEEP, 0); + I915_WRITE(GEN6_RC1e_THRESHOLD, 1000); + I915_WRITE(GEN6_RC6_THRESHOLD, 50000); + I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); + I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ + + rc6_mode = intel_enable_rc6(dev_priv->dev); + if (rc6_mode & INTEL_RC6_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6_ENABLE; + + if (rc6_mode & INTEL_RC6p_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE; + + if (rc6_mode & INTEL_RC6pp_ENABLE) + rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE; + + DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n", + (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off", + (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off"); + + I915_WRITE(GEN6_RC_CONTROL, + rc6_mask | + GEN6_RC_CTL_EI_MODE(1) | + GEN6_RC_CTL_HW_ENABLE); + + I915_WRITE(GEN6_RPNSWREQ, + GEN6_FREQUENCY(10) | + GEN6_OFFSET(0) | + GEN6_AGGRESSIVE_TURBO); + I915_WRITE(GEN6_RC_VIDEO_FREQ, + GEN6_FREQUENCY(12)); + + I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000); + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, + 18 << 24 | + 6 << 16); + I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000); + I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000); + I915_WRITE(GEN6_RP_UP_EI, 100000); + I915_WRITE(GEN6_RP_DOWN_EI, 5000000); + I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10); + I915_WRITE(GEN6_RP_CONTROL, + GEN6_RP_MEDIA_TURBO | + GEN6_RP_MEDIA_HW_MODE | + GEN6_RP_MEDIA_IS_GFX | + GEN6_RP_ENABLE | + GEN6_RP_UP_BUSY_AVG | + GEN6_RP_DOWN_IDLE_CONT); + + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + + I915_WRITE(GEN6_PCODE_DATA, 0); + I915_WRITE(GEN6_PCODE_MAILBOX, + GEN6_PCODE_READY | + GEN6_PCODE_WRITE_MIN_FREQ_TABLE); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + + min_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = rp_state_cap & 0xff; + cur_freq = (gt_perf_status & 0xff00) >> 8; + + /* Check for overclock support */ + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to become idle\n"); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS); + pcu_mbox = I915_READ(GEN6_PCODE_DATA); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0, + 500)) + DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); + if (pcu_mbox & (1<<31)) { /* OC supported */ + max_freq = pcu_mbox & 0xff; + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); + } + + /* In units of 100MHz */ + dev_priv->max_delay = max_freq; + dev_priv->min_delay = min_freq; + dev_priv->cur_delay = cur_freq; + + /* requires MSI enabled */ + I915_WRITE(GEN6_PMIER, + GEN6_PM_MBOX_EVENT | + GEN6_PM_THERMAL_EVENT | + GEN6_PM_RP_DOWN_TIMEOUT | + GEN6_PM_RP_UP_THRESHOLD | + GEN6_PM_RP_DOWN_THRESHOLD | + GEN6_PM_RP_UP_EI_EXPIRED | + GEN6_PM_RP_DOWN_EI_EXPIRED); + spin_lock_irq(&dev_priv->rps_lock); + WARN_ON(dev_priv->pm_iir != 0); + I915_WRITE(GEN6_PMIMR, 0); + spin_unlock_irq(&dev_priv->rps_lock); + /* enable all PM interrupts */ + I915_WRITE(GEN6_PMINTRMSK, 0); + + gen6_gt_force_wake_put(dev_priv); + mutex_unlock(&dev_priv->dev->struct_mutex); +} + +void gen6_update_ring_freq(struct drm_i915_private *dev_priv) +{ + int min_freq = 15; + int gpu_freq, ia_freq, max_ia_freq; + int scaling_factor = 180; + + max_ia_freq = cpufreq_quick_get_max(0); + /* + * Default to measured freq if none found, PCU will ensure we don't go + * over + */ + if (!max_ia_freq) + max_ia_freq = tsc_khz; + + /* Convert from kHz to MHz */ + max_ia_freq /= 1000; + + mutex_lock(&dev_priv->dev->struct_mutex); + + /* + * For each potential GPU frequency, load a ring frequency we'd like + * to use for memory access. We do this by specifying the IA frequency + * the PCU should use as a reference to determine the ring frequency. + */ + for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay; + gpu_freq--) { + int diff = dev_priv->max_delay - gpu_freq; + + /* + * For GPU frequencies less than 750MHz, just use the lowest + * ring freq. + */ + if (gpu_freq < min_freq) + ia_freq = 800; + else + ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); + ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); + + I915_WRITE(GEN6_PCODE_DATA, + (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) | + gpu_freq); + I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY | + GEN6_PCODE_WRITE_MIN_FREQ_TABLE); + if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & + GEN6_PCODE_READY) == 0, 10)) { + DRM_ERROR("pcode write of freq table timed out\n"); + continue; + } + } + + mutex_unlock(&dev_priv->dev->struct_mutex); +} + +static void ironlake_teardown_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->renderctx) { + i915_gem_object_unpin(dev_priv->renderctx); + drm_gem_object_unreference(&dev_priv->renderctx->base); + dev_priv->renderctx = NULL; + } + + if (dev_priv->pwrctx) { + i915_gem_object_unpin(dev_priv->pwrctx); + drm_gem_object_unreference(&dev_priv->pwrctx->base); + dev_priv->pwrctx = NULL; + } +} + +void ironlake_disable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_READ(PWRCTXA)) { + /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */ + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT); + wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON), + 50); + + I915_WRITE(PWRCTXA, 0); + POSTING_READ(PWRCTXA); + + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + POSTING_READ(RSTDBYCTL); + } + + ironlake_teardown_rc6(dev); +} + +static int ironlake_setup_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->renderctx == NULL) + dev_priv->renderctx = intel_alloc_context_page(dev); + if (!dev_priv->renderctx) + return -ENOMEM; + + if (dev_priv->pwrctx == NULL) + dev_priv->pwrctx = intel_alloc_context_page(dev); + if (!dev_priv->pwrctx) { + ironlake_teardown_rc6(dev); + return -ENOMEM; + } + + return 0; +} + +void ironlake_enable_rc6(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + /* rc6 disabled by default due to repeated reports of hanging during + * boot and resume. + */ + if (!intel_enable_rc6(dev)) + return; + + mutex_lock(&dev->struct_mutex); + ret = ironlake_setup_rc6(dev); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return; + } + + /* + * GPU can automatically power down the render unit if given a page + * to save state. + */ + ret = BEGIN_LP_RING(6); + if (ret) { + ironlake_teardown_rc6(dev); + mutex_unlock(&dev->struct_mutex); + return; + } + + OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN); + OUT_RING(MI_SET_CONTEXT); + OUT_RING(dev_priv->renderctx->gtt_offset | + MI_MM_SPACE_GTT | + MI_SAVE_EXT_STATE_EN | + MI_RESTORE_EXT_STATE_EN | + MI_RESTORE_INHIBIT); + OUT_RING(MI_SUSPEND_FLUSH); + OUT_RING(MI_NOOP); + OUT_RING(MI_FLUSH); + ADVANCE_LP_RING(); + + /* + * Wait for the command parser to advance past MI_SET_CONTEXT. The HW + * does an implicit flush, combined with MI_FLUSH above, it should be + * safe to assume that renderctx is valid + */ + ret = intel_wait_ring_idle(LP_RING(dev_priv)); + if (ret) { + DRM_ERROR("failed to enable ironlake power power savings\n"); + ironlake_teardown_rc6(dev); + mutex_unlock(&dev->struct_mutex); + return; + } + + I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN); + I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT); + mutex_unlock(&dev->struct_mutex); +} + -- cgit v0.10.2 From dde18883def89af28bd0c01aff3c7962b82dda18 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 18 Apr 2012 15:29:24 -0300 Subject: drm/i915: move emon functionality into intel_pm module This moves the Ironlake energy monitoring functionality into intel_pm module. Acked-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d3982e9..4fb1982 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6351,92 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fb_output_poll_changed, }; -static unsigned long intel_pxfreq(u32 vidfreq) -{ - unsigned long freq; - int div = (vidfreq & 0x3f0000) >> 16; - int post = (vidfreq & 0x3000) >> 12; - int pre = (vidfreq & 0x7); - - if (!pre) - return 0; - - freq = ((div * 133333) / ((1<dev_private; - u32 lcfuse; - u8 pxw[16]; - int i; - - /* Disable to program */ - I915_WRITE(ECR, 0); - POSTING_READ(ECR); - - /* Program energy weights for various events */ - I915_WRITE(SDEW, 0x15040d00); - I915_WRITE(CSIEW0, 0x007f0000); - I915_WRITE(CSIEW1, 0x1e220004); - I915_WRITE(CSIEW2, 0x04000004); - - for (i = 0; i < 5; i++) - I915_WRITE(PEW + (i * 4), 0); - for (i = 0; i < 3; i++) - I915_WRITE(DEW + (i * 4), 0); - - /* Program P-state weights to account for frequency power adjustment */ - for (i = 0; i < 16; i++) { - u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); - unsigned long freq = intel_pxfreq(pxvidfreq); - unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> - PXVFREQ_PX_SHIFT; - unsigned long val; - - val = vid * vid; - val *= (freq / 1000); - val *= 255; - val /= (127*127*900); - if (val > 0xff) - DRM_ERROR("bad pxval: %ld\n", val); - pxw[i] = val; - } - /* Render standby states get 0 weight */ - pxw[14] = 0; - pxw[15] = 0; - - for (i = 0; i < 4; i++) { - u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | - (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); - I915_WRITE(PXW + (i * 4), val); - } - - /* Adjust magic regs to magic values (more experimental results) */ - I915_WRITE(OGW0, 0); - I915_WRITE(OGW1, 0); - I915_WRITE(EG0, 0x00007f00); - I915_WRITE(EG1, 0x0000000e); - I915_WRITE(EG2, 0x000e0000); - I915_WRITE(EG3, 0x68000300); - I915_WRITE(EG4, 0x42000000); - I915_WRITE(EG5, 0x00140031); - I915_WRITE(EG6, 0); - I915_WRITE(EG7, 0); - - for (i = 0; i < 8; i++) - I915_WRITE(PXWL + (i * 4), 0); - - /* Enable PMON + select events */ - I915_WRITE(ECR, 0x80000019); - - lcfuse = I915_READ(LCFUSE02); - - dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); -} - static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 2f45de3..832130e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2492,3 +2492,89 @@ void ironlake_enable_rc6(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } +static unsigned long intel_pxfreq(u32 vidfreq) +{ + unsigned long freq; + int div = (vidfreq & 0x3f0000) >> 16; + int post = (vidfreq & 0x3000) >> 12; + int pre = (vidfreq & 0x7); + + if (!pre) + return 0; + + freq = ((div * 133333) / ((1<dev_private; + u32 lcfuse; + u8 pxw[16]; + int i; + + /* Disable to program */ + I915_WRITE(ECR, 0); + POSTING_READ(ECR); + + /* Program energy weights for various events */ + I915_WRITE(SDEW, 0x15040d00); + I915_WRITE(CSIEW0, 0x007f0000); + I915_WRITE(CSIEW1, 0x1e220004); + I915_WRITE(CSIEW2, 0x04000004); + + for (i = 0; i < 5; i++) + I915_WRITE(PEW + (i * 4), 0); + for (i = 0; i < 3; i++) + I915_WRITE(DEW + (i * 4), 0); + + /* Program P-state weights to account for frequency power adjustment */ + for (i = 0; i < 16; i++) { + u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4)); + unsigned long freq = intel_pxfreq(pxvidfreq); + unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >> + PXVFREQ_PX_SHIFT; + unsigned long val; + + val = vid * vid; + val *= (freq / 1000); + val *= 255; + val /= (127*127*900); + if (val > 0xff) + DRM_ERROR("bad pxval: %ld\n", val); + pxw[i] = val; + } + /* Render standby states get 0 weight */ + pxw[14] = 0; + pxw[15] = 0; + + for (i = 0; i < 4; i++) { + u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) | + (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]); + I915_WRITE(PXW + (i * 4), val); + } + + /* Adjust magic regs to magic values (more experimental results) */ + I915_WRITE(OGW0, 0); + I915_WRITE(OGW1, 0); + I915_WRITE(EG0, 0x00007f00); + I915_WRITE(EG1, 0x0000000e); + I915_WRITE(EG2, 0x000e0000); + I915_WRITE(EG3, 0x68000300); + I915_WRITE(EG4, 0x42000000); + I915_WRITE(EG5, 0x00140031); + I915_WRITE(EG6, 0); + I915_WRITE(EG7, 0); + + for (i = 0; i < 8; i++) + I915_WRITE(PXWL + (i * 4), 0); + + /* Enable PMON + select events */ + I915_WRITE(ECR, 0x80000019); + + lcfuse = I915_READ(LCFUSE02); + + dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); +} + -- cgit v0.10.2 From 6f1d69b04fcd7ba16791165e8287d95e88bef848 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 18 Apr 2012 15:29:25 -0300 Subject: drm/i915: move clock gating functionality into intel_pm module This moves the clock gating-related functions into intel_pm module. Also, please note that we do change the function type from static to non-static in this patch for the move, to prevent breaking bisecting with non-working intermediate commit. Those are returned back to static form in the following patch which setups a generic PM initialization function, which was split into a different one to simplify review. v2: rebase on top of latest drm-intel-next-queued to incorporate all the changes that went there meanwhile. Acked-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4fb1982..dec67aa 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1515,7 +1515,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, * Plane regs are double buffered, going from enabled->disabled needs a * trigger in order to latch. The display address reg provides this. */ -static void intel_flush_display_plane(struct drm_i915_private *dev_priv, +void intel_flush_display_plane(struct drm_i915_private *dev_priv, enum plane plane) { I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); @@ -6351,359 +6351,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fb_output_poll_changed, }; -static void ironlake_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - /* Required for FBC */ - dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | - DPFCRUNIT_CLOCK_GATE_DISABLE | - DPFDUNIT_CLOCK_GATE_DISABLE; - /* Required for CxSR */ - dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_3DCGDIS0, - MARIUNIT_CLOCK_GATE_DISABLE | - SVSMUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(PCH_3DCGDIS1, - VFMUNIT_CLOCK_GATE_DISABLE); - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - /* - * According to the spec the following bits should be set in - * order to enable memory self-refresh - * The bit 22/21 of 0x42004 - * The bit 5 of 0x42020 - * The bit 15 of 0x45000 - */ - I915_WRITE(ILK_DISPLAY_CHICKEN2, - (I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL)); - I915_WRITE(ILK_DSPCLK_GATE, - (I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE)); - I915_WRITE(DISP_ARB_CTL, - (I915_READ(DISP_ARB_CTL) | - DISP_FBC_WM_DIS)); - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* - * Based on the document from hardware guys the following bits - * should be set unconditionally in order to enable FBC. - * The bit 22 of 0x42000 - * The bit 22 of 0x42004 - * The bit 7,8,9 of 0x42020. - */ - if (IS_IRONLAKE_M(dev)) { - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPFC_DIS1 | - ILK_DPFC_DIS2 | - ILK_CLK_FBC); - } - - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); - I915_WRITE(_3D_CHICKEN2, - _3D_CHICKEN2_WM_READ_PIPELINED << 16 | - _3D_CHICKEN2_WM_READ_PIPELINED); -} - -static void gen6_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_ELPIN_409_SELECT); - - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* clear masked bit */ - I915_WRITE(CACHE_MODE_0, - CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT); - - I915_WRITE(GEN6_UCGCTL1, - I915_READ(GEN6_UCGCTL1) | - GEN6_BLBUNIT_CLOCK_GATE_DISABLE | - GEN6_CSUNIT_CLOCK_GATE_DISABLE); - - /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock - * gating disable must be set. Failure to set it results in - * flickering pixels due to Z write ordering failures after - * some amount of runtime in the Mesa "fire" demo, and Unigine - * Sanctuary and Tropics, and apparently anything else with - * alpha test or pixel discard. - * - * According to the spec, bit 11 (RCCUNIT) must also be set, - * but we didn't debug actual testcases to find it out. - */ - I915_WRITE(GEN6_UCGCTL2, - GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | - GEN6_RCCUNIT_CLOCK_GATE_DISABLE); - - /* Bspec says we need to always set all mask bits. */ - I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) | - _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL); - - /* - * According to the spec the following bits should be - * set in order to enable memory self-refresh and fbc: - * The bit21 and bit22 of 0x42000 - * The bit21 and bit22 of 0x42004 - * The bit5 and bit7 of 0x42020 - * The bit14 of 0x70180 - * The bit14 of 0x71180 - */ - I915_WRITE(ILK_DISPLAY_CHICKEN1, - I915_READ(ILK_DISPLAY_CHICKEN1) | - ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); - I915_WRITE(ILK_DISPLAY_CHICKEN2, - I915_READ(ILK_DISPLAY_CHICKEN2) | - ILK_DPARB_GATE | ILK_VSDPFD_FULL); - I915_WRITE(ILK_DSPCLK_GATE, - I915_READ(ILK_DSPCLK_GATE) | - ILK_DPARB_CLK_GATE | - ILK_DPFD_CLK_GATE); - - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } -} - -static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) -{ - uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); - - reg &= ~GEN7_FF_SCHED_MASK; - reg |= GEN7_FF_TS_SCHED_HW; - reg |= GEN7_FF_VS_SCHED_HW; - reg |= GEN7_FF_DS_SCHED_HW; - - I915_WRITE(GEN7_FF_THREAD_MODE, reg); -} - -static void ivybridge_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. - */ - I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - - I915_WRITE(IVB_CHICKEN3, - CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | - CHICKEN3_DGMG_DONE_FIX_DISABLE); - - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ - I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, - GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ - I915_WRITE(GEN7_L3CNTLREG1, - GEN7_WA_FOR_GEN7_L3_CONTROL); - I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, - GEN7_WA_L3_CHICKEN_MODE); - - /* This is required by WaCatErrorRejectionIssue */ - I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } - - gen7_setup_fixed_func_scheduler(dev_priv); -} - -static void valleyview_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; - - I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); - - I915_WRITE(WM3_LP_ILK, 0); - I915_WRITE(WM2_LP_ILK, 0); - I915_WRITE(WM1_LP_ILK, 0); - - /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. - * This implements the WaDisableRCZUnitClockGating workaround. - */ - I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); - - I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - - I915_WRITE(IVB_CHICKEN3, - CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | - CHICKEN3_DGMG_DONE_FIX_DISABLE); - - /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ - I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, - GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); - - /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ - I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); - I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); - - /* This is required by WaCatErrorRejectionIssue */ - I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, - I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | - GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); - - for_each_pipe(pipe) { - I915_WRITE(DSPCNTR(pipe), - I915_READ(DSPCNTR(pipe)) | - DISPPLANE_TRICKLE_FEED_DISABLE); - intel_flush_display_plane(dev_priv, pipe); - } - - I915_WRITE(CACHE_MODE_1, I915_READ(CACHE_MODE_1) | - (PIXEL_SUBSPAN_COLLECT_OPT_DISABLE << 16) | - PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); -} - -static void g4x_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t dspclk_gate; - - I915_WRITE(RENCLK_GATE_D1, 0); - I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | - GS_UNIT_CLOCK_GATE_DISABLE | - CL_UNIT_CLOCK_GATE_DISABLE); - I915_WRITE(RAMCLK_GATE_D, 0); - dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | - OVRUNIT_CLOCK_GATE_DISABLE | - OVCUNIT_CLOCK_GATE_DISABLE; - if (IS_GM45(dev)) - dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; - I915_WRITE(DSPCLK_GATE_D, dspclk_gate); -} - -static void crestline_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); - I915_WRITE(DSPCLK_GATE_D, 0); - I915_WRITE(RAMCLK_GATE_D, 0); - I915_WRITE16(DEUC, 0); -} - -static void broadwater_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | - I965_RCC_CLOCK_GATE_DISABLE | - I965_RCPB_CLOCK_GATE_DISABLE | - I965_ISC_CLOCK_GATE_DISABLE | - I965_FBC_CLOCK_GATE_DISABLE); - I915_WRITE(RENCLK_GATE_D2, 0); -} - -static void gen3_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dstate = I915_READ(D_STATE); - - dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | - DSTATE_DOT_CLOCK_GATING; - I915_WRITE(D_STATE, dstate); -} - -static void i85x_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); -} - -static void i830_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); -} - -static void ibx_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); -} - -static void cpt_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int pipe; - - /* - * On Ibex Peak and Cougar Point, we need to disable clock - * gating for the panel power sequencer or it will fail to - * start up when no ports are active. - */ - I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); - I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | - DPLS_EDP_PPS_FIX_DIS); - /* Without this, mode sets may fail silently on FDI */ - for_each_pipe(pipe) - I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); -} - -void intel_init_clock_gating(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - dev_priv->display.init_clock_gating(dev); - - if (dev_priv->display.init_pch_clock_gating) - dev_priv->display.init_pch_clock_gating(dev); -} - /* Set up chip specific display functions */ static void intel_init_display(struct drm_device *dev) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c87f29a..771075c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -339,6 +339,8 @@ extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config(struct intel_encoder *, int *, int *); extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder); extern int intel_plane_init(struct drm_device *dev, enum pipe pipe); +extern void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane); /* intel_panel.c */ extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, @@ -490,4 +492,18 @@ extern int i85x_get_fifo_size(struct drm_device *dev, int plane); extern int i845_get_fifo_size(struct drm_device *dev, int plane); extern int i830_get_fifo_size(struct drm_device *dev, int plane); +/* Clock gating */ +extern void ironlake_init_clock_gating(struct drm_device *dev); +extern void gen6_init_clock_gating(struct drm_device *dev); +extern void ivybridge_init_clock_gating(struct drm_device *dev); +extern void valleyview_init_clock_gating(struct drm_device *dev); +extern void g4x_init_clock_gating(struct drm_device *dev); +extern void crestline_init_clock_gating(struct drm_device *dev); +extern void broadwater_init_clock_gating(struct drm_device *dev); +extern void gen3_init_clock_gating(struct drm_device *dev); +extern void i85x_init_clock_gating(struct drm_device *dev); +extern void i830_init_clock_gating(struct drm_device *dev); +extern void ibx_init_clock_gating(struct drm_device *dev); +extern void cpt_init_clock_gating(struct drm_device *dev); + #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 832130e..4f35df2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2578,3 +2578,356 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } +void ironlake_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + /* Required for FBC */ + dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE | + DPFCRUNIT_CLOCK_GATE_DISABLE | + DPFDUNIT_CLOCK_GATE_DISABLE; + /* Required for CxSR */ + dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_3DCGDIS0, + MARIUNIT_CLOCK_GATE_DISABLE | + SVSMUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(PCH_3DCGDIS1, + VFMUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + /* + * According to the spec the following bits should be set in + * order to enable memory self-refresh + * The bit 22/21 of 0x42004 + * The bit 5 of 0x42020 + * The bit 15 of 0x45000 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN2, + (I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL)); + I915_WRITE(ILK_DSPCLK_GATE, + (I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE)); + I915_WRITE(DISP_ARB_CTL, + (I915_READ(DISP_ARB_CTL) | + DISP_FBC_WM_DIS)); + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* + * Based on the document from hardware guys the following bits + * should be set unconditionally in order to enable FBC. + * The bit 22 of 0x42000 + * The bit 22 of 0x42004 + * The bit 7,8,9 of 0x42020. + */ + if (IS_IRONLAKE_M(dev)) { + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPFC_DIS1 | + ILK_DPFC_DIS2 | + ILK_CLK_FBC); + } + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + I915_WRITE(_3D_CHICKEN2, + _3D_CHICKEN2_WM_READ_PIPELINED << 16 | + _3D_CHICKEN2_WM_READ_PIPELINED); +} + +void gen6_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_ELPIN_409_SELECT); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* clear masked bit */ + I915_WRITE(CACHE_MODE_0, + CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT); + + I915_WRITE(GEN6_UCGCTL1, + I915_READ(GEN6_UCGCTL1) | + GEN6_BLBUNIT_CLOCK_GATE_DISABLE | + GEN6_CSUNIT_CLOCK_GATE_DISABLE); + + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock + * gating disable must be set. Failure to set it results in + * flickering pixels due to Z write ordering failures after + * some amount of runtime in the Mesa "fire" demo, and Unigine + * Sanctuary and Tropics, and apparently anything else with + * alpha test or pixel discard. + * + * According to the spec, bit 11 (RCCUNIT) must also be set, + * but we didn't debug actual testcases to find it out. + */ + I915_WRITE(GEN6_UCGCTL2, + GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | + GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + + /* Bspec says we need to always set all mask bits. */ + I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) | + _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL); + + /* + * According to the spec the following bits should be + * set in order to enable memory self-refresh and fbc: + * The bit21 and bit22 of 0x42000 + * The bit21 and bit22 of 0x42004 + * The bit5 and bit7 of 0x42020 + * The bit14 of 0x70180 + * The bit14 of 0x71180 + */ + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE | ILK_VSDPFD_FULL); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPARB_CLK_GATE | + ILK_DPFD_CLK_GATE); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } +} + +static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) +{ + uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE); + + reg &= ~GEN7_FF_SCHED_MASK; + reg |= GEN7_FF_TS_SCHED_HW; + reg |= GEN7_FF_VS_SCHED_HW; + reg |= GEN7_FF_DS_SCHED_HW; + + I915_WRITE(GEN7_FF_THREAD_MODE, reg); +} + +void ivybridge_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. + * This implements the WaDisableRCZUnitClockGating workaround. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + + I915_WRITE(IVB_CHICKEN3, + CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | + CHICKEN3_DGMG_DONE_FIX_DISABLE); + + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, + GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); + + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + I915_WRITE(GEN7_L3CNTLREG1, + GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, + GEN7_WA_L3_CHICKEN_MODE); + + /* This is required by WaCatErrorRejectionIssue */ + I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | + GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + + gen7_setup_fixed_func_scheduler(dev_priv); +} + +void valleyview_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; + + I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate); + + I915_WRITE(WM3_LP_ILK, 0); + I915_WRITE(WM2_LP_ILK, 0); + I915_WRITE(WM1_LP_ILK, 0); + + /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. + * This implements the WaDisableRCZUnitClockGating workaround. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); + + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + + I915_WRITE(IVB_CHICKEN3, + CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE | + CHICKEN3_DGMG_DONE_FIX_DISABLE); + + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, + GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); + + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + + /* This is required by WaCatErrorRejectionIssue */ + I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | + GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + + for_each_pipe(pipe) { + I915_WRITE(DSPCNTR(pipe), + I915_READ(DSPCNTR(pipe)) | + DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } + + I915_WRITE(CACHE_MODE_1, I915_READ(CACHE_MODE_1) | + (PIXEL_SUBSPAN_COLLECT_OPT_DISABLE << 16) | + PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); +} + +void g4x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t dspclk_gate; + + I915_WRITE(RENCLK_GATE_D1, 0); + I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE | + GS_UNIT_CLOCK_GATE_DISABLE | + CL_UNIT_CLOCK_GATE_DISABLE); + I915_WRITE(RAMCLK_GATE_D, 0); + dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE | + OVRUNIT_CLOCK_GATE_DISABLE | + OVCUNIT_CLOCK_GATE_DISABLE; + if (IS_GM45(dev)) + dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, dspclk_gate); +} + +void crestline_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); + I915_WRITE(DSPCLK_GATE_D, 0); + I915_WRITE(RAMCLK_GATE_D, 0); + I915_WRITE16(DEUC, 0); +} + +void broadwater_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE | + I965_RCC_CLOCK_GATE_DISABLE | + I965_RCPB_CLOCK_GATE_DISABLE | + I965_ISC_CLOCK_GATE_DISABLE | + I965_FBC_CLOCK_GATE_DISABLE); + I915_WRITE(RENCLK_GATE_D2, 0); +} + +void gen3_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dstate = I915_READ(D_STATE); + + dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING | + DSTATE_DOT_CLOCK_GATING; + I915_WRITE(D_STATE, dstate); +} + +void i85x_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); +} + +void i830_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); +} + +void ibx_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); +} + +void cpt_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; + + /* + * On Ibex Peak and Cougar Point, we need to disable clock + * gating for the panel power sequencer or it will fail to + * start up when no ports are active. + */ + I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | + DPLS_EDP_PPS_FIX_DIS); + /* Without this, mode sets may fail silently on FDI */ + for_each_pipe(pipe) + I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); +} + +void intel_init_clock_gating(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->display.init_clock_gating(dev); + + if (dev_priv->display.init_pch_clock_gating) + dev_priv->display.init_pch_clock_gating(dev); +} + -- cgit v0.10.2 From 1fa611065080cf86d783a8e3acaa3de0f04eacd3 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 18 Apr 2012 15:29:26 -0300 Subject: drm/i915: add generic power management initialization This adds intel_pm routine for generic power-related infrastructure initialization. v2: now that all the platform-specific stuff is initialized in one place, we can also add back the static definitions to platform-specific functions which we abstract now. Acked-by: Jesse Barnes Acked-by: Ben Widawsky Signed-off-by: Eugeni Dodonov Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dec67aa..aa647c6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6367,23 +6367,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.update_plane = i9xx_update_plane; } - if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - dev_priv->display.enable_fbc = ironlake_enable_fbc; - dev_priv->display.disable_fbc = ironlake_disable_fbc; - } else if (IS_GM45(dev)) { - dev_priv->display.fbc_enabled = g4x_fbc_enabled; - dev_priv->display.enable_fbc = g4x_enable_fbc; - dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_CRESTLINE(dev)) { - dev_priv->display.fbc_enabled = i8xx_fbc_enabled; - dev_priv->display.enable_fbc = i8xx_enable_fbc; - dev_priv->display.disable_fbc = i8xx_disable_fbc; - } - /* 855GM needs testing */ - } - /* Returns the core display clock speed */ if (IS_VALLEYVIEW(dev)) dev_priv->display.get_display_clock_speed = @@ -6410,130 +6393,24 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; - /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { - dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; - dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; - - /* IVB configs may use multi-threaded forcewake */ - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { - u32 ecobus; - - /* A small trick here - if the bios hasn't configured MT forcewake, - * and if the device is in RC6, then force_wake_mt_get will not wake - * the device and the ECOBUS read will return zero. Which will be - * (correctly) interpreted by the test below as MT forcewake being - * disabled. - */ - mutex_lock(&dev->struct_mutex); - __gen6_gt_force_wake_mt_get(dev_priv); - ecobus = I915_READ_NOTRACE(ECOBUS); - __gen6_gt_force_wake_mt_put(dev_priv); - mutex_unlock(&dev->struct_mutex); - - if (ecobus & FORCEWAKE_MT_ENABLE) { - DRM_DEBUG_KMS("Using MT version of forcewake\n"); - dev_priv->display.force_wake_get = - __gen6_gt_force_wake_mt_get; - dev_priv->display.force_wake_put = - __gen6_gt_force_wake_mt_put; - } - } - - if (HAS_PCH_IBX(dev)) - dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; - else if (HAS_PCH_CPT(dev)) - dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; - if (IS_GEN5(dev)) { - if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) - dev_priv->display.update_wm = ironlake_update_wm; - else { - DRM_DEBUG_KMS("Failed to get proper latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } dev_priv->display.fdi_link_train = ironlake_fdi_link_train; - dev_priv->display.init_clock_gating = ironlake_init_clock_gating; dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_GEN6(dev)) { - if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } dev_priv->display.fdi_link_train = gen6_fdi_link_train; - dev_priv->display.init_clock_gating = gen6_init_clock_gating; dev_priv->display.write_eld = ironlake_write_eld; } else if (IS_IVYBRIDGE(dev)) { /* FIXME: detect B0+ stepping and use auto training */ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; - if (SNB_READ_WM0_LATENCY()) { - dev_priv->display.update_wm = sandybridge_update_wm; - dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; - } else { - DRM_DEBUG_KMS("Failed to read display plane latency. " - "Disable CxSR\n"); - dev_priv->display.update_wm = NULL; - } - dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; dev_priv->display.write_eld = ironlake_write_eld; } else dev_priv->display.update_wm = NULL; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; - dev_priv->display.init_clock_gating = - valleyview_init_clock_gating; dev_priv->display.force_wake_get = vlv_force_wake_get; dev_priv->display.force_wake_put = vlv_force_wake_put; - } else if (IS_PINEVIEW(dev)) { - if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), - dev_priv->is_ddr3, - dev_priv->fsb_freq, - dev_priv->mem_freq)) { - DRM_INFO("failed to find known CxSR latency " - "(found ddr%s fsb freq %d, mem freq %d), " - "disabling CxSR\n", - (dev_priv->is_ddr3 == 1) ? "3" : "2", - dev_priv->fsb_freq, dev_priv->mem_freq); - /* Disable CxSR and never update its watermark again */ - pineview_disable_cxsr(dev); - dev_priv->display.update_wm = NULL; - } else - dev_priv->display.update_wm = pineview_update_wm; - dev_priv->display.init_clock_gating = gen3_init_clock_gating; } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; - dev_priv->display.update_wm = g4x_update_wm; - dev_priv->display.init_clock_gating = g4x_init_clock_gating; - } else if (IS_GEN4(dev)) { - dev_priv->display.update_wm = i965_update_wm; - if (IS_CRESTLINE(dev)) - dev_priv->display.init_clock_gating = crestline_init_clock_gating; - else if (IS_BROADWATER(dev)) - dev_priv->display.init_clock_gating = broadwater_init_clock_gating; - } else if (IS_GEN3(dev)) { - dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i9xx_get_fifo_size; - dev_priv->display.init_clock_gating = gen3_init_clock_gating; - } else if (IS_I865G(dev)) { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - dev_priv->display.get_fifo_size = i830_get_fifo_size; - } else if (IS_I85X(dev)) { - dev_priv->display.update_wm = i9xx_update_wm; - dev_priv->display.get_fifo_size = i85x_get_fifo_size; - dev_priv->display.init_clock_gating = i85x_init_clock_gating; - } else { - dev_priv->display.update_wm = i830_update_wm; - dev_priv->display.init_clock_gating = i830_init_clock_gating; - if (IS_845G(dev)) - dev_priv->display.get_fifo_size = i845_get_fifo_size; - else - dev_priv->display.get_fifo_size = i830_get_fifo_size; } /* Default just returns -ENODEV to indicate unsupported */ @@ -6723,6 +6600,8 @@ void intel_modeset_init(struct drm_device *dev) intel_init_quirks(dev); + intel_init_pm(dev); + intel_init_display(dev); if (IS_GEN2(dev)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 771075c..c5bf8be 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -457,53 +457,10 @@ extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data, extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg); /* Power-related functions, located in intel_pm.c */ +extern void intel_init_pm(struct drm_device *dev); /* FBC */ -extern void i8xx_disable_fbc(struct drm_device *dev); -extern void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval); -extern bool i8xx_fbc_enabled(struct drm_device *dev); -extern void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval); -extern void g4x_disable_fbc(struct drm_device *dev); -extern bool g4x_fbc_enabled(struct drm_device *dev); -extern void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval); -extern void ironlake_disable_fbc(struct drm_device *dev); -extern bool ironlake_fbc_enabled(struct drm_device *dev); extern bool intel_fbc_enabled(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern void intel_update_fbc(struct drm_device *dev); -/* Watermarks */ -extern void pineview_update_wm(struct drm_device *dev); -extern void valleyview_update_wm(struct drm_device *dev); -extern void g4x_update_wm(struct drm_device *dev); -extern void i965_update_wm(struct drm_device *dev); -extern void i9xx_update_wm(struct drm_device *dev); -extern void i830_update_wm(struct drm_device *dev); -extern void ironlake_update_wm(struct drm_device *dev); -extern void sandybridge_update_wm(struct drm_device *dev); -extern void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, - uint32_t sprite_width, int pixel_size); -extern const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, - int is_ddr3, - int fsb, - int mem); -extern void pineview_disable_cxsr(struct drm_device *dev); -extern int i9xx_get_fifo_size(struct drm_device *dev, int plane); -extern int i85x_get_fifo_size(struct drm_device *dev, int plane); -extern int i845_get_fifo_size(struct drm_device *dev, int plane); -extern int i830_get_fifo_size(struct drm_device *dev, int plane); - -/* Clock gating */ -extern void ironlake_init_clock_gating(struct drm_device *dev); -extern void gen6_init_clock_gating(struct drm_device *dev); -extern void ivybridge_init_clock_gating(struct drm_device *dev); -extern void valleyview_init_clock_gating(struct drm_device *dev); -extern void g4x_init_clock_gating(struct drm_device *dev); -extern void crestline_init_clock_gating(struct drm_device *dev); -extern void broadwater_init_clock_gating(struct drm_device *dev); -extern void gen3_init_clock_gating(struct drm_device *dev); -extern void i85x_init_clock_gating(struct drm_device *dev); -extern void i830_init_clock_gating(struct drm_device *dev); -extern void ibx_init_clock_gating(struct drm_device *dev); -extern void cpt_init_clock_gating(struct drm_device *dev); - #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4f35df2..36940a3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -40,7 +40,7 @@ * i915.i915_enable_fbc parameter */ -void i8xx_disable_fbc(struct drm_device *dev) +static void i8xx_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 fbc_ctl; @@ -62,7 +62,7 @@ void i8xx_disable_fbc(struct drm_device *dev) DRM_DEBUG_KMS("disabled FBC\n"); } -void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -105,14 +105,14 @@ void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) cfb_pitch, crtc->y, intel_crtc->plane); } -bool i8xx_fbc_enabled(struct drm_device *dev) +static bool i8xx_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -139,7 +139,7 @@ void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); } -void g4x_disable_fbc(struct drm_device *dev) +static void g4x_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; @@ -154,7 +154,7 @@ void g4x_disable_fbc(struct drm_device *dev) } } -bool g4x_fbc_enabled(struct drm_device *dev) +static bool g4x_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -181,7 +181,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) gen6_gt_force_wake_put(dev_priv); } -void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -219,7 +219,7 @@ void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); } -void ironlake_disable_fbc(struct drm_device *dev) +static void ironlake_disable_fbc(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; @@ -234,7 +234,7 @@ void ironlake_disable_fbc(struct drm_device *dev) } } -bool ironlake_fbc_enabled(struct drm_device *dev) +static bool ironlake_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -586,7 +586,7 @@ const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, return NULL; } -void pineview_disable_cxsr(struct drm_device *dev) +static void pineview_disable_cxsr(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -610,7 +610,7 @@ void pineview_disable_cxsr(struct drm_device *dev) */ static const int latency_ns = 5000; -int i9xx_get_fifo_size(struct drm_device *dev, int plane) +static int i9xx_get_fifo_size(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dsparb = I915_READ(DSPARB); @@ -626,7 +626,7 @@ int i9xx_get_fifo_size(struct drm_device *dev, int plane) return size; } -int i85x_get_fifo_size(struct drm_device *dev, int plane) +static int i85x_get_fifo_size(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dsparb = I915_READ(DSPARB); @@ -643,7 +643,7 @@ int i85x_get_fifo_size(struct drm_device *dev, int plane) return size; } -int i845_get_fifo_size(struct drm_device *dev, int plane) +static int i845_get_fifo_size(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dsparb = I915_READ(DSPARB); @@ -659,7 +659,7 @@ int i845_get_fifo_size(struct drm_device *dev, int plane) return size; } -int i830_get_fifo_size(struct drm_device *dev, int plane) +static int i830_get_fifo_size(struct drm_device *dev, int plane) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dsparb = I915_READ(DSPARB); @@ -891,7 +891,7 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev) return enabled; } -void pineview_update_wm(struct drm_device *dev) +static void pineview_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -1169,7 +1169,7 @@ static void vlv_update_drain_latency(struct drm_device *dev) #define single_plane_enabled(mask) is_power_of_2(mask) -void valleyview_update_wm(struct drm_device *dev) +static void valleyview_update_wm(struct drm_device *dev) { static const int sr_latency_ns = 12000; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1220,7 +1220,7 @@ void valleyview_update_wm(struct drm_device *dev) (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT))); } -void g4x_update_wm(struct drm_device *dev) +static void g4x_update_wm(struct drm_device *dev) { static const int sr_latency_ns = 12000; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1271,7 +1271,7 @@ void g4x_update_wm(struct drm_device *dev) (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } -void i965_update_wm(struct drm_device *dev) +static void i965_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -1336,7 +1336,7 @@ void i965_update_wm(struct drm_device *dev) I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } -void i9xx_update_wm(struct drm_device *dev) +static void i9xx_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; const struct intel_watermark_params *wm_info; @@ -1447,7 +1447,7 @@ void i9xx_update_wm(struct drm_device *dev) } } -void i830_update_wm(struct drm_device *dev) +static void i830_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -1574,7 +1574,7 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane, display, cursor); } -void ironlake_update_wm(struct drm_device *dev) +static void ironlake_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int fbc_wm, plane_wm, cursor_wm; @@ -1657,7 +1657,7 @@ void ironlake_update_wm(struct drm_device *dev) */ } -void sandybridge_update_wm(struct drm_device *dev) +static void sandybridge_update_wm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */ @@ -1851,7 +1851,7 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, return *sprite_wm > 0x3ff ? false : true; } -void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, +static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe, uint32_t sprite_width, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2578,7 +2578,7 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } -void ironlake_init_clock_gating(struct drm_device *dev) +static void ironlake_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE; @@ -2647,7 +2647,7 @@ void ironlake_init_clock_gating(struct drm_device *dev) _3D_CHICKEN2_WM_READ_PIPELINED); } -void gen6_init_clock_gating(struct drm_device *dev) +static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; @@ -2730,7 +2730,7 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) I915_WRITE(GEN7_FF_THREAD_MODE, reg); } -void ivybridge_init_clock_gating(struct drm_device *dev) +static void ivybridge_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; @@ -2778,7 +2778,7 @@ void ivybridge_init_clock_gating(struct drm_device *dev) gen7_setup_fixed_func_scheduler(dev_priv); } -void valleyview_init_clock_gating(struct drm_device *dev) +static void valleyview_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; @@ -2826,7 +2826,7 @@ void valleyview_init_clock_gating(struct drm_device *dev) PIXEL_SUBSPAN_COLLECT_OPT_DISABLE); } -void g4x_init_clock_gating(struct drm_device *dev) +static void g4x_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t dspclk_gate; @@ -2844,7 +2844,7 @@ void g4x_init_clock_gating(struct drm_device *dev) I915_WRITE(DSPCLK_GATE_D, dspclk_gate); } -void crestline_init_clock_gating(struct drm_device *dev) +static void crestline_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2855,7 +2855,7 @@ void crestline_init_clock_gating(struct drm_device *dev) I915_WRITE16(DEUC, 0); } -void broadwater_init_clock_gating(struct drm_device *dev) +static void broadwater_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2867,7 +2867,7 @@ void broadwater_init_clock_gating(struct drm_device *dev) I915_WRITE(RENCLK_GATE_D2, 0); } -void gen3_init_clock_gating(struct drm_device *dev) +static void gen3_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 dstate = I915_READ(D_STATE); @@ -2877,21 +2877,21 @@ void gen3_init_clock_gating(struct drm_device *dev) I915_WRITE(D_STATE, dstate); } -void i85x_init_clock_gating(struct drm_device *dev) +static void i85x_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE); } -void i830_init_clock_gating(struct drm_device *dev) +static void i830_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE); } -void ibx_init_clock_gating(struct drm_device *dev) +static void ibx_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -2903,7 +2903,7 @@ void ibx_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); } -void cpt_init_clock_gating(struct drm_device *dev) +static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; @@ -2931,3 +2931,145 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_pch_clock_gating(dev); } +/* Set up chip specific power management-related functions */ +void intel_init_pm(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (I915_HAS_FBC(dev)) { + if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (IS_GM45(dev)) { + dev_priv->display.fbc_enabled = g4x_fbc_enabled; + dev_priv->display.enable_fbc = g4x_enable_fbc; + dev_priv->display.disable_fbc = g4x_disable_fbc; + } else if (IS_CRESTLINE(dev)) { + dev_priv->display.fbc_enabled = i8xx_fbc_enabled; + dev_priv->display.enable_fbc = i8xx_enable_fbc; + dev_priv->display.disable_fbc = i8xx_disable_fbc; + } + /* 855GM needs testing */ + } + + /* For FIFO watermark updates */ + if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; + dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; + + /* IVB configs may use multi-threaded forcewake */ + if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { + u32 ecobus; + + /* A small trick here - if the bios hasn't configured MT forcewake, + * and if the device is in RC6, then force_wake_mt_get will not wake + * the device and the ECOBUS read will return zero. Which will be + * (correctly) interpreted by the test below as MT forcewake being + * disabled. + */ + mutex_lock(&dev->struct_mutex); + __gen6_gt_force_wake_mt_get(dev_priv); + ecobus = I915_READ_NOTRACE(ECOBUS); + __gen6_gt_force_wake_mt_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + if (ecobus & FORCEWAKE_MT_ENABLE) { + DRM_DEBUG_KMS("Using MT version of forcewake\n"); + dev_priv->display.force_wake_get = + __gen6_gt_force_wake_mt_get; + dev_priv->display.force_wake_put = + __gen6_gt_force_wake_mt_put; + } + } + + if (HAS_PCH_IBX(dev)) + dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; + else if (HAS_PCH_CPT(dev)) + dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating; + + if (IS_GEN5(dev)) { + if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK) + dev_priv->display.update_wm = ironlake_update_wm; + else { + DRM_DEBUG_KMS("Failed to get proper latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ironlake_init_clock_gating; + } else if (IS_GEN6(dev)) { + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = gen6_init_clock_gating; + } else if (IS_IVYBRIDGE(dev)) { + /* FIXME: detect B0+ stepping and use auto training */ + if (SNB_READ_WM0_LATENCY()) { + dev_priv->display.update_wm = sandybridge_update_wm; + dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm; + } else { + DRM_DEBUG_KMS("Failed to read display plane latency. " + "Disable CxSR\n"); + dev_priv->display.update_wm = NULL; + } + dev_priv->display.init_clock_gating = ivybridge_init_clock_gating; + } else + dev_priv->display.update_wm = NULL; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->display.update_wm = valleyview_update_wm; + dev_priv->display.init_clock_gating = + valleyview_init_clock_gating; + dev_priv->display.force_wake_get = vlv_force_wake_get; + dev_priv->display.force_wake_put = vlv_force_wake_put; + } else if (IS_PINEVIEW(dev)) { + if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev), + dev_priv->is_ddr3, + dev_priv->fsb_freq, + dev_priv->mem_freq)) { + DRM_INFO("failed to find known CxSR latency " + "(found ddr%s fsb freq %d, mem freq %d), " + "disabling CxSR\n", + (dev_priv->is_ddr3 == 1) ? "3" : "2", + dev_priv->fsb_freq, dev_priv->mem_freq); + /* Disable CxSR and never update its watermark again */ + pineview_disable_cxsr(dev); + dev_priv->display.update_wm = NULL; + } else + dev_priv->display.update_wm = pineview_update_wm; + dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_G4X(dev)) { + dev_priv->display.update_wm = g4x_update_wm; + dev_priv->display.init_clock_gating = g4x_init_clock_gating; + } else if (IS_GEN4(dev)) { + dev_priv->display.update_wm = i965_update_wm; + if (IS_CRESTLINE(dev)) + dev_priv->display.init_clock_gating = crestline_init_clock_gating; + else if (IS_BROADWATER(dev)) + dev_priv->display.init_clock_gating = broadwater_init_clock_gating; + } else if (IS_GEN3(dev)) { + dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->display.get_fifo_size = i9xx_get_fifo_size; + dev_priv->display.init_clock_gating = gen3_init_clock_gating; + } else if (IS_I865G(dev)) { + dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + dev_priv->display.get_fifo_size = i830_get_fifo_size; + } else if (IS_I85X(dev)) { + dev_priv->display.update_wm = i9xx_update_wm; + dev_priv->display.get_fifo_size = i85x_get_fifo_size; + dev_priv->display.init_clock_gating = i85x_init_clock_gating; + } else { + dev_priv->display.update_wm = i830_update_wm; + dev_priv->display.init_clock_gating = i830_init_clock_gating; + if (IS_845G(dev)) + dev_priv->display.get_fifo_size = i845_get_fifo_size; + else + dev_priv->display.get_fifo_size = i830_get_fifo_size; + } +} + -- cgit v0.10.2 From 284d5df5716aad3c729d1ac4a2a93b8d0ac33ecc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 14 Apr 2012 17:41:59 +0100 Subject: drm/i915: Silence the change of LVDS sync polarity When the change to start adjusting the sync polarity of the LVDS mode was introduced in commit aa9b500ddf1a6318e7cf8b1754696edddae86db9 Author: Bryan Freed Date: Wed Jan 12 13:43:19 2011 -0800 drm/i915: Honour LVDS sync polarity from EDID we made the change in state verbose so that we could quickly spot any regressions that made have also been introduced with it. As there do not appear to have been any, remove the extra logging. v2: Remove the no longer used variables. Signed-off-by: Chris Wilson Acked-by: Jesse Barnes Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aa647c6..4c844c6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3416,7 +3416,7 @@ static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 temp, lvds_sync = 0; + u32 temp; temp = I915_READ(LVDS); temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; @@ -3446,22 +3446,11 @@ static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock, else temp &= ~LVDS_ENABLE_DITHER; } + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - lvds_sync |= LVDS_HSYNC_POLARITY; + temp |= LVDS_HSYNC_POLARITY; if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - lvds_sync |= LVDS_VSYNC_POLARITY; - if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) - != lvds_sync) { - char flags[2] = "-+"; - DRM_INFO("Changing LVDS panel from " - "(%chsync, %cvsync) to (%chsync, %cvsync)\n", - flags[!(temp & LVDS_HSYNC_POLARITY)], - flags[!(temp & LVDS_VSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - temp |= lvds_sync; - } + temp |= LVDS_VSYNC_POLARITY; I915_WRITE(LVDS, temp); } @@ -4012,7 +4001,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, int ret; struct fdi_m_n m_n = {0}; u32 temp; - u32 lvds_sync = 0; int target_clock, pixel_multiplier, lane, link_bw, factor; unsigned int pipe_bpp; bool dither; @@ -4305,22 +4293,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, * appropriately here, but we need to look more thoroughly into how * panels behave in the two modes. */ + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - lvds_sync |= LVDS_HSYNC_POLARITY; + temp |= LVDS_HSYNC_POLARITY; if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - lvds_sync |= LVDS_VSYNC_POLARITY; - if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY)) - != lvds_sync) { - char flags[2] = "-+"; - DRM_INFO("Changing LVDS panel from " - "(%chsync, %cvsync) to (%chsync, %cvsync)\n", - flags[!(temp & LVDS_HSYNC_POLARITY)], - flags[!(temp & LVDS_VSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_HSYNC_POLARITY)], - flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]); - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - temp |= lvds_sync; - } + temp |= LVDS_VSYNC_POLARITY; I915_WRITE(PCH_LVDS, temp); } -- cgit v0.10.2 From 31b14c9fc596a68a2a982d7e3c136922f81a2e25 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 19 Apr 2012 16:45:22 +0200 Subject: drm/i915: invalidate render cache on gen2 It looks like we also need to flush the render cache when we just invalidate it. This fixes a regression in i-g-t/gem_tiled_blits on my i855gm. I guess the render cache there is virtually indexed, so we need to clean it when changing gtt mappings. This regression has been introduce in commit 46f0f8d120c4afae53a5670bf3ac80a928340ff3 Author: Chris Wilson Date: Wed Apr 18 11:12:11 2012 +0100 drm/i915: Don't set a MBZ bit in gen2/3 MI_FLUSH Reviewed-by: Chris Wilson Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6f610f2..12d9bc7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -61,7 +61,7 @@ gen2_render_ring_flush(struct intel_ring_buffer *ring, int ret; cmd = MI_FLUSH; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) + if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0) cmd |= MI_NO_WRITE_FLUSH; if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) -- cgit v0.10.2 From 3801a7fd8615365a58960561d3bd3479b485ed3e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 20 Apr 2012 13:13:54 +0100 Subject: drm/i915/tv: fix open-coded ARRAY_SIZE. Signed-off-by: Dave Airlie Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index ca12c70..67f444d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -811,7 +811,7 @@ intel_tv_mode_lookup(const char *tv_format) { int i; - for (i = 0; i < sizeof(tv_modes) / sizeof(tv_modes[0]); i++) { + for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { const struct tv_mode *tv_mode = &tv_modes[i]; if (!strcmp(tv_format, tv_mode->name)) -- cgit v0.10.2 From a85d4bcb8a0cd5b3c754f98ff91ef2b9b3a73bc5 Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Fri, 20 Apr 2012 11:50:01 -0700 Subject: drm/i915: rc6 residency (fix the fix) Chris' fix for my 32b breakage was incorrect. do_div returns a remainder. Go back to a divide macro which is more 32b friendly. Tested on x86-64. This has only been compile tested on 32b systems. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=48756 Cc: Chris Wilson Sincere-apologies: Chris Wilson Signed-off-by: Ben Widawsky [danvet: fixup 32bit compile-fail.] Signed-Off-by: Daniel Vetter diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index f1b5108..79f8344 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -39,8 +39,8 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) if (!intel_enable_rc6(dev)) return 0; - raw_time = I915_READ(reg) * 128ULL + 500; - return do_div(raw_time, 100000); + raw_time = I915_READ(reg) * 128ULL; + return DIV_ROUND_UP_ULL(raw_time, 100000); } static ssize_t -- cgit v0.10.2