Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Apr 2010 18:52:48 +0000 (11:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 9 Apr 2010 18:52:48 +0000 (11:52 -0700)
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6:
  [S390] Update default configuration.
  [S390] nss: add missing .previous statement to asm function
  [S390] increase default size of vmalloc area
  [S390] s390: disable change bit override
  [S390] fix io_return critical section cleanup
  [S390] sclp_async: potential buffer overflow
  [S390] arch/s390/kernel: Add missing unlock

77 files changed:
Documentation/DocBook/tracepoint.tmpl
Documentation/block/biodoc.txt
block/Kconfig
block/blk-settings.c
block/blk-sysfs.c
block/cfq-iosched.c
block/elevator.c
drivers/base/memory.c
drivers/block/DAC960.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_worker.c
drivers/block/loop.c
drivers/block/paride/pcd.c
drivers/block/paride/pf.c
drivers/block/paride/pt.c
drivers/block/virtio_blk.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_debugfs.c
drivers/gpu/drm/nouveau/nouveau_dp.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_encoder.h
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_irq.c
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_display.h
drivers/gpu/drm/nouveau/nv50_fbcon.c
drivers/gpu/drm/nouveau/nv50_gpio.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/nouveau/nv50_sor.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_legacy_encoders.c
drivers/scsi/sd.c
fs/bio.c
fs/cifs/cifsfs.c
fs/cifs/cifssmb.c
fs/cifs/file.c
fs/fs-writeback.c
include/linux/blkdev.h
include/linux/drbd.h
include/linux/drbd_nl.h
include/linux/genhd.h
include/linux/i2o.h
include/linux/lcm.h [new file with mode: 0644]
include/linux/radix-tree.h
include/linux/slab.h
include/linux/writeback.h
include/trace/events/block.h
lib/Makefile
lib/lcm.c [new file with mode: 0644]
lib/radix-tree.c
mm/backing-dev.c
mm/slab.c
mm/slub.c
mm/util.c

index 8bca1d5cec09a8bf6c8c5f0e6f159d770fcf806c..e8473eae2a2064ecef2afadf2e92551dc327bea3 100644 (file)
      </address>
     </affiliation>
    </author>
+   <author>
+    <firstname>William</firstname>
+    <surname>Cohen</surname>
+    <affiliation>
+     <address>
+      <email>wcohen@redhat.com</email>
+     </address>
+    </affiliation>
+   </author>
   </authorgroup>
 
   <legalnotice>
 !Iinclude/trace/events/signal.h
   </chapter>
 
+  <chapter id="block">
+   <title>Block IO</title>
+!Iinclude/trace/events/block.h
+  </chapter>
 </book>
index 6fab97ea7e6b0ecd4b3973cd0787257f14647617..508b5b2b0289dd88215a26301aa633d4c45821e8 100644 (file)
@@ -1162,8 +1162,8 @@ where a driver received a request ala this before:
 
 As mentioned, there is no virtual mapping of a bio. For DMA, this is
 not a problem as the driver probably never will need a virtual mapping.
-Instead it needs a bus mapping (pci_map_page for a single segment or
-use blk_rq_map_sg for scatter gather) to be able to ship it to the driver. For
+Instead it needs a bus mapping (dma_map_page for a single segment or
+use dma_map_sg for scatter gather) to be able to ship it to the driver. For
 PIO drivers (or drivers that need to revert to PIO transfer once in a
 while (IDE for example)), where the CPU is doing the actual data
 transfer a virtual mapping is needed. If the driver supports highmem I/O,
index 62a5921321cd4e379223bc9fba4242a5dba488b6..f9e89f4d94bba17392f0416598d0ff7f27f92002 100644 (file)
@@ -78,8 +78,9 @@ config BLK_DEV_INTEGRITY
        Protection.  If in doubt, say N.
 
 config BLK_CGROUP
-       tristate
+       tristate "Block cgroup support"
        depends on CGROUPS
+       depends on CFQ_GROUP_IOSCHED
        default n
        ---help---
        Generic block IO controller cgroup interface. This is the common
index d9a9db5f0a2bddfbdd6e5dbfe8a8c0c7a73b24b0..f5ed5a1187ba8564527b70f682328b31eea4549a 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/bootmem.h>     /* for max_pfn/max_low_pfn */
 #include <linux/gcd.h>
+#include <linux/lcm.h>
 #include <linux/jiffies.h>
 #include <linux/gfp.h>
 
@@ -462,16 +463,6 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
 }
 EXPORT_SYMBOL(blk_queue_stack_limits);
 
-static unsigned int lcm(unsigned int a, unsigned int b)
-{
-       if (a && b)
-               return (a * b) / gcd(a, b);
-       else if (b)
-               return b;
-
-       return a;
-}
-
 /**
  * blk_stack_limits - adjust queue_limits for stacked devices
  * @t: the stacking driver limits (top device)
index c2b821fa324a115b95c5dd93920b34dd189f9dc7..306759bbdf1be719ef1f8e0a1f1912475c521a09 100644 (file)
@@ -107,6 +107,19 @@ static ssize_t queue_max_sectors_show(struct request_queue *q, char *page)
        return queue_var_show(max_sectors_kb, (page));
 }
 
+static ssize_t queue_max_segments_show(struct request_queue *q, char *page)
+{
+       return queue_var_show(queue_max_segments(q), (page));
+}
+
+static ssize_t queue_max_segment_size_show(struct request_queue *q, char *page)
+{
+       if (test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
+               return queue_var_show(queue_max_segment_size(q), (page));
+
+       return queue_var_show(PAGE_CACHE_SIZE, (page));
+}
+
 static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page)
 {
        return queue_var_show(queue_logical_block_size(q), page);
@@ -281,6 +294,16 @@ static struct queue_sysfs_entry queue_max_hw_sectors_entry = {
        .show = queue_max_hw_sectors_show,
 };
 
+static struct queue_sysfs_entry queue_max_segments_entry = {
+       .attr = {.name = "max_segments", .mode = S_IRUGO },
+       .show = queue_max_segments_show,
+};
+
+static struct queue_sysfs_entry queue_max_segment_size_entry = {
+       .attr = {.name = "max_segment_size", .mode = S_IRUGO },
+       .show = queue_max_segment_size_show,
+};
+
 static struct queue_sysfs_entry queue_iosched_entry = {
        .attr = {.name = "scheduler", .mode = S_IRUGO | S_IWUSR },
        .show = elv_iosched_show,
@@ -356,6 +379,8 @@ static struct attribute *default_attrs[] = {
        &queue_ra_entry.attr,
        &queue_max_hw_sectors_entry.attr,
        &queue_max_sectors_entry.attr,
+       &queue_max_segments_entry.attr,
+       &queue_max_segment_size_entry.attr,
        &queue_iosched_entry.attr,
        &queue_hw_sector_size_entry.attr,
        &queue_logical_block_size_entry.attr,
index fc98a48554fd46025c4dcc9a12f75dc4a98e609b..838834be115b3f341f3bc6e0eba54a5c3fcc424c 100644 (file)
@@ -48,6 +48,7 @@ static const int cfq_hist_divisor = 4;
 #define CFQ_SERVICE_SHIFT       12
 
 #define CFQQ_SEEK_THR          (sector_t)(8 * 100)
+#define CFQQ_CLOSE_THR         (sector_t)(8 * 1024)
 #define CFQQ_SECT_THR_NONROT   (sector_t)(2 * 32)
 #define CFQQ_SEEKY(cfqq)       (hweight32(cfqq->seek_history) > 32/8)
 
@@ -948,6 +949,11 @@ cfq_find_alloc_cfqg(struct cfq_data *cfqd, struct cgroup *cgroup, int create)
        unsigned int major, minor;
 
        cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
+       if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+               sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+               cfqg->blkg.dev = MKDEV(major, minor);
+               goto done;
+       }
        if (cfqg || !create)
                goto done;
 
@@ -1518,7 +1524,8 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
                                   struct cfq_queue *cfqq)
 {
        if (cfqq) {
-               cfq_log_cfqq(cfqd, cfqq, "set_active");
+               cfq_log_cfqq(cfqd, cfqq, "set_active wl_prio:%d wl_type:%d",
+                               cfqd->serving_prio, cfqd->serving_type);
                cfqq->slice_start = 0;
                cfqq->dispatch_start = jiffies;
                cfqq->allocated_slice = 0;
@@ -1661,9 +1668,9 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
 }
 
 static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq,
-                              struct request *rq, bool for_preempt)
+                              struct request *rq)
 {
-       return cfq_dist_from_last(cfqd, rq) <= CFQQ_SEEK_THR;
+       return cfq_dist_from_last(cfqd, rq) <= CFQQ_CLOSE_THR;
 }
 
 static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
@@ -1690,7 +1697,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
         * will contain the closest sector.
         */
        __cfqq = rb_entry(parent, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        if (blk_rq_pos(__cfqq->next_rq) < sector)
@@ -1701,7 +1708,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
                return NULL;
 
        __cfqq = rb_entry(node, struct cfq_queue, p_node);
-       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq, false))
+       if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq))
                return __cfqq;
 
        return NULL;
@@ -1722,6 +1729,8 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
 {
        struct cfq_queue *cfqq;
 
+       if (cfq_class_idle(cur_cfqq))
+               return NULL;
        if (!cfq_cfqq_sync(cur_cfqq))
                return NULL;
        if (CFQQ_SEEKY(cur_cfqq))
@@ -1788,7 +1797,11 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
         * Otherwise, we do only if they are the last ones
         * in their service tree.
         */
-       return service_tree->count == 1 && cfq_cfqq_sync(cfqq);
+       if (service_tree->count == 1 && cfq_cfqq_sync(cfqq))
+               return 1;
+       cfq_log_cfqq(cfqd, cfqq, "Not idling. st->count:%d",
+                       service_tree->count);
+       return 0;
 }
 
 static void cfq_arm_slice_timer(struct cfq_data *cfqd)
@@ -1833,8 +1846,11 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
         * time slice.
         */
        if (sample_valid(cic->ttime_samples) &&
-           (cfqq->slice_end - jiffies < cic->ttime_mean))
+           (cfqq->slice_end - jiffies < cic->ttime_mean)) {
+               cfq_log_cfqq(cfqd, cfqq, "Not idling. think_time:%d",
+                               cic->ttime_mean);
                return;
+       }
 
        cfq_mark_cfqq_wait_request(cfqq);
 
@@ -2042,6 +2058,7 @@ static void choose_service_tree(struct cfq_data *cfqd, struct cfq_group *cfqg)
                slice = max(slice, 2 * cfqd->cfq_slice_idle);
 
        slice = max_t(unsigned, slice, CFQ_MIN_TT);
+       cfq_log(cfqd, "workload slice:%d", slice);
        cfqd->workload_expires = jiffies + slice;
        cfqd->noidle_tree_requires_idle = false;
 }
@@ -2189,10 +2206,13 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
        struct cfq_queue *cfqq;
        int dispatched = 0;
 
-       while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL)
+       /* Expire the timeslice of the current active queue first */
+       cfq_slice_expired(cfqd, 0);
+       while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL) {
+               __cfq_set_active_queue(cfqd, cfqq);
                dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+       }
 
-       cfq_slice_expired(cfqd, 0);
        BUG_ON(cfqd->busy_queues);
 
        cfq_log(cfqd, "forced_dispatch=%d", dispatched);
@@ -3104,7 +3124,7 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
         * if this request is as-good as one we would expect from the
         * current cfqq, let it preempt
         */
-       if (cfq_rq_close(cfqd, cfqq, rq, true))
+       if (cfq_rq_close(cfqd, cfqq, rq))
                return true;
 
        return false;
@@ -3308,6 +3328,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
                if (cfq_should_wait_busy(cfqd, cfqq)) {
                        cfqq->slice_end = jiffies + cfqd->cfq_slice_idle;
                        cfq_mark_cfqq_wait_busy(cfqq);
+                       cfq_log_cfqq(cfqd, cfqq, "will busy wait");
                }
 
                /*
index df75676f6671ea97e33b78567dae2fbfb0f75058..76e3702d53817e4aee08d092a59f07ca840145cc 100644 (file)
@@ -154,7 +154,7 @@ static struct elevator_type *elevator_get(const char *name)
 
                spin_unlock(&elv_list_lock);
 
-               sprintf(elv, "%s-iosched", name);
+               snprintf(elv, sizeof(elv), "%s-iosched", name);
 
                request_module("%s", elv);
                spin_lock(&elv_list_lock);
index 4f4aa5897b4cee4722fed70a0820df5e49f9d000..933442f40321b1889b183cf4396486a4c35ad96f 100644 (file)
@@ -313,7 +313,7 @@ static ssize_t
 print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
                 char *buf)
 {
-       return sprintf(buf, "%#lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
+       return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
 }
 
 static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
index 459f1bc25a7b813e1094f54903d57852825983af..c5f22bb0a48efb78422f770bb298fdcc94203d96 100644 (file)
@@ -2533,7 +2533,6 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
        Controller->RequestQueue[n] = RequestQueue;
        blk_queue_bounce_limit(RequestQueue, Controller->BounceBufferLimit);
        RequestQueue->queuedata = Controller;
-       blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit);
        blk_queue_max_segments(RequestQueue, Controller->DriverScatterGatherLimit);
        blk_queue_max_hw_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
        disk->queue = RequestQueue;
index 17956ff6a08dea7b4de01e707553de42ca60bd22..df018990c42252f59f4e57c40abddabb3118368f 100644 (file)
@@ -536,7 +536,9 @@ static void atodb_endio(struct bio *bio, int error)
        put_ldev(mdev);
 }
 
+/* sector to word */
 #define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL))
+
 /* activity log to on disk bitmap -- prepare bio unless that sector
  * is already covered by previously prepared bios */
 static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
@@ -546,13 +548,20 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
 {
        struct bio *bio;
        struct page *page;
-       sector_t on_disk_sector = enr + mdev->ldev->md.md_offset
-                                     + mdev->ldev->md.bm_offset;
+       sector_t on_disk_sector;
        unsigned int page_offset = PAGE_SIZE;
        int offset;
        int i = 0;
        int err = -ENOMEM;
 
+       /* We always write aligned, full 4k blocks,
+        * so we can ignore the logical_block_size (for now) */
+       enr &= ~7U;
+       on_disk_sector = enr + mdev->ldev->md.md_offset
+                            + mdev->ldev->md.bm_offset;
+
+       D_ASSERT(!(on_disk_sector & 7U));
+
        /* Check if that enr is already covered by an already created bio.
         * Caution, bios[] is not NULL terminated,
         * but only initialized to all NULL.
@@ -588,7 +597,7 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
 
        offset = S2W(enr);
        drbd_bm_get_lel(mdev, offset,
-                       min_t(size_t, S2W(1), drbd_bm_words(mdev) - offset),
+                       min_t(size_t, S2W(8), drbd_bm_words(mdev) - offset),
                        kmap(page) + page_offset);
        kunmap(page);
 
@@ -597,7 +606,7 @@ static int atodb_prepare_unless_covered(struct drbd_conf *mdev,
        bio->bi_bdev = mdev->ldev->md_bdev;
        bio->bi_sector = on_disk_sector;
 
-       if (bio_add_page(bio, page, MD_SECTOR_SIZE, page_offset) != MD_SECTOR_SIZE)
+       if (bio_add_page(bio, page, 4096, page_offset) != 4096)
                goto out_put_page;
 
        atomic_inc(&wc->count);
@@ -1327,7 +1336,7 @@ int drbd_rs_del_all(struct drbd_conf *mdev)
                /* ok, ->resync is there. */
                for (i = 0; i < mdev->resync->nr_elements; i++) {
                        e = lc_element_by_index(mdev->resync, i);
-                       bm_ext = e ? lc_entry(e, struct bm_extent, lce) : NULL;
+                       bm_ext = lc_entry(e, struct bm_extent, lce);
                        if (bm_ext->lce.lc_number == LC_FREE)
                                continue;
                        if (bm_ext->lce.lc_number == mdev->resync_wenr) {
index 3d6f3d988949f913269d2cd7c5db642319bab6f0..3390716898d5aaf429b8c08db34cd28ff68ed569 100644 (file)
@@ -67,7 +67,7 @@ struct drbd_bitmap {
        size_t   bm_words;
        size_t   bm_number_of_pages;
        sector_t bm_dev_capacity;
-       struct semaphore bm_change; /* serializes resize operations */
+       struct mutex bm_change; /* serializes resize operations */
 
        atomic_t bm_async_io;
        wait_queue_head_t bm_io_wait;
@@ -115,7 +115,7 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why)
                return;
        }
 
-       trylock_failed = down_trylock(&b->bm_change);
+       trylock_failed = !mutex_trylock(&b->bm_change);
 
        if (trylock_failed) {
                dev_warn(DEV, "%s going to '%s' but bitmap already locked for '%s' by %s\n",
@@ -126,7 +126,7 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why)
                    b->bm_task == mdev->receiver.task ? "receiver" :
                    b->bm_task == mdev->asender.task  ? "asender"  :
                    b->bm_task == mdev->worker.task   ? "worker"   : "?");
-               down(&b->bm_change);
+               mutex_lock(&b->bm_change);
        }
        if (__test_and_set_bit(BM_LOCKED, &b->bm_flags))
                dev_err(DEV, "FIXME bitmap already locked in bm_lock\n");
@@ -148,7 +148,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev)
 
        b->bm_why  = NULL;
        b->bm_task = NULL;
-       up(&b->bm_change);
+       mutex_unlock(&b->bm_change);
 }
 
 /* word offset to long pointer */
@@ -296,7 +296,7 @@ int drbd_bm_init(struct drbd_conf *mdev)
        if (!b)
                return -ENOMEM;
        spin_lock_init(&b->bm_lock);
-       init_MUTEX(&b->bm_change);
+       mutex_init(&b->bm_change);
        init_waitqueue_head(&b->bm_io_wait);
 
        mdev->bitmap = b;
index d9301e861d9f355f611128f625cd470ad05b3383..e5e86a78182001fc0894f0aa156470a75abf9154 100644 (file)
@@ -261,6 +261,9 @@ static inline const char *cmdname(enum drbd_packets cmd)
                [P_OV_REQUEST]          = "OVRequest",
                [P_OV_REPLY]            = "OVReply",
                [P_OV_RESULT]           = "OVResult",
+               [P_CSUM_RS_REQUEST]     = "CsumRSRequest",
+               [P_RS_IS_IN_SYNC]       = "CsumRSIsInSync",
+               [P_COMPRESSED_BITMAP]   = "CBitmap",
                [P_MAX_CMD]             = NULL,
        };
 
@@ -443,13 +446,18 @@ struct p_rs_param_89 {
        char csums_alg[SHARED_SECRET_MAX];
 } __packed;
 
+enum drbd_conn_flags {
+       CF_WANT_LOSE = 1,
+       CF_DRY_RUN = 2,
+};
+
 struct p_protocol {
        struct p_header head;
        u32 protocol;
        u32 after_sb_0p;
        u32 after_sb_1p;
        u32 after_sb_2p;
-       u32 want_lose;
+       u32 conn_flags;
        u32 two_primaries;
 
               /* Since protocol version 87 and higher. */
@@ -791,6 +799,8 @@ enum {
                                 * while this is set. */
        RESIZE_PENDING,         /* Size change detected locally, waiting for the response from
                                 * the peer, if it changed there as well. */
+       CONN_DRY_RUN,           /* Expect disconnect after resync handshake. */
+       GOT_PING_ACK,           /* set when we receive a ping_ack packet, misc wait gets woken */
 };
 
 struct drbd_bitmap; /* opaque for drbd_conf */
index ab871e00ffc5b91702f3adfa6dbf2eeaa4047e24..67e0fc5422497f269bb8ccb9ab1ae24c12db6a09 100644 (file)
@@ -1668,7 +1668,7 @@ int drbd_send_sync_param(struct drbd_conf *mdev, struct syncer_conf *sc)
 int drbd_send_protocol(struct drbd_conf *mdev)
 {
        struct p_protocol *p;
-       int size, rv;
+       int size, cf, rv;
 
        size = sizeof(struct p_protocol);
 
@@ -1685,9 +1685,21 @@ int drbd_send_protocol(struct drbd_conf *mdev)
        p->after_sb_0p   = cpu_to_be32(mdev->net_conf->after_sb_0p);
        p->after_sb_1p   = cpu_to_be32(mdev->net_conf->after_sb_1p);
        p->after_sb_2p   = cpu_to_be32(mdev->net_conf->after_sb_2p);
-       p->want_lose     = cpu_to_be32(mdev->net_conf->want_lose);
        p->two_primaries = cpu_to_be32(mdev->net_conf->two_primaries);
 
+       cf = 0;
+       if (mdev->net_conf->want_lose)
+               cf |= CF_WANT_LOSE;
+       if (mdev->net_conf->dry_run) {
+               if (mdev->agreed_pro_version >= 92)
+                       cf |= CF_DRY_RUN;
+               else {
+                       dev_err(DEV, "--dry-run is not supported by peer");
+                       return 0;
+               }
+       }
+       p->conn_flags    = cpu_to_be32(cf);
+
        if (mdev->agreed_pro_version >= 87)
                strcpy(p->integrity_alg, mdev->net_conf->integrity_alg);
 
@@ -3161,14 +3173,18 @@ void drbd_free_bc(struct drbd_backing_dev *ldev)
 void drbd_free_sock(struct drbd_conf *mdev)
 {
        if (mdev->data.socket) {
+               mutex_lock(&mdev->data.mutex);
                kernel_sock_shutdown(mdev->data.socket, SHUT_RDWR);
                sock_release(mdev->data.socket);
                mdev->data.socket = NULL;
+               mutex_unlock(&mdev->data.mutex);
        }
        if (mdev->meta.socket) {
+               mutex_lock(&mdev->meta.mutex);
                kernel_sock_shutdown(mdev->meta.socket, SHUT_RDWR);
                sock_release(mdev->meta.socket);
                mdev->meta.socket = NULL;
+               mutex_unlock(&mdev->meta.mutex);
        }
 }
 
index 4df3b40b1057d225fe310601c77021a6f37f0d7c..6429d2b19e064a0e5aa56c77a91aca2d96e588dd 100644 (file)
@@ -285,8 +285,8 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
                }
 
                if (r == SS_NO_UP_TO_DATE_DISK && force &&
-                   (mdev->state.disk == D_INCONSISTENT ||
-                    mdev->state.disk == D_OUTDATED)) {
+                   (mdev->state.disk < D_UP_TO_DATE &&
+                    mdev->state.disk >= D_INCONSISTENT)) {
                        mask.disk = D_MASK;
                        val.disk  = D_UP_TO_DATE;
                        forced = 1;
@@ -407,7 +407,7 @@ static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
        }
 
        reply->ret_code =
-               drbd_set_role(mdev, R_PRIMARY, primary_args.overwrite_peer);
+               drbd_set_role(mdev, R_PRIMARY, primary_args.primary_force);
 
        return 0;
 }
@@ -941,6 +941,25 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
 
        drbd_md_set_sector_offsets(mdev, nbc);
 
+       /* allocate a second IO page if logical_block_size != 512 */
+       logical_block_size = bdev_logical_block_size(nbc->md_bdev);
+       if (logical_block_size == 0)
+               logical_block_size = MD_SECTOR_SIZE;
+
+       if (logical_block_size != MD_SECTOR_SIZE) {
+               if (!mdev->md_io_tmpp) {
+                       struct page *page = alloc_page(GFP_NOIO);
+                       if (!page)
+                               goto force_diskless_dec;
+
+                       dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n",
+                            logical_block_size, MD_SECTOR_SIZE);
+                       dev_warn(DEV, "Workaround engaged (has performance impact).\n");
+
+                       mdev->md_io_tmpp = page;
+               }
+       }
+
        if (!mdev->bitmap) {
                if (drbd_bm_init(mdev)) {
                        retcode = ERR_NOMEM;
@@ -980,25 +999,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
                goto force_diskless_dec;
        }
 
-       /* allocate a second IO page if logical_block_size != 512 */
-       logical_block_size = bdev_logical_block_size(nbc->md_bdev);
-       if (logical_block_size == 0)
-               logical_block_size = MD_SECTOR_SIZE;
-
-       if (logical_block_size != MD_SECTOR_SIZE) {
-               if (!mdev->md_io_tmpp) {
-                       struct page *page = alloc_page(GFP_NOIO);
-                       if (!page)
-                               goto force_diskless_dec;
-
-                       dev_warn(DEV, "Meta data's bdev logical_block_size = %d != %d\n",
-                            logical_block_size, MD_SECTOR_SIZE);
-                       dev_warn(DEV, "Workaround engaged (has performance impact).\n");
-
-                       mdev->md_io_tmpp = page;
-               }
-       }
-
        /* Reset the "barriers don't work" bits here, then force meta data to
         * be written, to ensure we determine if barriers are supported. */
        if (nbc->dc.no_md_flush)
index d065c646b35a06fe9fba171864951efbe12e405d..ed9f1de24a71e39664be0d47976f9375e3e0ac28 100644 (file)
@@ -2513,6 +2513,10 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
        }
 
        if (hg == -100) {
+               /* FIXME this log message is not correct if we end up here
+                * after an attempted attach on a diskless node.
+                * We just refuse to attach -- well, we drop the "connection"
+                * to that disk, in a way... */
                dev_alert(DEV, "Split-Brain detected, dropping connection!\n");
                drbd_khelper(mdev, "split-brain");
                return C_MASK;
@@ -2538,6 +2542,16 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol
                }
        }
 
+       if (mdev->net_conf->dry_run || test_bit(CONN_DRY_RUN, &mdev->flags)) {
+               if (hg == 0)
+                       dev_info(DEV, "dry-run connect: No resync, would become Connected immediately.\n");
+               else
+                       dev_info(DEV, "dry-run connect: Would become %s, doing a %s resync.",
+                                drbd_conn_str(hg > 0 ? C_SYNC_SOURCE : C_SYNC_TARGET),
+                                abs(hg) >= 2 ? "full" : "bit-map based");
+               return C_MASK;
+       }
+
        if (abs(hg) >= 2) {
                dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n");
                if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake"))
@@ -2585,7 +2599,7 @@ static int receive_protocol(struct drbd_conf *mdev, struct p_header *h)
        struct p_protocol *p = (struct p_protocol *)h;
        int header_size, data_size;
        int p_proto, p_after_sb_0p, p_after_sb_1p, p_after_sb_2p;
-       int p_want_lose, p_two_primaries;
+       int p_want_lose, p_two_primaries, cf;
        char p_integrity_alg[SHARED_SECRET_MAX] = "";
 
        header_size = sizeof(*p) - sizeof(*h);
@@ -2598,8 +2612,14 @@ static int receive_protocol(struct drbd_conf *mdev, struct p_header *h)
        p_after_sb_0p   = be32_to_cpu(p->after_sb_0p);
        p_after_sb_1p   = be32_to_cpu(p->after_sb_1p);
        p_after_sb_2p   = be32_to_cpu(p->after_sb_2p);
-       p_want_lose     = be32_to_cpu(p->want_lose);
        p_two_primaries = be32_to_cpu(p->two_primaries);
+       cf              = be32_to_cpu(p->conn_flags);
+       p_want_lose = cf & CF_WANT_LOSE;
+
+       clear_bit(CONN_DRY_RUN, &mdev->flags);
+
+       if (cf & CF_DRY_RUN)
+               set_bit(CONN_DRY_RUN, &mdev->flags);
 
        if (p_proto != mdev->net_conf->wire_protocol) {
                dev_err(DEV, "incompatible communication protocols\n");
@@ -3118,13 +3138,16 @@ static int receive_state(struct drbd_conf *mdev, struct p_header *h)
 
                put_ldev(mdev);
                if (nconn == C_MASK) {
+                       nconn = C_CONNECTED;
                        if (mdev->state.disk == D_NEGOTIATING) {
                                drbd_force_state(mdev, NS(disk, D_DISKLESS));
-                               nconn = C_CONNECTED;
                        } else if (peer_state.disk == D_NEGOTIATING) {
                                dev_err(DEV, "Disk attach process on the peer node was aborted.\n");
                                peer_state.disk = D_DISKLESS;
+                               real_peer_disk = D_DISKLESS;
                        } else {
+                               if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags))
+                                       return FALSE;
                                D_ASSERT(oconn == C_WF_REPORT_PARAMS);
                                drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
                                return FALSE;
@@ -3594,10 +3617,7 @@ static void drbd_disconnect(struct drbd_conf *mdev)
 
        /* asender does not clean up anything. it must not interfere, either */
        drbd_thread_stop(&mdev->asender);
-
-       mutex_lock(&mdev->data.mutex);
        drbd_free_sock(mdev);
-       mutex_unlock(&mdev->data.mutex);
 
        spin_lock_irq(&mdev->req_lock);
        _drbd_wait_ee_list_empty(mdev, &mdev->active_ee);
@@ -4054,6 +4074,8 @@ static int got_PingAck(struct drbd_conf *mdev, struct p_header *h)
 {
        /* restore idle timeout */
        mdev->meta.socket->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ;
+       if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags))
+               wake_up(&mdev->misc_wait);
 
        return TRUE;
 }
index b453c2bca3be5d3740c81be7e41d2ff953bb937d..44bf6d11197e7bbad72f511ba36fba23747be68e 100644 (file)
@@ -938,7 +938,8 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
 
                if (eq) {
                        drbd_set_in_sync(mdev, e->sector, e->size);
-                       mdev->rs_same_csum++;
+                       /* rs_same_csums unit is BM_BLOCK_SIZE */
+                       mdev->rs_same_csum += e->size >> BM_BLOCK_SHIFT;
                        ok = drbd_send_ack(mdev, P_RS_IS_IN_SYNC, e);
                } else {
                        inc_rs_pending(mdev);
@@ -1288,6 +1289,14 @@ int drbd_alter_sa(struct drbd_conf *mdev, int na)
        return retcode;
 }
 
+static void ping_peer(struct drbd_conf *mdev)
+{
+       clear_bit(GOT_PING_ACK, &mdev->flags);
+       request_ping(mdev);
+       wait_event(mdev->misc_wait,
+                  test_bit(GOT_PING_ACK, &mdev->flags) || mdev->state.conn < C_CONNECTED);
+}
+
 /**
  * drbd_start_resync() - Start the resync process
  * @mdev:      DRBD device.
@@ -1371,7 +1380,6 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
                _drbd_pause_after(mdev);
        }
        write_unlock_irq(&global_state_lock);
-       drbd_state_unlock(mdev);
        put_ldev(mdev);
 
        if (r == SS_SUCCESS) {
@@ -1382,11 +1390,8 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
 
                if (mdev->rs_total == 0) {
                        /* Peer still reachable? Beware of failing before-resync-target handlers! */
-                       request_ping(mdev);
-                       __set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(mdev->net_conf->ping_timeo*HZ/9); /* 9 instead 10 */
+                       ping_peer(mdev);
                        drbd_resync_finished(mdev);
-                       return;
                }
 
                /* ns.conn may already be != mdev->state.conn,
@@ -1398,6 +1403,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side)
 
                drbd_md_sync(mdev);
        }
+       drbd_state_unlock(mdev);
 }
 
 int drbd_worker(struct drbd_thread *thi)
index cb69929d917a5a8221a5045eba71f0ebd480ffc2..8546d123b9a745492cbbe0aace5b5ce6a2324298 100644 (file)
@@ -237,6 +237,8 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
                if (ret)
                        goto fail;
 
+               file_update_time(file);
+
                transfer_result = lo_do_transfer(lo, WRITE, page, offset,
                                bvec->bv_page, bv_offs, size, IV);
                copied = size;
index 8866ca369d5e5e1814c27eab1b3c53fb5ff0777b..71acf4e53356f6ba6e4810848324e2ea268ae482 100644 (file)
@@ -341,11 +341,11 @@ static int pcd_wait(struct pcd_unit *cd, int go, int stop, char *fun, char *msg)
               && (j++ < PCD_SPIN))
                udelay(PCD_DELAY);
 
-       if ((r & (IDE_ERR & stop)) || (j >= PCD_SPIN)) {
+       if ((r & (IDE_ERR & stop)) || (j > PCD_SPIN)) {
                s = read_reg(cd, 7);
                e = read_reg(cd, 1);
                p = read_reg(cd, 2);
-               if (j >= PCD_SPIN)
+               if (j > PCD_SPIN)
                        e |= 0x100;
                if (fun)
                        printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
index ddb4f9abd480b8f0cb6ce013d6c514e5a211d120..c059aab3006b9a5c794e0b91814dd41d064c0052 100644 (file)
@@ -391,11 +391,11 @@ static int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg)
               && (j++ < PF_SPIN))
                udelay(PF_SPIN_DEL);
 
-       if ((r & (STAT_ERR & stop)) || (j >= PF_SPIN)) {
+       if ((r & (STAT_ERR & stop)) || (j > PF_SPIN)) {
                s = read_reg(pf, 7);
                e = read_reg(pf, 1);
                p = read_reg(pf, 2);
-               if (j >= PF_SPIN)
+               if (j > PF_SPIN)
                        e |= 0x100;
                if (fun)
                        printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
index 1e4006e18f03060138709ed6930e770211e5706e..bc5825fdeaabcfa297e9d00ffe1be1e8ade921fe 100644 (file)
@@ -274,11 +274,11 @@ static int pt_wait(struct pt_unit *tape, int go, int stop, char *fun, char *msg)
               && (j++ < PT_SPIN))
                udelay(PT_SPIN_DEL);
 
-       if ((r & (STAT_ERR & stop)) || (j >= PT_SPIN)) {
+       if ((r & (STAT_ERR & stop)) || (j > PT_SPIN)) {
                s = read_reg(pi, 7);
                e = read_reg(pi, 1);
                p = read_reg(pi, 2);
-               if (j >= PT_SPIN)
+               if (j > PT_SPIN)
                        e |= 0x100;
                if (fun)
                        printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
index 4b12b820c9a62f655e0745b8d2eae87c16d55437..2138a7ae050c10c44bdba1608f441a7811ca1a22 100644 (file)
@@ -348,14 +348,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        set_capacity(vblk->disk, cap);
 
        /* We can handle whatever the host told us to handle. */
-       blk_queue_max_phys_segments(q, vblk->sg_elems-2);
-       blk_queue_max_hw_segments(q, vblk->sg_elems-2);
+       blk_queue_max_segments(q, vblk->sg_elems-2);
 
        /* No need to bounce any requests */
        blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
 
        /* No real sector limit. */
-       blk_queue_max_sectors(q, -1U);
+       blk_queue_max_hw_sectors(q, -1U);
 
        /* Host can optionally specify maximum segment size and number of
         * segments. */
index 2cc6e87d849d6d9f16271fdd0c17032aa4a8d5a6..18f41d7061f0d04f7ff9e1b465ea6565aa520cbe 100644 (file)
@@ -85,6 +85,8 @@ static struct edid_quirk {
 
        /* Envision Peripherals, Inc. EN-7100e */
        { "EPI", 59264, EDID_QUIRK_135_CLOCK_TOO_HIGH },
+       /* Envision EN2028 */
+       { "EPI", 8232, EDID_QUIRK_PREFER_LARGE_60 },
 
        /* Funai Electronics PM36B */
        { "FCM", 13600, EDID_QUIRK_PREFER_LARGE_75 |
index 7f0d807a0d0d4f1bc220ef59ca02ce917aa0dfde..453df3f6053fbb0ffbe865b1e6f25cc1718d6492 100644 (file)
@@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv50_cursor.o nv50_display.o nv50_fbcon.o \
              nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
              nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
-             nv17_gpio.o
+             nv17_gpio.o nv50_gpio.o
 
 nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
 nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
index b5a9336a2e88f58d3e90129c631262896f0f163b..abc382a9918bfe9be71c33cb2cba83ee07a25d08 100644 (file)
@@ -2573,48 +2573,34 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
         * each GPIO according to various values listed in each entry
         */
 
-       const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
+       struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
        const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
-       const uint8_t *gpio_table = &bios->data[bios->dcb.gpio_table_ptr];
-       const uint8_t *gpio_entry;
        int i;
 
-       if (!iexec->execute)
-               return 1;
-
-       if (bios->dcb.version != 0x40) {
-               NV_ERROR(bios->dev, "DCB table not version 4.0\n");
-               return 0;
-       }
-
-       if (!bios->dcb.gpio_table_ptr) {
-               NV_WARN(bios->dev, "Invalid pointer to INIT_8E table\n");
-               return 0;
+       if (dev_priv->card_type != NV_50) {
+               NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
+               return -ENODEV;
        }
 
-       gpio_entry = gpio_table + gpio_table[1];
-       for (i = 0; i < gpio_table[2]; i++, gpio_entry += gpio_table[3]) {
-               uint32_t entry = ROM32(gpio_entry[0]), r, s, v;
-               int line = (entry & 0x0000001f);
+       if (!iexec->execute)
+               return 1;
 
-               BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, entry);
+       for (i = 0; i < bios->dcb.gpio.entries; i++) {
+               struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i];
+               uint32_t r, s, v;
 
-               if ((entry & 0x0000ff00) == 0x0000ff00)
-                       continue;
+               BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
 
-               r = nv50_gpio_reg[line >> 3];
-               s = (line & 0x07) << 2;
-               v = bios_rd32(bios, r) & ~(0x00000003 << s);
-               if (entry & 0x01000000)
-                       v |= (((entry & 0x60000000) >> 29) ^ 2) << s;
-               else
-                       v |= (((entry & 0x18000000) >> 27) ^ 2) << s;
-               bios_wr32(bios, r, v);
+               nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
 
-               r = nv50_gpio_ctl[line >> 4];
-               s = (line & 0x0f);
+               /* The NVIDIA binary driver doesn't appear to actually do
+                * any of this, my VBIOS does however.
+                */
+               /* Not a clue, needs de-magicing */
+               r = nv50_gpio_ctl[gpio->line >> 4];
+               s = (gpio->line & 0x0f);
                v = bios_rd32(bios, r) & ~(0x00010001 << s);
-               switch ((entry & 0x06000000) >> 25) {
+               switch ((gpio->entry & 0x06000000) >> 25) {
                case 1:
                        v |= (0x00000001 << s);
                        break;
@@ -3198,7 +3184,6 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
        struct nvbios *bios = &dev_priv->vbios;
        unsigned int outputset = (dcbent->or == 4) ? 1 : 0;
        uint16_t scriptptr = 0, clktable;
-       uint8_t clktableptr = 0;
 
        /*
         * For now we assume version 3.0 table - g80 support will need some
@@ -3217,26 +3202,29 @@ static int run_lvds_table(struct drm_device *dev, struct dcb_entry *dcbent, int
                scriptptr = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 11 + outputset * 2]);
                break;
        case LVDS_RESET:
+               clktable = bios->fp.lvdsmanufacturerpointer + 15;
+               if (dcbent->or == 4)
+                       clktable += 8;
+
                if (dcbent->lvdsconf.use_straps_for_mode) {
                        if (bios->fp.dual_link)
-                               clktableptr += 2;
-                       if (bios->fp.BITbit1)
-                               clktableptr++;
+                               clktable += 4;
+                       if (bios->fp.if_is_24bit)
+                               clktable += 2;
                } else {
                        /* using EDID */
-                       uint8_t fallback = bios->data[bios->fp.lvdsmanufacturerpointer + 4];
-                       int fallbackcmpval = (dcbent->or == 4) ? 4 : 1;
+                       int cmpval_24bit = (dcbent->or == 4) ? 4 : 1;
 
                        if (bios->fp.dual_link) {
-                               clktableptr += 2;
-                               fallbackcmpval *= 2;
+                               clktable += 4;
+                               cmpval_24bit <<= 1;
                        }
-                       if (fallbackcmpval & fallback)
-                               clktableptr++;
+
+                       if (bios->fp.strapless_is_24bit & cmpval_24bit)
+                               clktable += 2;
                }
 
-               /* adding outputset * 8 may not be correct */
-               clktable = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 15 + clktableptr * 2 + outputset * 8]);
+               clktable = ROM16(bios->data[clktable]);
                if (!clktable) {
                        NV_ERROR(dev, "Pixel clock comparison table not found\n");
                        return -ENOENT;
@@ -3638,37 +3626,40 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b
                *if_is_24bit = bios->data[lvdsofs] & 16;
                break;
        case 0x30:
-               /*
-                * My money would be on there being a 24 bit interface bit in
-                * this table, but I have no example of a laptop bios with a
-                * 24 bit panel to confirm that. Hence we shout loudly if any
-                * bit other than bit 0 is set (I've not even seen bit 1)
-                */
-               if (bios->data[lvdsofs] > 1)
-                       NV_ERROR(dev,
-                                "You have a very unusual laptop display; please report it\n");
+       case 0x40:
                /*
                 * No sign of the "power off for reset" or "reset for panel
                 * on" bits, but it's safer to assume we should
                 */
                bios->fp.power_off_for_reset = true;
                bios->fp.reset_after_pclk_change = true;
+
                /*
                 * It's ok lvdsofs is wrong for nv4x edid case; dual_link is
-                * over-written, and BITbit1 isn't used
+                * over-written, and if_is_24bit isn't used
                 */
                bios->fp.dual_link = bios->data[lvdsofs] & 1;
-               bios->fp.BITbit1 = bios->data[lvdsofs] & 2;
-               bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10;
-               break;
-       case 0x40:
-               bios->fp.dual_link = bios->data[lvdsofs] & 1;
                bios->fp.if_is_24bit = bios->data[lvdsofs] & 2;
                bios->fp.strapless_is_24bit = bios->data[bios->fp.lvdsmanufacturerpointer + 4];
                bios->fp.duallink_transition_clk = ROM16(bios->data[bios->fp.lvdsmanufacturerpointer + 5]) * 10;
                break;
        }
 
+       /* Dell Latitude D620 reports a too-high value for the dual-link
+        * transition freq, causing us to program the panel incorrectly.
+        *
+        * It doesn't appear the VBIOS actually uses its transition freq
+        * (90000kHz), instead it uses the "Number of LVDS channels" field
+        * out of the panel ID structure (http://www.spwg.org/).
+        *
+        * For the moment, a quirk will do :)
+        */
+       if ((dev->pdev->device == 0x01d7) &&
+           (dev->pdev->subsystem_vendor == 0x1028) &&
+           (dev->pdev->subsystem_device == 0x01c2)) {
+               bios->fp.duallink_transition_clk = 80000;
+       }
+
        /* set dual_link flag for EDID case */
        if (pxclk && (chip_version < 0x25 || chip_version > 0x28))
                bios->fp.dual_link = (pxclk >= bios->fp.duallink_transition_clk);
@@ -5077,25 +5068,25 @@ parse_dcb30_gpio_entry(struct nvbios *bios, uint16_t offset)
        gpio->tag = tag;
        gpio->line = line;
        gpio->invert = flags != 4;
+       gpio->entry = ent;
 }
 
 static void
 parse_dcb40_gpio_entry(struct nvbios *bios, uint16_t offset)
 {
+       uint32_t entry = ROM32(bios->data[offset]);
        struct dcb_gpio_entry *gpio;
-       uint32_t ent = ROM32(bios->data[offset]);
-       uint8_t line = ent & 0x1f,
-               tag = ent >> 8 & 0xff;
 
-       if (tag == 0xff)
+       if ((entry & 0x0000ff00) == 0x0000ff00)
                return;
 
        gpio = new_gpio_entry(bios);
-
-       /* Currently unused, we may need more fields parsed at some
-        * point. */
-       gpio->tag = tag;
-       gpio->line = line;
+       gpio->tag = (entry & 0x0000ff00) >> 8;
+       gpio->line = (entry & 0x0000001f) >> 0;
+       gpio->state_default = (entry & 0x01000000) >> 24;
+       gpio->state[0] = (entry & 0x18000000) >> 27;
+       gpio->state[1] = (entry & 0x60000000) >> 29;
+       gpio->entry = entry;
 }
 
 static void
index 4f88e6924d272846eff330a9a84307aa05fa3dc7..c0d7b0a3ece0a35929c3c0f07b7183136f0cd607 100644 (file)
@@ -49,6 +49,9 @@ struct dcb_gpio_entry {
        enum dcb_gpio_tag tag;
        int line;
        bool invert;
+       uint32_t entry;
+       uint8_t state_default;
+       uint8_t state[2];
 };
 
 struct dcb_gpio_table {
@@ -267,7 +270,6 @@ struct nvbios {
                bool reset_after_pclk_change;
                bool dual_link;
                bool link_c_increment;
-               bool BITbit1;
                bool if_is_24bit;
                int duallink_transition_clk;
                uint8_t strapless_is_24bit;
index 9042dd7fb05899ebb3a1673f2244aed40920846b..957d17629840254c1ccf5ad13139856cea232525 100644 (file)
@@ -72,7 +72,7 @@ nouveau_bo_fixup_align(struct drm_device *dev,
         * many small buffers.
         */
        if (dev_priv->card_type == NV_50) {
-               uint32_t block_size = nouveau_mem_fb_amount(dev) >> 15;
+               uint32_t block_size = dev_priv->vram_size >> 15;
                int i;
 
                switch (tile_flags) {
@@ -154,7 +154,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
 
        nvbo->placement.fpfn = 0;
        nvbo->placement.lpfn = mappable ? dev_priv->fb_mappable_pages : 0;
-       nouveau_bo_placement_set(nvbo, flags);
+       nouveau_bo_placement_set(nvbo, flags, 0);
 
        nvbo->channel = chan;
        ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
@@ -173,26 +173,33 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
        return 0;
 }
 
+static void
+set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
+{
+       *n = 0;
+
+       if (type & TTM_PL_FLAG_VRAM)
+               pl[(*n)++] = TTM_PL_FLAG_VRAM | flags;
+       if (type & TTM_PL_FLAG_TT)
+               pl[(*n)++] = TTM_PL_FLAG_TT | flags;
+       if (type & TTM_PL_FLAG_SYSTEM)
+               pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
+}
+
 void
-nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t memtype)
+nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
 {
-       int n = 0;
-
-       if (memtype & TTM_PL_FLAG_VRAM)
-               nvbo->placements[n++] = TTM_PL_FLAG_VRAM | TTM_PL_MASK_CACHING;
-       if (memtype & TTM_PL_FLAG_TT)
-               nvbo->placements[n++] = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
-       if (memtype & TTM_PL_FLAG_SYSTEM)
-               nvbo->placements[n++] = TTM_PL_FLAG_SYSTEM | TTM_PL_MASK_CACHING;
-       nvbo->placement.placement = nvbo->placements;
-       nvbo->placement.busy_placement = nvbo->placements;
-       nvbo->placement.num_placement = n;
-       nvbo->placement.num_busy_placement = n;
-
-       if (nvbo->pin_refcnt) {
-               while (n--)
-                       nvbo->placements[n] |= TTM_PL_FLAG_NO_EVICT;
-       }
+       struct ttm_placement *pl = &nvbo->placement;
+       uint32_t flags = TTM_PL_MASK_CACHING |
+               (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
+
+       pl->placement = nvbo->placements;
+       set_placement_list(nvbo->placements, &pl->num_placement,
+                          type, flags);
+
+       pl->busy_placement = nvbo->busy_placements;
+       set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
+                          type | busy, flags);
 }
 
 int
@@ -200,7 +207,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
-       int ret, i;
+       int ret;
 
        if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
                NV_ERROR(nouveau_bdev(bo->bdev)->dev,
@@ -216,9 +223,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
        if (ret)
                goto out;
 
-       nouveau_bo_placement_set(nvbo, memtype);
-       for (i = 0; i < nvbo->placement.num_placement; i++)
-               nvbo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+       nouveau_bo_placement_set(nvbo, memtype, 0);
 
        ret = ttm_bo_validate(bo, &nvbo->placement, false, false);
        if (ret == 0) {
@@ -245,7 +250,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
 {
        struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
-       int ret, i;
+       int ret;
 
        if (--nvbo->pin_refcnt)
                return 0;
@@ -254,8 +259,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
        if (ret)
                return ret;
 
-       for (i = 0; i < nvbo->placement.num_placement; i++)
-               nvbo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+       nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
 
        ret = ttm_bo_validate(bo, &nvbo->placement, false, false);
        if (ret == 0) {
@@ -396,8 +400,8 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->io_addr = NULL;
                man->io_offset = drm_get_resource_start(dev, 1);
                man->io_size = drm_get_resource_len(dev, 1);
-               if (man->io_size > nouveau_mem_fb_amount(dev))
-                       man->io_size = nouveau_mem_fb_amount(dev);
+               if (man->io_size > dev_priv->vram_size)
+                       man->io_size = dev_priv->vram_size;
 
                man->gpu_offset = dev_priv->vm_vram_base;
                break;
@@ -440,10 +444,11 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 
        switch (bo->mem.mem_type) {
        case TTM_PL_VRAM:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT);
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT,
+                                        TTM_PL_FLAG_SYSTEM);
                break;
        default:
-               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM);
+               nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0);
                break;
        }
 
index 6dfb425cbae9432f4718ae33c77b754c4ac9a8dc..1fc57ef58295091eef1e8ad979ad50b17c2fb9a4 100644 (file)
@@ -142,7 +142,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
                                           GFP_KERNEL);
        if (!dev_priv->fifos[channel])
                return -ENOMEM;
-       dev_priv->fifo_alloc_count++;
        chan = dev_priv->fifos[channel];
        INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
        INIT_LIST_HEAD(&chan->fence.pending);
@@ -321,7 +320,6 @@ nouveau_channel_free(struct nouveau_channel *chan)
                iounmap(chan->user);
 
        dev_priv->fifos[chan->id] = NULL;
-       dev_priv->fifo_alloc_count--;
        kfree(chan);
 }
 
index 8ff9ef5d4b47d1bd1df4287e0c4e109b4aaed52a..a251886a0ce66f8b2b7cdf1518d0fe12d7f30560 100644 (file)
@@ -137,10 +137,9 @@ nouveau_debugfs_memory_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_minor *minor = node->minor;
-       struct drm_device *dev = minor->dev;
+       struct drm_nouveau_private *dev_priv = minor->dev->dev_private;
 
-       seq_printf(m, "VRAM total: %dKiB\n",
-                  (int)(nouveau_mem_fb_amount(dev) >> 10));
+       seq_printf(m, "VRAM total: %dKiB\n", (int)(dev_priv->vram_size >> 10));
        return 0;
 }
 
index f954ad93e81f3f17ca5385591e7dca9ff6547a49..deeb21c6865c84d6f490e7bc5e82fa7acf5cfc99 100644 (file)
@@ -483,7 +483,7 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
        ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT);
        ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT);
 
-       for (;;) {
+       for (i = 0; i < 16; i++) {
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000);
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl);
                nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000);
@@ -502,6 +502,12 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
                        break;
        }
 
+       if (i == 16) {
+               NV_ERROR(dev, "auxch DEFER too many times, bailing\n");
+               ret = -EREMOTEIO;
+               goto out;
+       }
+
        if (cmd & 1) {
                if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
                        ret = -EREMOTEIO;
index d8b559011777a2094187d93a7dc836f80122ec16..ace630aa89e1c6b9755df63a1af28a61a6db6229 100644 (file)
@@ -76,6 +76,7 @@ struct nouveau_bo {
        struct ttm_buffer_object bo;
        struct ttm_placement placement;
        u32 placements[3];
+       u32 busy_placements[3];
        struct ttm_bo_kmap_obj kmap;
        struct list_head head;
 
@@ -519,6 +520,7 @@ struct drm_nouveau_private {
 
        struct workqueue_struct *wq;
        struct work_struct irq_work;
+       struct work_struct hpd_work;
 
        struct list_head vbl_waiting;
 
@@ -533,7 +535,6 @@ struct drm_nouveau_private {
 
        struct fb_info *fbdev_info;
 
-       int fifo_alloc_count;
        struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
 
        struct nouveau_engine engine;
@@ -553,12 +554,6 @@ struct drm_nouveau_private {
        uint32_t ramro_offset;
        uint32_t ramro_size;
 
-       /* base physical addresses */
-       uint64_t fb_phys;
-       uint64_t fb_available_size;
-       uint64_t fb_mappable_pages;
-       uint64_t fb_aper_free;
-
        struct {
                enum {
                        NOUVEAU_GART_NONE = 0,
@@ -572,10 +567,6 @@ struct drm_nouveau_private {
                struct nouveau_gpuobj *sg_ctxdma;
                struct page *sg_dummy_page;
                dma_addr_t sg_dummy_bus;
-
-               /* nottm hack */
-               struct drm_ttm_backend *sg_be;
-               unsigned long sg_handle;
        } gart_info;
 
        /* nv10-nv40 tiling regions */
@@ -584,6 +575,16 @@ struct drm_nouveau_private {
                spinlock_t lock;
        } tile;
 
+       /* VRAM/fb configuration */
+       uint64_t vram_size;
+       uint64_t vram_sys_base;
+
+       uint64_t fb_phys;
+       uint64_t fb_available_size;
+       uint64_t fb_mappable_pages;
+       uint64_t fb_aper_free;
+       int fb_mtrr;
+
        /* G8x/G9x virtual address space */
        uint64_t vm_gart_base;
        uint64_t vm_gart_size;
@@ -592,10 +593,6 @@ struct drm_nouveau_private {
        uint64_t vm_end;
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
-       uint64_t vram_sys_base;
-
-       /* the mtrr covering the FB */
-       int fb_mtrr;
 
        struct mem_block *ramin_heap;
 
@@ -614,11 +611,7 @@ struct drm_nouveau_private {
        uint32_t dac_users[4];
 
        struct nouveau_suspend_resume {
-               uint32_t fifo_mode;
-               uint32_t graph_ctx_control;
-               uint32_t graph_state;
                uint32_t *ramin_copy;
-               uint64_t ramin_size;
        } susres;
 
        struct backlight_device *backlight;
@@ -717,7 +710,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
                                                 struct drm_file *, int tail);
 extern void nouveau_mem_takedown(struct mem_block **heap);
 extern void nouveau_mem_free_block(struct mem_block *);
-extern uint64_t nouveau_mem_fb_amount(struct drm_device *);
+extern int  nouveau_mem_detect(struct drm_device *dev);
 extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
 extern int  nouveau_mem_init(struct drm_device *);
 extern int  nouveau_mem_init_agp(struct drm_device *);
@@ -1124,7 +1117,8 @@ extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
 extern int nouveau_bo_unpin(struct nouveau_bo *);
 extern int nouveau_bo_map(struct nouveau_bo *);
 extern void nouveau_bo_unmap(struct nouveau_bo *);
-extern void nouveau_bo_placement_set(struct nouveau_bo *, uint32_t memtype);
+extern void nouveau_bo_placement_set(struct nouveau_bo *, uint32_t type,
+                                    uint32_t busy);
 extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
 extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
 extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
@@ -1168,6 +1162,10 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
 int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
 int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
 
+/* nv50_gpio.c */
+int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
+int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
+
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
 #define ioread16_native ioread16be
index bc4a24029ed12a4ee5a59857975791a867699054..9f28b94e479bd1c7e7ba1f68bb59f29975559dbf 100644 (file)
@@ -47,6 +47,7 @@ struct nouveau_encoder {
 
        union {
                struct {
+                       int mc_unknown;
                        int dpcd_version;
                        int link_nr;
                        int link_bw;
index 0d22f66f1c795c1784cd3078c8e87f88dd4b8044..1bc0b38a5167d49f6c2a2a6a23fe385e07135c06 100644 (file)
@@ -180,40 +180,35 @@ nouveau_gem_set_domain(struct drm_gem_object *gem, uint32_t read_domains,
 {
        struct nouveau_bo *nvbo = gem->driver_private;
        struct ttm_buffer_object *bo = &nvbo->bo;
-       uint64_t flags;
+       uint32_t domains = valid_domains &
+               (write_domains ? write_domains : read_domains);
+       uint32_t pref_flags = 0, valid_flags = 0;
 
-       if (!valid_domains || (!read_domains && !write_domains))
+       if (!domains)
                return -EINVAL;
 
-       if (write_domains) {
-               if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
-                   (write_domains & NOUVEAU_GEM_DOMAIN_VRAM))
-                       flags = TTM_PL_FLAG_VRAM;
-               else
-               if ((valid_domains & NOUVEAU_GEM_DOMAIN_GART) &&
-                   (write_domains & NOUVEAU_GEM_DOMAIN_GART))
-                       flags = TTM_PL_FLAG_TT;
-               else
-                       return -EINVAL;
-       } else {
-               if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
-                   (read_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
-                   bo->mem.mem_type == TTM_PL_VRAM)
-                       flags = TTM_PL_FLAG_VRAM;
-               else
-               if ((valid_domains & NOUVEAU_GEM_DOMAIN_GART) &&
-                   (read_domains & NOUVEAU_GEM_DOMAIN_GART) &&
-                   bo->mem.mem_type == TTM_PL_TT)
-                       flags = TTM_PL_FLAG_TT;
-               else
-               if ((valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
-                   (read_domains & NOUVEAU_GEM_DOMAIN_VRAM))
-                       flags = TTM_PL_FLAG_VRAM;
-               else
-                       flags = TTM_PL_FLAG_TT;
-       }
+       if (valid_domains & NOUVEAU_GEM_DOMAIN_VRAM)
+               valid_flags |= TTM_PL_FLAG_VRAM;
+
+       if (valid_domains & NOUVEAU_GEM_DOMAIN_GART)
+               valid_flags |= TTM_PL_FLAG_TT;
+
+       if ((domains & NOUVEAU_GEM_DOMAIN_VRAM) &&
+           bo->mem.mem_type == TTM_PL_VRAM)
+               pref_flags |= TTM_PL_FLAG_VRAM;
+
+       else if ((domains & NOUVEAU_GEM_DOMAIN_GART) &&
+                bo->mem.mem_type == TTM_PL_TT)
+               pref_flags |= TTM_PL_FLAG_TT;
+
+       else if (domains & NOUVEAU_GEM_DOMAIN_VRAM)
+               pref_flags |= TTM_PL_FLAG_VRAM;
+
+       else
+               pref_flags |= TTM_PL_FLAG_TT;
+
+       nouveau_bo_placement_set(nvbo, pref_flags, valid_flags);
 
-       nouveau_bo_placement_set(nvbo, flags);
        return 0;
 }
 
index 2bd59a92fee50439ddd892c96f839f909af50bf2..13e73cee4c44d6fa2764f7ff3ff710148f545c3e 100644 (file)
@@ -51,6 +51,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
 
        if (dev_priv->card_type == NV_50) {
                INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
+               INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
                INIT_LIST_HEAD(&dev_priv->vbl_waiting);
        }
 }
index 2dc09dbd817d06d178343bf7280f7187115dd555..775a7017af6437da7c149dfda2a04d172704fdb2 100644 (file)
@@ -347,6 +347,20 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
                return -EBUSY;
        }
 
+       nv_wr32(dev, 0x100c80, 0x00040001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+               return -EBUSY;
+       }
+
+       nv_wr32(dev, 0x100c80, 0x00060001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+               return -EBUSY;
+       }
+
        return 0;
 }
 
@@ -384,6 +398,20 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
        }
 
        nv_wr32(dev, 0x100c80, 0x00000001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+               return;
+       }
+
+       nv_wr32(dev, 0x100c80, 0x00040001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+               return;
+       }
+
+       nv_wr32(dev, 0x100c80, 0x00060001);
        if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
                NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
                NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
@@ -449,9 +477,30 @@ void nouveau_mem_close(struct drm_device *dev)
        }
 }
 
-/*XXX won't work on BSD because of pci_read_config_dword */
 static uint32_t
-nouveau_mem_fb_amount_igp(struct drm_device *dev)
+nouveau_mem_detect_nv04(struct drm_device *dev)
+{
+       uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0);
+
+       if (boot0 & 0x00000100)
+               return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
+
+       switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
+       case NV04_BOOT_0_RAM_AMOUNT_32MB:
+               return 32 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_16MB:
+               return 16 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_8MB:
+               return 8 * 1024 * 1024;
+       case NV04_BOOT_0_RAM_AMOUNT_4MB:
+               return 4 * 1024 * 1024;
+       }
+
+       return 0;
+}
+
+static uint32_t
+nouveau_mem_detect_nforce(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct pci_dev *bridge;
@@ -463,11 +512,11 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev)
                return 0;
        }
 
-       if (dev_priv->flags&NV_NFORCE) {
+       if (dev_priv->flags & NV_NFORCE) {
                pci_read_config_dword(bridge, 0x7C, &mem);
                return (uint64_t)(((mem >> 6) & 31) + 1)*1024*1024;
        } else
-       if (dev_priv->flags&NV_NFORCE2) {
+       if (dev_priv->flags & NV_NFORCE2) {
                pci_read_config_dword(bridge, 0x84, &mem);
                return (uint64_t)(((mem >> 4) & 127) + 1)*1024*1024;
        }
@@ -477,50 +526,32 @@ nouveau_mem_fb_amount_igp(struct drm_device *dev)
 }
 
 /* returns the amount of FB ram in bytes */
-uint64_t nouveau_mem_fb_amount(struct drm_device *dev)
+int
+nouveau_mem_detect(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t boot0;
-
-       switch (dev_priv->card_type) {
-       case NV_04:
-               boot0 = nv_rd32(dev, NV03_BOOT_0);
-               if (boot0 & 0x00000100)
-                       return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
-
-               switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
-               case NV04_BOOT_0_RAM_AMOUNT_32MB:
-                       return 32 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_16MB:
-                       return 16 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_8MB:
-                       return 8 * 1024 * 1024;
-               case NV04_BOOT_0_RAM_AMOUNT_4MB:
-                       return 4 * 1024 * 1024;
-               }
-               break;
-       case NV_10:
-       case NV_20:
-       case NV_30:
-       case NV_40:
-       case NV_50:
-       default:
-               if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
-                       return nouveau_mem_fb_amount_igp(dev);
-               } else {
-                       uint64_t mem;
-                       mem = (nv_rd32(dev, NV04_FIFO_DATA) &
-                                       NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK) >>
-                                       NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT;
-                       return mem * 1024 * 1024;
-               }
-               break;
+
+       if (dev_priv->card_type == NV_04) {
+               dev_priv->vram_size = nouveau_mem_detect_nv04(dev);
+       } else
+       if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
+               dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
+       } else {
+               dev_priv->vram_size  = nv_rd32(dev, NV04_FIFO_DATA);
+               dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
+               if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
+                       dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
        }
 
-       NV_ERROR(dev,
-               "Unable to detect video ram size. Please report your setup to "
-                                                       DRIVER_EMAIL "\n");
-       return 0;
+       NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
+       if (dev_priv->vram_sys_base) {
+               NV_INFO(dev, "Stolen system memory at: 0x%010llx\n",
+                       dev_priv->vram_sys_base);
+       }
+
+       if (dev_priv->vram_size)
+               return 0;
+       return -ENOMEM;
 }
 
 #if __OS_HAS_AGP
@@ -631,15 +662,12 @@ nouveau_mem_init(struct drm_device *dev)
        spin_lock_init(&dev_priv->ttm.bo_list_lock);
        spin_lock_init(&dev_priv->tile.lock);
 
-       dev_priv->fb_available_size = nouveau_mem_fb_amount(dev);
-
+       dev_priv->fb_available_size = dev_priv->vram_size;
        dev_priv->fb_mappable_pages = dev_priv->fb_available_size;
        if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1))
                dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1);
        dev_priv->fb_mappable_pages >>= PAGE_SHIFT;
 
-       NV_INFO(dev, "%d MiB VRAM\n", (int)(dev_priv->fb_available_size >> 20));
-
        /* remove reserved space at end of vram from available amount */
        dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram;
        dev_priv->fb_aper_free = dev_priv->fb_available_size;
index 86785b8d42ed75a66b9ad01f04ab0a138d21f59d..1d6ee8b55154c95aa763ed278c31b14da32fa9a7 100644 (file)
@@ -172,6 +172,24 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
        }
        dev_priv->engine.instmem.finish_access(nvbe->dev);
 
+       if (dev_priv->card_type == NV_50) {
+               nv_wr32(dev, 0x100c80, 0x00050001);
+               if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+                       NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+                       NV_ERROR(dev, "0x100c80 = 0x%08x\n",
+                                               nv_rd32(dev, 0x100c80));
+                       return -EBUSY;
+               }
+
+               nv_wr32(dev, 0x100c80, 0x00000001);
+               if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+                       NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+                       NV_ERROR(dev, "0x100c80 = 0x%08x\n",
+                                               nv_rd32(dev, 0x100c80));
+                       return -EBUSY;
+               }
+       }
+
        nvbe->bound = false;
        return 0;
 }
index 10656a6be8e6aff3cac3bd93795176347a5bb2e8..e1710640a2786b6051a8f305eabf9951bd699b63 100644 (file)
@@ -341,7 +341,7 @@ nouveau_card_init_channel(struct drm_device *dev)
 
        gpuobj = NULL;
        ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY,
-                                    0, nouveau_mem_fb_amount(dev),
+                                    0, dev_priv->vram_size,
                                     NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM,
                                     &gpuobj);
        if (ret)
@@ -427,6 +427,10 @@ nouveau_card_init(struct drm_device *dev)
                        goto out;
        }
 
+       ret = nouveau_mem_detect(dev);
+       if (ret)
+               goto out_bios;
+
        ret = nouveau_gpuobj_early_init(dev);
        if (ret)
                goto out_bios;
@@ -502,7 +506,7 @@ nouveau_card_init(struct drm_device *dev)
                else
                        ret = nv04_display_create(dev);
                if (ret)
-                       goto out_irq;
+                       goto out_channel;
        }
 
        ret = nouveau_backlight_init(dev);
@@ -516,6 +520,11 @@ nouveau_card_init(struct drm_device *dev)
 
        return 0;
 
+out_channel:
+       if (dev_priv->channel) {
+               nouveau_channel_free(dev_priv->channel);
+               dev_priv->channel = NULL;
+       }
 out_irq:
        drm_irq_uninstall(dev);
 out_fifo:
@@ -533,6 +542,7 @@ out_mc:
 out_gpuobj:
        nouveau_gpuobj_takedown(dev);
 out_mem:
+       nouveau_sgdma_takedown(dev);
        nouveau_mem_close(dev);
 out_instmem:
        engine->instmem.takedown(dev);
index 6b2ef4a9fce17c135c17ebe410866ef8f60d4b30..500ccfd3a0b8c664b62cdc308ebaff0cc95d3042 100644 (file)
@@ -278,7 +278,7 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
        default:
                nv_wr32(dev, 0x2230, 0);
                nv_wr32(dev, NV40_PFIFO_RAMFC,
-                       ((nouveau_mem_fb_amount(dev) - 512 * 1024 +
+                       ((dev_priv->vram_size - 512 * 1024 +
                          dev_priv->ramfc_offset) >> 16) | (3 << 16));
                break;
        }
index 53e8afe1dcd1a0dc6fedf5fd9d819edc87e4b918..0616c96e4b67834f9de49511d85c93614e0bf9ea 100644 (file)
@@ -335,6 +335,27 @@ nv40_graph_init(struct drm_device *dev)
        nv_wr32(dev, 0x400b38, 0x2ffff800);
        nv_wr32(dev, 0x400b3c, 0x00006000);
 
+       /* Tiling related stuff. */
+       switch (dev_priv->chipset) {
+       case 0x44:
+       case 0x4a:
+               nv_wr32(dev, 0x400bc4, 0x1003d888);
+               nv_wr32(dev, 0x400bbc, 0xb7a7b500);
+               break;
+       case 0x46:
+               nv_wr32(dev, 0x400bc4, 0x0000e024);
+               nv_wr32(dev, 0x400bbc, 0xb7a7b520);
+               break;
+       case 0x4c:
+       case 0x4e:
+       case 0x67:
+               nv_wr32(dev, 0x400bc4, 0x1003d888);
+               nv_wr32(dev, 0x400bbc, 0xb7a7b540);
+               break;
+       default:
+               break;
+       }
+
        /* Turn all the tiling regions off. */
        for (i = 0; i < pfb->num_tiles; i++)
                nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
index fac6c88a2b1f1042b88720c853ba466fd7807c8b..649db4c1b690677689dbba5627781f9efc16ce8c 100644 (file)
@@ -143,7 +143,7 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
        }
 
        ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19,
-                                 0, nouveau_mem_fb_amount(dev));
+                                 0, dev_priv->vram_size);
        if (ret) {
                nv50_evo_channel_del(pchan);
                return ret;
@@ -231,7 +231,7 @@ nv50_display_init(struct drm_device *dev)
        /* This used to be in crtc unblank, but seems out of place there. */
        nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0);
        /* RAM is clamped to 256 MiB. */
-       ram_amount = nouveau_mem_fb_amount(dev);
+       ram_amount = dev_priv->vram_size;
        NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount);
        if (ram_amount > 256*1024*1024)
                ram_amount = 256*1024*1024;
@@ -529,8 +529,10 @@ int nv50_display_create(struct drm_device *dev)
        }
 
        ret = nv50_display_init(dev);
-       if (ret)
+       if (ret) {
+               nv50_display_destroy(dev);
                return ret;
+       }
 
        return 0;
 }
@@ -885,10 +887,12 @@ nv50_display_error_handler(struct drm_device *dev)
        nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000);
 }
 
-static void
-nv50_display_irq_hotplug(struct drm_device *dev)
+void
+nv50_display_irq_hotplug_bh(struct work_struct *work)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct drm_nouveau_private *dev_priv =
+               container_of(work, struct drm_nouveau_private, hpd_work);
+       struct drm_device *dev = dev_priv->dev;
        struct drm_connector *connector;
        const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
        uint32_t unplug_mask, plug_mask, change_mask;
@@ -949,8 +953,10 @@ nv50_display_irq_handler(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        uint32_t delayed = 0;
 
-       while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG)
-               nv50_display_irq_hotplug(dev);
+       if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
+               if (!work_pending(&dev_priv->hpd_work))
+                       queue_work(dev_priv->wq, &dev_priv->hpd_work);
+       }
 
        while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
                uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0);
index 3ae8d0725f635d8b41b0e797f5b1b30f4c7a79d5..581d405ac014606041e253c7830c137569e63af6 100644 (file)
@@ -37,6 +37,7 @@
 
 void nv50_display_irq_handler(struct drm_device *dev);
 void nv50_display_irq_handler_bh(struct work_struct *work);
+void nv50_display_irq_hotplug_bh(struct work_struct *work);
 int nv50_display_init(struct drm_device *dev);
 int nv50_display_create(struct drm_device *dev);
 int nv50_display_destroy(struct drm_device *dev);
index 25a3cd8794f919991ab0ed717e129557eafaad55..a8c70e7e9184d1a0170188641f97a00db7102ed0 100644 (file)
@@ -157,8 +157,11 @@ nv50_fbcon_accel_init(struct fb_info *info)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_channel *chan = dev_priv->channel;
        struct nouveau_gpuobj *eng2d = NULL;
+       uint64_t fb;
        int ret, format;
 
+       fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base;
+
        switch (info->var.bits_per_pixel) {
        case 8:
                format = 0xf3;
@@ -248,9 +251,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
        OUT_RING(chan, info->fix.line_length);
        OUT_RING(chan, info->var.xres_virtual);
        OUT_RING(chan, info->var.yres_virtual);
-       OUT_RING(chan, 0);
-       OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys +
-                        dev_priv->vm_vram_base);
+       OUT_RING(chan, upper_32_bits(fb));
+       OUT_RING(chan, lower_32_bits(fb));
        BEGIN_RING(chan, NvSub2D, 0x0230, 2);
        OUT_RING(chan, format);
        OUT_RING(chan, 1);
@@ -258,9 +260,8 @@ nv50_fbcon_accel_init(struct fb_info *info)
        OUT_RING(chan, info->fix.line_length);
        OUT_RING(chan, info->var.xres_virtual);
        OUT_RING(chan, info->var.yres_virtual);
-       OUT_RING(chan, 0);
-       OUT_RING(chan, info->fix.smem_start - dev_priv->fb_phys +
-                        dev_priv->vm_vram_base);
+       OUT_RING(chan, upper_32_bits(fb));
+       OUT_RING(chan, lower_32_bits(fb));
 
        return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c
new file mode 100644 (file)
index 0000000..c61782b
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_hw.h"
+
+static int
+nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift)
+{
+       const uint32_t nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
+
+       if (gpio->line > 32)
+               return -EINVAL;
+
+       *reg = nv50_gpio_reg[gpio->line >> 3];
+       *shift = (gpio->line & 7) << 2;
+       return 0;
+}
+
+int
+nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
+{
+       struct dcb_gpio_entry *gpio;
+       uint32_t r, s, v;
+
+       gpio = nouveau_bios_gpio_entry(dev, tag);
+       if (!gpio)
+               return -ENOENT;
+
+       if (nv50_gpio_location(gpio, &r, &s))
+               return -EINVAL;
+
+       v = nv_rd32(dev, r) >> (s + 2);
+       return ((v & 1) == (gpio->state[1] & 1));
+}
+
+int
+nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
+{
+       struct dcb_gpio_entry *gpio;
+       uint32_t r, s, v;
+
+       gpio = nouveau_bios_gpio_entry(dev, tag);
+       if (!gpio)
+               return -ENOENT;
+
+       if (nv50_gpio_location(gpio, &r, &s))
+               return -EINVAL;
+
+       v  = nv_rd32(dev, r) & ~(0x3 << s);
+       v |= (gpio->state[state] ^ 2) << s;
+       nv_wr32(dev, r, v);
+       return 0;
+}
index c62b33a02f889431fc6cde830138d16e3f0c6f40..b203d06f601f4ad9e314d4eadd21a25813cf8bce 100644 (file)
@@ -410,9 +410,10 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
        { 0x5039, false, NULL }, /* m2mf */
        { 0x502d, false, NULL }, /* 2d */
        { 0x50c0, false, NULL }, /* compute */
+       { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */
        { 0x5097, false, NULL }, /* tesla (nv50) */
-       { 0x8297, false, NULL }, /* tesla (nv80/nv90) */
-       { 0x8397, false, NULL }, /* tesla (nva0) */
-       { 0x8597, false, NULL }, /* tesla (nva8) */
+       { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */
+       { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */
+       { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
        {}
 };
index 546b31949a3079a8a8b4c82ab5d5534498437532..42a8fb20c1e6359d698107654b46ee015c7fb36a 100644 (file)
 #define CP_FLAG_AUTO_LOAD             ((2 * 32) + 5)
 #define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
 #define CP_FLAG_AUTO_LOAD_PENDING     1
+#define CP_FLAG_NEWCTX                ((2 * 32) + 10)
+#define CP_FLAG_NEWCTX_BUSY           0
+#define CP_FLAG_NEWCTX_DONE           1
 #define CP_FLAG_XFER                  ((2 * 32) + 11)
 #define CP_FLAG_XFER_IDLE             0
 #define CP_FLAG_XFER_BUSY             1
-#define CP_FLAG_NEWCTX                ((2 * 32) + 12)
-#define CP_FLAG_NEWCTX_BUSY           0
-#define CP_FLAG_NEWCTX_DONE           1
 #define CP_FLAG_ALWAYS                ((2 * 32) + 13)
 #define CP_FLAG_ALWAYS_FALSE          0
 #define CP_FLAG_ALWAYS_TRUE           1
@@ -177,6 +177,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
        case 0x96:
        case 0x98:
        case 0xa0:
+       case 0xa3:
        case 0xa5:
        case 0xa8:
        case 0xaa:
@@ -364,6 +365,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
        case 0xac:
                gr_def(ctx, 0x401c00, 0x042500df);
                break;
+       case 0xa3:
        case 0xa5:
        case 0xa8:
                gr_def(ctx, 0x401c00, 0x142500df);
@@ -418,6 +420,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                break;
        case 0x84:
        case 0xa0:
+       case 0xa3:
        case 0xa5:
        case 0xa8:
        case 0xaa:
@@ -792,6 +795,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                case 0xa5:
                                        gr_def(ctx, offset + 0x1c, 0x310c0000);
                                        break;
+                               case 0xa3:
                                case 0xa8:
                                case 0xaa:
                                case 0xac:
@@ -859,6 +863,8 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                        else
                                gr_def(ctx, offset + 0x8, 0x05010202);
                        gr_def(ctx, offset + 0xc, 0x00030201);
+                       if (dev_priv->chipset == 0xa3)
+                               cp_ctx(ctx, base + 0x36c, 1);
 
                        cp_ctx(ctx, base + 0x400, 2);
                        gr_def(ctx, base + 0x404, 0x00000040);
@@ -1159,7 +1165,9 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
                nv50_graph_construct_gene_unk8(ctx);
                if (dev_priv->chipset == 0xa0)
                        xf_emit(ctx, 0x189, 0);
-               else if (dev_priv->chipset < 0xa8)
+               else if (dev_priv->chipset == 0xa3)
+                       xf_emit(ctx, 0xd5, 0);
+               else if (dev_priv->chipset == 0xa5)
                        xf_emit(ctx, 0x99, 0);
                else if (dev_priv->chipset == 0xaa)
                        xf_emit(ctx, 0x65, 0);
@@ -1197,6 +1205,8 @@ nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
                ctx->ctxvals_pos = offset + 4;
                if (dev_priv->chipset == 0xa0)
                        xf_emit(ctx, 0xa80, 0);
+               else if (dev_priv->chipset == 0xa3)
+                       xf_emit(ctx, 0xa7c, 0);
                else
                        xf_emit(ctx, 0xa7a, 0);
                xf_emit(ctx, 1, 0x3fffff);
@@ -1341,6 +1351,7 @@ nv50_graph_construct_gene_unk1(struct nouveau_grctx *ctx)
                xf_emit(ctx, 0x942, 0);
                break;
        case 0xa0:
+       case 0xa3:
                xf_emit(ctx, 0x2042, 0);
                break;
        case 0xa5:
index de1f5b0062c551c3f9480aa0efeb326634f3f635..5f21df31f3aa7f69beac46ff65dc11885a5f02bd 100644 (file)
@@ -63,9 +63,10 @@ nv50_instmem_init(struct drm_device *dev)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_channel *chan;
        uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size;
+       uint32_t save_nv001700;
+       uint64_t v;
        struct nv50_instmem_priv *priv;
        int ret, i;
-       uint32_t v, save_nv001700;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -76,17 +77,12 @@ nv50_instmem_init(struct drm_device *dev)
        for (i = 0x1700; i <= 0x1710; i += 4)
                priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
 
-       if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
-               dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
-       else
-               dev_priv->vram_sys_base = 0;
-
        /* Reserve the last MiB of VRAM, we should probably try to avoid
         * setting up the below tables over the top of the VBIOS image at
         * some point.
         */
        dev_priv->ramin_rsvd_vram = 1 << 20;
-       c_offset = nouveau_mem_fb_amount(dev) - dev_priv->ramin_rsvd_vram;
+       c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
        c_size   = 128 << 10;
        c_vmpd   = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200;
        c_ramfc  = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20;
@@ -106,7 +102,7 @@ nv50_instmem_init(struct drm_device *dev)
        dev_priv->vm_gart_size = NV50_VM_BLOCK;
 
        dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size;
-       dev_priv->vm_vram_size = nouveau_mem_fb_amount(dev);
+       dev_priv->vm_vram_size = dev_priv->vram_size;
        if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM)
                dev_priv->vm_vram_size = NV50_VM_MAX_VRAM;
        dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK);
@@ -189,8 +185,8 @@ nv50_instmem_init(struct drm_device *dev)
 
        i = 0;
        while (v < dev_priv->vram_sys_base + c_offset + c_size) {
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v);
-               BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v));
+               BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v));
                v += 0x1000;
                i += 8;
        }
index c2fff543b06f4a1c5269e4fa8e7cfb4b69f475d2..0c68698f23df7d94b86e0a0a6ceb1a45c7b9bdae 100644 (file)
@@ -211,7 +211,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                        mode_ctl = 0x0200;
                break;
        case OUTPUT_DP:
-               mode_ctl |= 0x00050000;
+               mode_ctl |= (nv_encoder->dp.mc_unknown << 16);
                if (nv_encoder->dcb->sorconf.link & 1)
                        mode_ctl |= 0x00000800;
                else
@@ -274,6 +274,7 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
 int
 nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_encoder *nv_encoder = NULL;
        struct drm_encoder *encoder;
        bool dum;
@@ -319,5 +320,27 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
        encoder->possible_crtcs = entry->heads;
        encoder->possible_clones = 0;
 
+       if (nv_encoder->dcb->type == OUTPUT_DP) {
+               uint32_t mc, or = nv_encoder->or;
+
+               if (dev_priv->chipset < 0x90 ||
+                   dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
+                       mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
+               else
+                       mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
+
+               switch ((mc & 0x00000f00) >> 8) {
+               case 8:
+               case 9:
+                       nv_encoder->dp.mc_unknown = (mc & 0x000f0000) >> 16;
+                       break;
+               default:
+                       break;
+               }
+
+               if (!nv_encoder->dp.mc_unknown)
+                       nv_encoder->dp.mc_unknown = 5;
+       }
+
        return 0;
 }
index 07b7ebf1f466a3be426bf1bb3aabe68756973916..bcec2d79636e3d425ca9eca14e33d993ff32e484 100644 (file)
@@ -1137,6 +1137,7 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
        int len, ws, ps, ptr;
        unsigned char op;
        atom_exec_context ectx;
+       int ret = 0;
 
        if (!base)
                return -EINVAL;
@@ -1169,7 +1170,8 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
                if (ectx.abort) {
                        DRM_ERROR("atombios stuck executing %04X (len %d, WS %d, PS %d) @ 0x%04X\n",
                                base, len, ws, ps, ptr - 1);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto free;
                }
 
                if (op < ATOM_OP_CNT && op > 0)
@@ -1184,9 +1186,10 @@ static int atom_execute_table_locked(struct atom_context *ctx, int index, uint32
        debug_depth--;
        SDEBUG("<<\n");
 
+free:
        if (ws)
                kfree(ectx.ws);
-       return 0;
+       return ret;
 }
 
 int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
index 561048a7c0a4e876f2b5565593eee5785b9460b1..2b9affe754ce70fcffda57bb751e071be07b080a 100644 (file)
@@ -325,11 +325,12 @@ void r300_gpu_init(struct radeon_device *rdev)
 
        r100_hdp_reset(rdev);
        /* FIXME: rv380 one pipes ? */
-       if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) {
+       if ((rdev->family == CHIP_R300 && rdev->pdev->device != 0x4144) ||
+           (rdev->family == CHIP_R350)) {
                /* r300,r350 */
                rdev->num_gb_pipes = 2;
        } else {
-               /* rv350,rv370,rv380 */
+               /* rv350,rv370,rv380,r300 AD */
                rdev->num_gb_pipes = 1;
        }
        rdev->num_z_pipes = 1;
index 1fff95505cf5fec08f5506c47e26b8e00866632c..5673665ff216d9cf2f74f19ce51cd4897538b3e7 100644 (file)
@@ -69,16 +69,19 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
        struct radeon_i2c_bus_rec i2c;
        int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
        struct _ATOM_GPIO_I2C_INFO *i2c_info;
-       uint16_t data_offset;
-       int i;
+       uint16_t data_offset, size;
+       int i, num_indices;
 
        memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
        i2c.valid = false;
 
-       if (atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset)) {
+       if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
                i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
 
-               for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
+               num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
+                       sizeof(ATOM_GPIO_I2C_ASSIGMENT);
+
+               for (i = 0; i < num_indices; i++) {
                        gpio = &i2c_info->asGPIO_Info[i];
 
                        if (gpio->sucI2cId.ucAccess == id) {
index 2becdeda68a34ae4d94d8102f33d0d87fe6de959..37db8adb27481678b959f74f1f7432a177485ddb 100644 (file)
@@ -760,7 +760,9 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
                        dac = RBIOS8(dac_info + 0x3) & 0xf;
                        p_dac->ps2_pdac_adj = (bg << 8) | (dac);
                }
-               found = 1;
+               /* if the values are all zeros, use the table */
+               if (p_dac->ps2_pdac_adj)
+                       found = 1;
        }
 
        if (!found) /* fallback to defaults */
@@ -895,7 +897,9 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
                        bg = RBIOS8(dac_info + 0x10) & 0xf;
                        dac = RBIOS8(dac_info + 0x11) & 0xf;
                        tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
-                       found = 1;
+                       /* if the values are all zeros, use the table */
+                       if (tv_dac->ps2_tvdac_adj)
+                               found = 1;
                } else if (rev > 1) {
                        bg = RBIOS8(dac_info + 0xc) & 0xf;
                        dac = (RBIOS8(dac_info + 0xc) >> 4) & 0xf;
@@ -908,7 +912,9 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
                        bg = RBIOS8(dac_info + 0xe) & 0xf;
                        dac = (RBIOS8(dac_info + 0xe) >> 4) & 0xf;
                        tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
-                       found = 1;
+                       /* if the values are all zeros, use the table */
+                       if (tv_dac->ps2_tvdac_adj)
+                               found = 1;
                }
                tv_dac->tv_std = radeon_combios_get_tv_info(rdev);
        }
@@ -925,7 +931,9 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
                                    (bg << 16) | (dac << 20);
                                tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;
                                tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj;
-                               found = 1;
+                               /* if the values are all zeros, use the table */
+                               if (tv_dac->ps2_tvdac_adj)
+                                       found = 1;
                        } else {
                                bg = RBIOS8(dac_info + 0x4) & 0xf;
                                dac = RBIOS8(dac_info + 0x5) & 0xf;
@@ -933,7 +941,9 @@ struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
                                    (bg << 16) | (dac << 20);
                                tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;
                                tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj;
-                               found = 1;
+                               /* if the values are all zeros, use the table */
+                               if (tv_dac->ps2_tvdac_adj)
+                                       found = 1;
                        }
                } else {
                        DRM_INFO("No TV DAC info found in BIOS\n");
index 60d59816b94ff6a4d94784482d2d613a88c56543..3fba50540f72cf02b0f3bc1dd9de9c9e6201905b 100644 (file)
@@ -315,7 +315,7 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr
                radeon_encoder = to_radeon_encoder(encoder);
                if (!radeon_encoder->enc_priv)
                        return 0;
-               if (rdev->is_atom_bios) {
+               if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom) {
                        struct radeon_encoder_atom_dac *dac_int;
                        dac_int = radeon_encoder->enc_priv;
                        dac_int->tv_std = val;
index dc6eba6b96dd1f5476cd3f6bda470e0cda6b245b..419630dd207550cff62b69ecd12d86d101ad8687 100644 (file)
@@ -417,8 +417,9 @@ static int radeon_do_wait_for_idle(drm_radeon_private_t * dev_priv)
        return -EBUSY;
 }
 
-static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
+static void radeon_init_pipes(struct drm_device *dev)
 {
+       drm_radeon_private_t *dev_priv = dev->dev_private;
        uint32_t gb_tile_config, gb_pipe_sel = 0;
 
        if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV530) {
@@ -436,11 +437,12 @@ static void radeon_init_pipes(drm_radeon_private_t *dev_priv)
                dev_priv->num_gb_pipes = ((gb_pipe_sel >> 12) & 0x3) + 1;
        } else {
                /* R3xx */
-               if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300) ||
+               if (((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R300 &&
+                    dev->pdev->device != 0x4144) ||
                    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R350)) {
                        dev_priv->num_gb_pipes = 2;
                } else {
-                       /* R3Vxx */
+                       /* RV3xx/R300 AD */
                        dev_priv->num_gb_pipes = 1;
                }
        }
@@ -736,7 +738,7 @@ static int radeon_do_engine_reset(struct drm_device * dev)
 
        /* setup the raster pipes */
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R300)
-           radeon_init_pipes(dev_priv);
+           radeon_init_pipes(dev);
 
        /* Reset the CP ring */
        radeon_do_cp_reset(dev_priv);
index 52d6f96f274b2722ec0617cf5420ced519514442..c52fc3080b6775e8594d79ae8a41031c0152d8aa 100644 (file)
@@ -317,12 +317,8 @@ atombios_dac_setup(struct drm_encoder *encoder, int action)
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        DAC_ENCODER_CONTROL_PS_ALLOCATION args;
-       int index = 0, num = 0;
+       int index = 0;
        struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv;
-       enum radeon_tv_std tv_std = TV_STD_NTSC;
-
-       if (dac_info->tv_std)
-               tv_std = dac_info->tv_std;
 
        memset(&args, 0, sizeof(args));
 
@@ -330,12 +326,10 @@ atombios_dac_setup(struct drm_encoder *encoder, int action)
        case ENCODER_OBJECT_ID_INTERNAL_DAC1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
                index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
-               num = 1;
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC2:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
                index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
-               num = 2;
                break;
        }
 
@@ -346,7 +340,7 @@ atombios_dac_setup(struct drm_encoder *encoder, int action)
        else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
                args.ucDacStandard = ATOM_DAC1_CV;
        else {
-               switch (tv_std) {
+               switch (dac_info->tv_std) {
                case TV_STD_PAL:
                case TV_STD_PAL_M:
                case TV_STD_SCART_PAL:
@@ -377,10 +371,6 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
        TV_ENCODER_CONTROL_PS_ALLOCATION args;
        int index = 0;
        struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv;
-       enum radeon_tv_std tv_std = TV_STD_NTSC;
-
-       if (dac_info->tv_std)
-               tv_std = dac_info->tv_std;
 
        memset(&args, 0, sizeof(args));
 
@@ -391,7 +381,7 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
        if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
                args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
        else {
-               switch (tv_std) {
+               switch (dac_info->tv_std) {
                case TV_STD_NTSC:
                        args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
                        break;
@@ -1558,12 +1548,14 @@ static const struct drm_encoder_funcs radeon_atom_enc_funcs = {
 struct radeon_encoder_atom_dac *
 radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder)
 {
+       struct drm_device *dev = radeon_encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL);
 
        if (!dac)
                return NULL;
 
-       dac->tv_std = TV_STD_NTSC;
+       dac->tv_std = radeon_atombios_get_tv_info(rdev);
        return dac;
 }
 
@@ -1641,6 +1633,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC1:
                drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+               radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder);
                drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC2:
index cf389ce50a8a7ecb3db5a31a4829c45e690bbc20..2441cca7d775d899de9cf5f27481352aef2da30f 100644 (file)
@@ -830,8 +830,8 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
                                crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
 
                        if (rdev->family == CHIP_R420 ||
-                                       rdev->family == CHIP_R423 ||
-                                       rdev->family == CHIP_RV410)
+                           rdev->family == CHIP_R423 ||
+                           rdev->family == CHIP_RV410)
                                tv_dac_cntl |= (R420_TV_DAC_RDACPD |
                                                R420_TV_DAC_GDACPD |
                                                R420_TV_DAC_BDACPD |
@@ -907,35 +907,43 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
        if (rdev->family != CHIP_R200) {
                tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
                if (rdev->family == CHIP_R420 ||
-                               rdev->family == CHIP_R423 ||
-                               rdev->family == CHIP_RV410) {
+                   rdev->family == CHIP_R423 ||
+                   rdev->family == CHIP_RV410) {
                        tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
-                                       RADEON_TV_DAC_BGADJ_MASK |
-                                       R420_TV_DAC_DACADJ_MASK |
-                                       R420_TV_DAC_RDACPD |
-                                       R420_TV_DAC_GDACPD |
-                                       R420_TV_DAC_BDACPD |
-                                       R420_TV_DAC_TVENABLE);
+                                        RADEON_TV_DAC_BGADJ_MASK |
+                                        R420_TV_DAC_DACADJ_MASK |
+                                        R420_TV_DAC_RDACPD |
+                                        R420_TV_DAC_GDACPD |
+                                        R420_TV_DAC_BDACPD |
+                                        R420_TV_DAC_TVENABLE);
                } else {
                        tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
-                                       RADEON_TV_DAC_BGADJ_MASK |
-                                       RADEON_TV_DAC_DACADJ_MASK |
-                                       RADEON_TV_DAC_RDACPD |
-                                       RADEON_TV_DAC_GDACPD |
-                                       RADEON_TV_DAC_BDACPD);
+                                        RADEON_TV_DAC_BGADJ_MASK |
+                                        RADEON_TV_DAC_DACADJ_MASK |
+                                        RADEON_TV_DAC_RDACPD |
+                                        RADEON_TV_DAC_GDACPD |
+                                        RADEON_TV_DAC_BDACPD);
                }
 
-               /*  FIXME TV */
-               if (tv_dac) {
-                       struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
-                       tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
-                                       RADEON_TV_DAC_NHOLD |
-                                       RADEON_TV_DAC_STD_PS2 |
-                                       tv_dac->ps2_tvdac_adj);
+               tv_dac_cntl |= RADEON_TV_DAC_NBLANK | RADEON_TV_DAC_NHOLD;
+
+               if (is_tv) {
+                       if (tv_dac->tv_std == TV_STD_NTSC ||
+                           tv_dac->tv_std == TV_STD_NTSC_J ||
+                           tv_dac->tv_std == TV_STD_PAL_M ||
+                           tv_dac->tv_std == TV_STD_PAL_60)
+                               tv_dac_cntl |= tv_dac->ntsc_tvdac_adj;
+                       else
+                               tv_dac_cntl |= tv_dac->pal_tvdac_adj;
+
+                       if (tv_dac->tv_std == TV_STD_NTSC ||
+                           tv_dac->tv_std == TV_STD_NTSC_J)
+                               tv_dac_cntl |= RADEON_TV_DAC_STD_NTSC;
+                       else
+                               tv_dac_cntl |= RADEON_TV_DAC_STD_PAL;
                } else
-                       tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
-                                       RADEON_TV_DAC_NHOLD |
-                                       RADEON_TV_DAC_STD_PS2);
+                       tv_dac_cntl |= (RADEON_TV_DAC_STD_PS2 |
+                                       tv_dac->ps2_tvdac_adj);
 
                WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
        }
index 58c62ff42ab3953f98e27e230f236bb4cb98d99f..8b827f37b03ef95195be9736b9495cec6d390c5c 100644 (file)
@@ -2186,7 +2186,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
        blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
 
        gd->driverfs_dev = &sdp->sdev_gendev;
-       gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
+       gd->flags = GENHD_FL_EXT_DEVT;
        if (sdp->removable)
                gd->flags |= GENHD_FL_REMOVABLE;
 
index e1f922184b4506466e20978902fb114905549bcd..e7bf6ca64dcf028caec480f4ecb82b2ff32d2463 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -554,7 +554,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                                        .bi_rw = bio->bi_rw,
                                };
 
-                               if (q->merge_bvec_fn(q, &bvm, prev) < len) {
+                               if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) {
                                        prev->bv_len -= len;
                                        return 0;
                                }
@@ -607,7 +607,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                 * merge_bvec_fn() returns number of bytes it can accept
                 * at this offset
                 */
-               if (q->merge_bvec_fn(q, &bvm, bvec) < len) {
+               if (q->merge_bvec_fn(q, &bvm, bvec) < bvec->bv_len) {
                        bvec->bv_page = NULL;
                        bvec->bv_len = 0;
                        bvec->bv_offset = 0;
index 5183bc2a19167690d1b77fbcea0ec21b8518072f..ded66be6597c9d126fab1f75148222a09504c68d 100644 (file)
@@ -808,6 +808,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
        .release = cifs_close,
        .fsync = cifs_fsync,
        .flush = cifs_flush,
+       .mmap = cifs_file_mmap,
        .splice_read = generic_file_splice_read,
 #ifdef CONFIG_CIFS_POSIX
        .unlocked_ioctl  = cifs_ioctl,
index 3f4fbd670507dffd3eec9bd3c609ef4aff6429ca..5d3f29fef53228eec75dccac45b2d58697d57775 100644 (file)
@@ -1431,6 +1431,8 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        __u32 bytes_sent;
        __u16 byte_count;
 
+       *nbytes = 0;
+
        /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
        if (tcon->ses == NULL)
                return -ECONNABORTED;
@@ -1513,11 +1515,18 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        cifs_stats_inc(&tcon->num_writes);
        if (rc) {
                cFYI(1, ("Send error in write = %d", rc));
-               *nbytes = 0;
        } else {
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
+
+               /*
+                * Mask off high 16 bits when bytes written as returned by the
+                * server is greater than bytes requested by the client. Some
+                * OS/2 servers are known to set incorrect CountHigh values.
+                */
+               if (*nbytes > count)
+                       *nbytes &= 0xFFFF;
        }
 
        cifs_buf_release(pSMB);
@@ -1606,6 +1615,14 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
                *nbytes = le16_to_cpu(pSMBr->CountHigh);
                *nbytes = (*nbytes) << 16;
                *nbytes += le16_to_cpu(pSMBr->Count);
+
+               /*
+                * Mask off high 16 bits when bytes written as returned by the
+                * server is greater than bytes requested by the client. OS/2
+                * servers are known to set incorrect CountHigh values.
+                */
+               if (*nbytes > count)
+                       *nbytes &= 0xFFFF;
        }
 
 /*     cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
@@ -1794,8 +1811,21 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
                }
                parm_data = (struct cifs_posix_lock *)
                        ((char *)&pSMBr->hdr.Protocol + data_offset);
-               if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+               if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
                        pLockData->fl_type = F_UNLCK;
+               else {
+                       if (parm_data->lock_type ==
+                                       __constant_cpu_to_le16(CIFS_RDLCK))
+                               pLockData->fl_type = F_RDLCK;
+                       else if (parm_data->lock_type ==
+                                       __constant_cpu_to_le16(CIFS_WRLCK))
+                               pLockData->fl_type = F_WRLCK;
+
+                       pLockData->fl_start = parm_data->start;
+                       pLockData->fl_end = parm_data->start +
+                                               parm_data->length - 1;
+                       pLockData->fl_pid = parm_data->pid;
+               }
        }
 
 plk_err_exit:
index 058b390d3da8d02c758f33c6bccddcc7080344f2..9b11a8f56f3ab1dbf7b994bc109917ac3fbc6a44 100644 (file)
@@ -839,8 +839,32 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
                } else {
                        /* if rc == ERR_SHARING_VIOLATION ? */
-                       rc = 0; /* do not change lock type to unlock
-                                  since range in use */
+                       rc = 0;
+
+                       if (lockType & LOCKING_ANDX_SHARED_LOCK) {
+                               pfLock->fl_type = F_WRLCK;
+                       } else {
+                               rc = CIFSSMBLock(xid, tcon, netfid, length,
+                                       pfLock->fl_start, 0, 1,
+                                       lockType | LOCKING_ANDX_SHARED_LOCK,
+                                       0 /* wait flag */);
+                               if (rc == 0) {
+                                       rc = CIFSSMBLock(xid, tcon, netfid,
+                                               length, pfLock->fl_start, 1, 0,
+                                               lockType |
+                                               LOCKING_ANDX_SHARED_LOCK,
+                                               0 /* wait flag */);
+                                       pfLock->fl_type = F_RDLCK;
+                                       if (rc != 0)
+                                               cERROR(1, ("Error unlocking "
+                                               "previously locked range %d "
+                                               "during test of lock", rc));
+                                       rc = 0;
+                               } else {
+                                       pfLock->fl_type = F_WRLCK;
+                                       rc = 0;
+                               }
+                       }
                }
 
                FreeXid(xid);
index 781a322ccb456b926ff2906526645fd8dcd7cfec..4b37f7cea4dd28edac895ebbe9017d80e7031c16 100644 (file)
@@ -554,108 +554,85 @@ select_queue:
        return ret;
 }
 
-static void unpin_sb_for_writeback(struct super_block **psb)
+static void unpin_sb_for_writeback(struct super_block *sb)
 {
-       struct super_block *sb = *psb;
-
-       if (sb) {
-               up_read(&sb->s_umount);
-               put_super(sb);
-               *psb = NULL;
-       }
+       up_read(&sb->s_umount);
+       put_super(sb);
 }
 
+enum sb_pin_state {
+       SB_PINNED,
+       SB_NOT_PINNED,
+       SB_PIN_FAILED
+};
+
 /*
  * For WB_SYNC_NONE writeback, the caller does not have the sb pinned
  * before calling writeback. So make sure that we do pin it, so it doesn't
  * go away while we are writing inodes from it.
- *
- * Returns 0 if the super was successfully pinned (or pinning wasn't needed),
- * 1 if we failed.
  */
-static int pin_sb_for_writeback(struct writeback_control *wbc,
-                               struct inode *inode, struct super_block **psb)
+static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc,
+                                             struct super_block *sb)
 {
-       struct super_block *sb = inode->i_sb;
-
-       /*
-        * If this sb is already pinned, nothing more to do. If not and
-        * *psb is non-NULL, unpin the old one first
-        */
-       if (sb == *psb)
-               return 0;
-       else if (*psb)
-               unpin_sb_for_writeback(psb);
-
        /*
         * Caller must already hold the ref for this
         */
        if (wbc->sync_mode == WB_SYNC_ALL) {
                WARN_ON(!rwsem_is_locked(&sb->s_umount));
-               return 0;
+               return SB_NOT_PINNED;
        }
-
        spin_lock(&sb_lock);
        sb->s_count++;
        if (down_read_trylock(&sb->s_umount)) {
                if (sb->s_root) {
                        spin_unlock(&sb_lock);
-                       goto pinned;
+                       return SB_PINNED;
                }
                /*
                 * umounted, drop rwsem again and fall through to failure
                 */
                up_read(&sb->s_umount);
        }
-
        sb->s_count--;
        spin_unlock(&sb_lock);
-       return 1;
-pinned:
-       *psb = sb;
-       return 0;
+       return SB_PIN_FAILED;
 }
 
-static void writeback_inodes_wb(struct bdi_writeback *wb,
-                               struct writeback_control *wbc)
+/*
+ * Write a portion of b_io inodes which belong to @sb.
+ * If @wbc->sb != NULL, then find and write all such
+ * inodes. Otherwise write only ones which go sequentially
+ * in reverse order.
+ * Return 1, if the caller writeback routine should be
+ * interrupted. Otherwise return 0.
+ */
+static int writeback_sb_inodes(struct super_block *sb,
+                              struct bdi_writeback *wb,
+                              struct writeback_control *wbc)
 {
-       struct super_block *sb = wbc->sb, *pin_sb = NULL;
-       const unsigned long start = jiffies;    /* livelock avoidance */
-
-       spin_lock(&inode_lock);
-
-       if (!wbc->for_kupdate || list_empty(&wb->b_io))
-               queue_io(wb, wbc->older_than_this);
-
        while (!list_empty(&wb->b_io)) {
-               struct inode *inode = list_entry(wb->b_io.prev,
-                                               struct inode, i_list);
                long pages_skipped;
-
-               /*
-                * super block given and doesn't match, skip this inode
-                */
-               if (sb && sb != inode->i_sb) {
+               struct inode *inode = list_entry(wb->b_io.prev,
+                                                struct inode, i_list);
+               if (wbc->sb && sb != inode->i_sb) {
+                       /* super block given and doesn't
+                          match, skip this inode */
                        redirty_tail(inode);
                        continue;
                }
-
+               if (sb != inode->i_sb)
+                       /* finish with this superblock */
+                       return 0;
                if (inode->i_state & (I_NEW | I_WILL_FREE)) {
                        requeue_io(inode);
                        continue;
                }
-
                /*
                 * Was this inode dirtied after sync_sb_inodes was called?
                 * This keeps sync from extra jobs and livelock.
                 */
-               if (inode_dirtied_after(inode, start))
-                       break;
-
-               if (pin_sb_for_writeback(wbc, inode, &pin_sb)) {
-                       requeue_io(inode);
-                       continue;
-               }
+               if (inode_dirtied_after(inode, wbc->wb_start))
+                       return 1;
 
                BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
                __iget(inode);
@@ -674,14 +651,50 @@ static void writeback_inodes_wb(struct bdi_writeback *wb,
                spin_lock(&inode_lock);
                if (wbc->nr_to_write <= 0) {
                        wbc->more_io = 1;
-                       break;
+                       return 1;
                }
                if (!list_empty(&wb->b_more_io))
                        wbc->more_io = 1;
        }
+       /* b_io is empty */
+       return 1;
+}
+
+static void writeback_inodes_wb(struct bdi_writeback *wb,
+                               struct writeback_control *wbc)
+{
+       int ret = 0;
 
-       unpin_sb_for_writeback(&pin_sb);
+       wbc->wb_start = jiffies; /* livelock avoidance */
+       spin_lock(&inode_lock);
+       if (!wbc->for_kupdate || list_empty(&wb->b_io))
+               queue_io(wb, wbc->older_than_this);
+
+       while (!list_empty(&wb->b_io)) {
+               struct inode *inode = list_entry(wb->b_io.prev,
+                                                struct inode, i_list);
+               struct super_block *sb = inode->i_sb;
+               enum sb_pin_state state;
+
+               if (wbc->sb && sb != wbc->sb) {
+                       /* super block given and doesn't
+                          match, skip this inode */
+                       redirty_tail(inode);
+                       continue;
+               }
+               state = pin_sb_for_writeback(wbc, sb);
+
+               if (state == SB_PIN_FAILED) {
+                       requeue_io(inode);
+                       continue;
+               }
+               ret = writeback_sb_inodes(sb, wb, wbc);
 
+               if (state == SB_PINNED)
+                       unpin_sb_for_writeback(sb);
+               if (ret)
+                       break;
+       }
        spin_unlock(&inode_lock);
        /* Leave any unwritten inodes on b_io */
 }
index ebd22dbed861da16481a1f4995dd9460f71caca4..6690e8bae7bb5946396577fcc12a9c85836cb7b5 100644 (file)
@@ -158,7 +158,6 @@ enum rq_flag_bits {
 struct request {
        struct list_head queuelist;
        struct call_single_data csd;
-       int cpu;
 
        struct request_queue *q;
 
@@ -166,9 +165,11 @@ struct request {
        enum rq_cmd_type_bits cmd_type;
        unsigned long atomic_flags;
 
+       int cpu;
+
        /* the following two fields are internal, NEVER access directly */
-       sector_t __sector;              /* sector cursor */
        unsigned int __data_len;        /* total data len */
+       sector_t __sector;              /* sector cursor */
 
        struct bio *bio;
        struct bio *biotail;
@@ -201,20 +202,20 @@ struct request {
 
        unsigned short ioprio;
 
+       int ref_count;
+
        void *special;          /* opaque pointer available for LLD use */
        char *buffer;           /* kaddr of the current segment if available */
 
        int tag;
        int errors;
 
-       int ref_count;
-
        /*
         * when request is used as a packet command carrier
         */
-       unsigned short cmd_len;
        unsigned char __cmd[BLK_MAX_CDB];
        unsigned char *cmd;
+       unsigned short cmd_len;
 
        unsigned int extra_len; /* length of alignment and padding */
        unsigned int sense_len;
@@ -921,26 +922,7 @@ extern void blk_cleanup_queue(struct request_queue *);
 extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
 extern void blk_queue_bounce_limit(struct request_queue *, u64);
 extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
-
-/* Temporary compatibility wrapper */
-static inline void blk_queue_max_sectors(struct request_queue *q, unsigned int max)
-{
-       blk_queue_max_hw_sectors(q, max);
-}
-
 extern void blk_queue_max_segments(struct request_queue *, unsigned short);
-
-static inline void blk_queue_max_phys_segments(struct request_queue *q, unsigned short max)
-{
-       blk_queue_max_segments(q, max);
-}
-
-static inline void blk_queue_max_hw_segments(struct request_queue *q, unsigned short max)
-{
-       blk_queue_max_segments(q, max);
-}
-
-
 extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
 extern void blk_queue_max_discard_sectors(struct request_queue *q,
                unsigned int max_discard_sectors);
@@ -1030,11 +1012,6 @@ static inline int sb_issue_discard(struct super_block *sb,
 
 extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm);
 
-#define MAX_PHYS_SEGMENTS 128
-#define MAX_HW_SEGMENTS 128
-#define SAFE_MAX_SECTORS 255
-#define MAX_SEGMENT_SIZE       65536
-
 enum blk_default_limits {
        BLK_MAX_SEGMENTS        = 128,
        BLK_SAFE_MAX_SECTORS    = 255,
index 78962272338a757b1eb17b2cb167b30e1090b3ed..4341b1a97a344d63d06dace3555ecee71eb59a53 100644 (file)
@@ -56,7 +56,7 @@ extern const char *drbd_buildtag(void);
 #define REL_VERSION "8.3.7"
 #define API_VERSION 88
 #define PRO_VERSION_MIN 86
-#define PRO_VERSION_MAX 91
+#define PRO_VERSION_MAX 92
 
 
 enum drbd_io_error_p {
index a4d82f8959942be17b948f06af29ceb07e58f5d1..f7431a4ca6082b20637b4e01e7dc96d8ffdef984 100644 (file)
@@ -12,7 +12,7 @@
 #endif
 
 NL_PACKET(primary, 1,
-       NL_BIT(         1,      T_MAY_IGNORE,   overwrite_peer)
+       NL_BIT(         1,      T_MAY_IGNORE,   primary_force)
 )
 
 NL_PACKET(secondary, 2, )
@@ -63,6 +63,7 @@ NL_PACKET(net_conf, 5,
        NL_BIT(         41,     T_MAY_IGNORE,   always_asbp)
        NL_BIT(         61,     T_MAY_IGNORE,   no_cork)
        NL_BIT(         62,     T_MANDATORY,    auto_sndbuf_size)
+       NL_BIT(         70,     T_MANDATORY,    dry_run)
 )
 
 NL_PACKET(disconnect, 6, )
index 56b50514ab2582a9ee288f68cfe630ccd846121a..5f2f4c4d8fb0594720bfc1643cec75fbf12aaa36 100644 (file)
@@ -109,7 +109,7 @@ struct hd_struct {
 };
 
 #define GENHD_FL_REMOVABLE                     1
-#define GENHD_FL_DRIVERFS                      2
+/* 2 is unused */
 #define GENHD_FL_MEDIA_CHANGE_NOTIFY           4
 #define GENHD_FL_CD                            8
 #define GENHD_FL_UP                            16
index 87018dc5527dac26d9baf1eefd000b56f74509ff..9e7a12d6385d73f4115bc7528aa30926bdc2005b 100644 (file)
@@ -782,7 +782,6 @@ extern int i2o_exec_lct_get(struct i2o_controller *);
 #define to_i2o_driver(drv) container_of(drv,struct i2o_driver, driver)
 #define to_i2o_device(dev) container_of(dev, struct i2o_device, device)
 #define to_i2o_controller(dev) container_of(dev, struct i2o_controller, device)
-#define kobj_to_i2o_device(kobj) to_i2o_device(container_of(kobj, struct device, kobj))
 
 /**
  *     i2o_out_to_virt - Turn an I2O message to a virtual address
diff --git a/include/linux/lcm.h b/include/linux/lcm.h
new file mode 100644 (file)
index 0000000..7bf01d7
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LCM_H
+#define _LCM_H
+
+#include <linux/compiler.h>
+
+unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__;
+
+#endif /* _LCM_H */
index c5da7491809655fde7650c0ba65753988b41c4ab..55ca73cf25e5c850217d4dc626e551a2ff0ac0d4 100644 (file)
@@ -121,6 +121,13 @@ do {                                                                       \
  * (Note, rcu_assign_pointer and rcu_dereference are not needed to control
  * access to data items when inserting into or looking up from the radix tree)
  *
+ * Note that the value returned by radix_tree_tag_get() may not be relied upon
+ * if only the RCU read lock is held.  Functions to set/clear tags and to
+ * delete nodes running concurrently with it may affect its result such that
+ * two consecutive reads in the same locked section may return different
+ * values.  If reliability is required, modification functions must also be
+ * excluded from concurrency.
+ *
  * radix_tree_tagged is able to be called without locking or RCU.
  */
 
index 488446289cab4839670d8ff507d1cfb508d2fc98..49d1247cd6d904b1bc8cfc38a2193bd179855c35 100644 (file)
@@ -106,6 +106,7 @@ int kmem_cache_shrink(struct kmem_cache *);
 void kmem_cache_free(struct kmem_cache *, void *);
 unsigned int kmem_cache_size(struct kmem_cache *);
 const char *kmem_cache_name(struct kmem_cache *);
+int kern_ptr_validate(const void *ptr, unsigned long size);
 int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
 
 /*
index 76e8903cd204d4b2a21a8577a00150532c3dc24f..36520ded3e062701866a5a4941e1cc0a85d19b37 100644 (file)
@@ -34,6 +34,9 @@ struct writeback_control {
        enum writeback_sync_modes sync_mode;
        unsigned long *older_than_this; /* If !NULL, only write back inodes
                                           older than this */
+       unsigned long wb_start;         /* Time writeback_inodes_wb was
+                                          called. This is needed to avoid
+                                          extra jobs and livelock */
        long nr_to_write;               /* Write this many pages, and decrement
                                           this for each page written */
        long pages_skipped;             /* Pages which were not written */
index 5fb72733331e4e8a16d0144ad97097b174de80a8..d870a918559cde9ef478f3d8935c6361309fc6bb 100644 (file)
@@ -40,6 +40,16 @@ DECLARE_EVENT_CLASS(block_rq_with_error,
                  __entry->nr_sector, __entry->errors)
 );
 
+/**
+ * block_rq_abort - abort block operation request
+ * @q: queue containing the block operation request
+ * @rq: block IO operation request
+ *
+ * Called immediately after pending block IO operation request @rq in
+ * queue @q is aborted. The fields in the operation request @rq
+ * can be examined to determine which device and sectors the pending
+ * operation would access.
+ */
 DEFINE_EVENT(block_rq_with_error, block_rq_abort,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -47,6 +57,15 @@ DEFINE_EVENT(block_rq_with_error, block_rq_abort,
        TP_ARGS(q, rq)
 );
 
+/**
+ * block_rq_requeue - place block IO request back on a queue
+ * @q: queue holding operation
+ * @rq: block IO operation request
+ *
+ * The block operation request @rq is being placed back into queue
+ * @q.  For some reason the request was not completed and needs to be
+ * put back in the queue.
+ */
 DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -54,6 +73,17 @@ DEFINE_EVENT(block_rq_with_error, block_rq_requeue,
        TP_ARGS(q, rq)
 );
 
+/**
+ * block_rq_complete - block IO operation completed by device driver
+ * @q: queue containing the block operation request
+ * @rq: block operations request
+ *
+ * The block_rq_complete tracepoint event indicates that some portion
+ * of operation request has been completed by the device driver.  If
+ * the @rq->bio is %NULL, then there is absolutely no additional work to
+ * do for the request. If @rq->bio is non-NULL then there is
+ * additional work required to complete the request.
+ */
 DEFINE_EVENT(block_rq_with_error, block_rq_complete,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -95,6 +125,16 @@ DECLARE_EVENT_CLASS(block_rq,
                  __entry->nr_sector, __entry->comm)
 );
 
+/**
+ * block_rq_insert - insert block operation request into queue
+ * @q: target queue
+ * @rq: block IO operation request
+ *
+ * Called immediately before block operation request @rq is inserted
+ * into queue @q.  The fields in the operation request @rq struct can
+ * be examined to determine which device and sectors the pending
+ * operation would access.
+ */
 DEFINE_EVENT(block_rq, block_rq_insert,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -102,6 +142,14 @@ DEFINE_EVENT(block_rq, block_rq_insert,
        TP_ARGS(q, rq)
 );
 
+/**
+ * block_rq_issue - issue pending block IO request operation to device driver
+ * @q: queue holding operation
+ * @rq: block IO operation operation request
+ *
+ * Called when block operation request @rq from queue @q is sent to a
+ * device driver for processing.
+ */
 DEFINE_EVENT(block_rq, block_rq_issue,
 
        TP_PROTO(struct request_queue *q, struct request *rq),
@@ -109,6 +157,17 @@ DEFINE_EVENT(block_rq, block_rq_issue,
        TP_ARGS(q, rq)
 );
 
+/**
+ * block_bio_bounce - used bounce buffer when processing block operation
+ * @q: queue holding the block operation
+ * @bio: block operation
+ *
+ * A bounce buffer was used to handle the block operation @bio in @q.
+ * This occurs when hardware limitations prevent a direct transfer of
+ * data between the @bio data memory area and the IO device.  Use of a
+ * bounce buffer requires extra copying of data and decreases
+ * performance.
+ */
 TRACE_EVENT(block_bio_bounce,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
@@ -138,6 +197,14 @@ TRACE_EVENT(block_bio_bounce,
                  __entry->nr_sector, __entry->comm)
 );
 
+/**
+ * block_bio_complete - completed all work on the block operation
+ * @q: queue holding the block operation
+ * @bio: block operation completed
+ *
+ * This tracepoint indicates there is no further work to do on this
+ * block IO operation @bio.
+ */
 TRACE_EVENT(block_bio_complete,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
@@ -193,6 +260,14 @@ DECLARE_EVENT_CLASS(block_bio,
                  __entry->nr_sector, __entry->comm)
 );
 
+/**
+ * block_bio_backmerge - merging block operation to the end of an existing operation
+ * @q: queue holding operation
+ * @bio: new block operation to merge
+ *
+ * Merging block request @bio to the end of an existing block request
+ * in queue @q.
+ */
 DEFINE_EVENT(block_bio, block_bio_backmerge,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
@@ -200,6 +275,14 @@ DEFINE_EVENT(block_bio, block_bio_backmerge,
        TP_ARGS(q, bio)
 );
 
+/**
+ * block_bio_frontmerge - merging block operation to the beginning of an existing operation
+ * @q: queue holding operation
+ * @bio: new block operation to merge
+ *
+ * Merging block IO operation @bio to the beginning of an existing block
+ * operation in queue @q.
+ */
 DEFINE_EVENT(block_bio, block_bio_frontmerge,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
@@ -207,6 +290,13 @@ DEFINE_EVENT(block_bio, block_bio_frontmerge,
        TP_ARGS(q, bio)
 );
 
+/**
+ * block_bio_queue - putting new block IO operation in queue
+ * @q: queue holding operation
+ * @bio: new block operation
+ *
+ * About to place the block IO operation @bio into queue @q.
+ */
 DEFINE_EVENT(block_bio, block_bio_queue,
 
        TP_PROTO(struct request_queue *q, struct bio *bio),
@@ -243,6 +333,15 @@ DECLARE_EVENT_CLASS(block_get_rq,
                  __entry->nr_sector, __entry->comm)
 );
 
+/**
+ * block_getrq - get a free request entry in queue for block IO operations
+ * @q: queue for operations
+ * @bio: pending block IO operation
+ * @rw: low bit indicates a read (%0) or a write (%1)
+ *
+ * A request struct for queue @q has been allocated to handle the
+ * block IO operation @bio.
+ */
 DEFINE_EVENT(block_get_rq, block_getrq,
 
        TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
@@ -250,6 +349,17 @@ DEFINE_EVENT(block_get_rq, block_getrq,
        TP_ARGS(q, bio, rw)
 );
 
+/**
+ * block_sleeprq - waiting to get a free request entry in queue for block IO operation
+ * @q: queue for operation
+ * @bio: pending block IO operation
+ * @rw: low bit indicates a read (%0) or a write (%1)
+ *
+ * In the case where a request struct cannot be provided for queue @q
+ * the process needs to wait for an request struct to become
+ * available.  This tracepoint event is generated each time the
+ * process goes to sleep waiting for request struct become available.
+ */
 DEFINE_EVENT(block_get_rq, block_sleeprq,
 
        TP_PROTO(struct request_queue *q, struct bio *bio, int rw),
@@ -257,6 +367,14 @@ DEFINE_EVENT(block_get_rq, block_sleeprq,
        TP_ARGS(q, bio, rw)
 );
 
+/**
+ * block_plug - keep operations requests in request queue
+ * @q: request queue to plug
+ *
+ * Plug the request queue @q.  Do not allow block operation requests
+ * to be sent to the device driver. Instead, accumulate requests in
+ * the queue to improve throughput performance of the block device.
+ */
 TRACE_EVENT(block_plug,
 
        TP_PROTO(struct request_queue *q),
@@ -293,6 +411,13 @@ DECLARE_EVENT_CLASS(block_unplug,
        TP_printk("[%s] %d", __entry->comm, __entry->nr_rq)
 );
 
+/**
+ * block_unplug_timer - timed release of operations requests in queue to device driver
+ * @q: request queue to unplug
+ *
+ * Unplug the request queue @q because a timer expired and allow block
+ * operation requests to be sent to the device driver.
+ */
 DEFINE_EVENT(block_unplug, block_unplug_timer,
 
        TP_PROTO(struct request_queue *q),
@@ -300,6 +425,13 @@ DEFINE_EVENT(block_unplug, block_unplug_timer,
        TP_ARGS(q)
 );
 
+/**
+ * block_unplug_io - release of operations requests in request queue
+ * @q: request queue to unplug
+ *
+ * Unplug request queue @q because device driver is scheduled to work
+ * on elements in the request queue.
+ */
 DEFINE_EVENT(block_unplug, block_unplug_io,
 
        TP_PROTO(struct request_queue *q),
@@ -307,6 +439,17 @@ DEFINE_EVENT(block_unplug, block_unplug_io,
        TP_ARGS(q)
 );
 
+/**
+ * block_split - split a single bio struct into two bio structs
+ * @q: queue containing the bio
+ * @bio: block operation being split
+ * @new_sector: The starting sector for the new bio
+ *
+ * The bio request @bio in request queue @q needs to be split into two
+ * bio requests. The newly created @bio request starts at
+ * @new_sector. This split may be required due to hardware limitation
+ * such as operation crossing device boundaries in a RAID system.
+ */
 TRACE_EVENT(block_split,
 
        TP_PROTO(struct request_queue *q, struct bio *bio,
@@ -337,6 +480,16 @@ TRACE_EVENT(block_split,
                  __entry->comm)
 );
 
+/**
+ * block_remap - map request for a partition to the raw device
+ * @q: queue holding the operation
+ * @bio: revised operation
+ * @dev: device for the operation
+ * @from: original sector for the operation
+ *
+ * An operation for a partition on a block device has been mapped to the
+ * raw block device.
+ */
 TRACE_EVENT(block_remap,
 
        TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev,
@@ -370,6 +523,17 @@ TRACE_EVENT(block_remap,
                  (unsigned long long)__entry->old_sector)
 );
 
+/**
+ * block_rq_remap - map request for a block operation request
+ * @q: queue holding the operation
+ * @rq: block IO operation request
+ * @dev: device for the operation
+ * @from: original sector for the operation
+ *
+ * The block operation request @rq in @q has been remapped.  The block
+ * operation request @rq holds the current information and @from hold
+ * the original sector.
+ */
 TRACE_EVENT(block_rq_remap,
 
        TP_PROTO(struct request_queue *q, struct request *rq, dev_t dev,
index 2e152aed71980852a4a682a6e98082a01d7048be..0d4015205c642a844ba3a417a7b05a8f530bf014 100644 (file)
@@ -21,7 +21,7 @@ lib-y += kobject.o kref.o klist.o
 
 obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
         bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
-        string_helpers.o gcd.o list_sort.o
+        string_helpers.o gcd.o lcm.o list_sort.o
 
 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
 CFLAGS_kobject.o += -DDEBUG
diff --git a/lib/lcm.c b/lib/lcm.c
new file mode 100644 (file)
index 0000000..157cd88
--- /dev/null
+++ b/lib/lcm.c
@@ -0,0 +1,15 @@
+#include <linux/kernel.h>
+#include <linux/gcd.h>
+#include <linux/module.h>
+
+/* Lowest common multiple */
+unsigned long lcm(unsigned long a, unsigned long b)
+{
+       if (a && b)
+               return (a * b) / gcd(a, b);
+       else if (b)
+               return b;
+
+       return a;
+}
+EXPORT_SYMBOL_GPL(lcm);
index 0871582aa29de45fa8ff6f372cd8e8622c3fcc46..2a087e0f98633cf00724ef0ef7b411d9f60b609e 100644 (file)
@@ -555,6 +555,10 @@ EXPORT_SYMBOL(radix_tree_tag_clear);
  *
  *  0: tag not present or not set
  *  1: tag set
+ *
+ * Note that the return value of this function may not be relied on, even if
+ * the RCU lock is held, unless tag modification and node deletion are excluded
+ * from concurrency.
  */
 int radix_tree_tag_get(struct radix_tree_root *root,
                        unsigned long index, unsigned int tag)
@@ -595,12 +599,8 @@ int radix_tree_tag_get(struct radix_tree_root *root,
                 */
                if (!tag_get(node, tag, offset))
                        saw_unset_tag = 1;
-               if (height == 1) {
-                       int ret = tag_get(node, tag, offset);
-
-                       BUG_ON(ret && saw_unset_tag);
-                       return !!ret;
-               }
+               if (height == 1)
+                       return !!tag_get(node, tag, offset);
                node = rcu_dereference_raw(node->slots[offset]);
                shift -= RADIX_TREE_MAP_SHIFT;
                height--;
index 0e8ca0347707b62d9cfb35a3fb353f2bf6f79e6a..f13e067e1467dcbd6cae04f92b7701f814758e03 100644 (file)
@@ -227,6 +227,9 @@ static struct device_attribute bdi_dev_attrs[] = {
 static __init int bdi_class_init(void)
 {
        bdi_class = class_create(THIS_MODULE, "bdi");
+       if (IS_ERR(bdi_class))
+               return PTR_ERR(bdi_class);
+
        bdi_class->dev_attrs = bdi_dev_attrs;
        bdi_debug_init();
        return 0;
index a9f325b28bed145a4aab6ff8414b074d3b233280..bac0f4fcc216548fae98d352b0787cf509c0f262 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3602,21 +3602,10 @@ EXPORT_SYMBOL(kmem_cache_alloc_notrace);
  */
 int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr)
 {
-       unsigned long addr = (unsigned long)ptr;
-       unsigned long min_addr = PAGE_OFFSET;
-       unsigned long align_mask = BYTES_PER_WORD - 1;
        unsigned long size = cachep->buffer_size;
        struct page *page;
 
-       if (unlikely(addr < min_addr))
-               goto out;
-       if (unlikely(addr > (unsigned long)high_memory - size))
-               goto out;
-       if (unlikely(addr & align_mask))
-               goto out;
-       if (unlikely(!kern_addr_valid(addr)))
-               goto out;
-       if (unlikely(!kern_addr_valid(addr + size - 1)))
+       if (unlikely(!kern_ptr_validate(ptr, size)))
                goto out;
        page = virt_to_page(ptr);
        if (unlikely(!PageSlab(page)))
index b364844a1068be41e1419fa02746060af67e92bb..7d6c8b1ccf63afda07c374ff9d4b933f44dbed12 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2386,6 +2386,9 @@ int kmem_ptr_validate(struct kmem_cache *s, const void *object)
 {
        struct page *page;
 
+       if (!kern_ptr_validate(object, s->size))
+               return 0;
+
        page = get_object_page(object);
 
        if (!page || s != page->slab)
index 834db7be240f3e10769166396fdec9b2620eeb82..f5712e8964be8a8da2c521361dee71c123689428 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -186,6 +186,27 @@ void kzfree(const void *p)
 }
 EXPORT_SYMBOL(kzfree);
 
+int kern_ptr_validate(const void *ptr, unsigned long size)
+{
+       unsigned long addr = (unsigned long)ptr;
+       unsigned long min_addr = PAGE_OFFSET;
+       unsigned long align_mask = sizeof(void *) - 1;
+
+       if (unlikely(addr < min_addr))
+               goto out;
+       if (unlikely(addr > (unsigned long)high_memory - size))
+               goto out;
+       if (unlikely(addr & align_mask))
+               goto out;
+       if (unlikely(!kern_addr_valid(addr)))
+               goto out;
+       if (unlikely(!kern_addr_valid(addr + size - 1)))
+               goto out;
+       return 1;
+out:
+       return 0;
+}
+
 /*
  * strndup_user - duplicate an existing string from user space
  * @s: The string to duplicate
This page took 0.092518 seconds and 5 git commands to generate.