diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau')
31 files changed, 212 insertions, 125 deletions
diff --git a/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/drivers/gpu/drm/nouveau/core/core/gpuobj.c index 1f34549aff1..70586fde69c 100644 --- a/drivers/gpu/drm/nouveau/core/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/core/core/gpuobj.c @@ -39,6 +39,11 @@ nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)  			nv_wo32(gpuobj, i, 0x00000000);  	} +	if (gpuobj->node) { +		nouveau_mm_free(&nv_gpuobj(gpuobj->parent)->heap, +				&gpuobj->node); +	} +  	if (gpuobj->heap.block_size)  		nouveau_mm_fini(&gpuobj->heap); diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c index bfddf87926d..a6d3cd6490f 100644 --- a/drivers/gpu/drm/nouveau/core/core/mm.c +++ b/drivers/gpu/drm/nouveau/core/core/mm.c @@ -218,13 +218,16 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)  	node = kzalloc(sizeof(*node), GFP_KERNEL);  	if (!node)  		return -ENOMEM; -	node->offset = roundup(offset, mm->block_size); -	node->length = rounddown(offset + length, mm->block_size) - node->offset; + +	if (length) { +		node->offset  = roundup(offset, mm->block_size); +		node->length  = rounddown(offset + length, mm->block_size); +		node->length -= node->offset; +	}  	list_add_tail(&node->nl_entry, &mm->nodes);  	list_add_tail(&node->fl_entry, &mm->free);  	mm->heap_nodes++; -	mm->heap_size += length;  	return 0;  } @@ -236,7 +239,7 @@ nouveau_mm_fini(struct nouveau_mm *mm)  	int nodes = 0;  	list_for_each_entry(node, &mm->nodes, nl_entry) { -		if (nodes++ == mm->heap_nodes) +		if (WARN_ON(nodes++ == mm->heap_nodes))  			return -EBUSY;  	} diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 16a9afb1060..15b182c84ce 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -22,6 +22,8 @@   * Authors: Ben Skeggs   */ +#include <subdev/bar.h> +  #include <engine/software.h>  #include <engine/disp.h> @@ -37,6 +39,7 @@ nv50_disp_sclass[] = {  static void  nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)  { +	struct nouveau_bar *bar = nouveau_bar(priv);  	struct nouveau_disp *disp = &priv->base;  	struct nouveau_software_chan *chan, *temp;  	unsigned long flags; @@ -46,19 +49,25 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)  		if (chan->vblank.crtc != crtc)  			continue; -		nv_wr32(priv, 0x001704, chan->vblank.channel); -		nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - -		if (nv_device(priv)->chipset == 0x50) { -			nv_wr32(priv, 0x001570, chan->vblank.offset); -			nv_wr32(priv, 0x001574, chan->vblank.value); +		if (nv_device(priv)->chipset >= 0xc0) { +			nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); +			bar->flush(bar); +			nv_wr32(priv, 0x06000c, +				upper_32_bits(chan->vblank.offset)); +			nv_wr32(priv, 0x060010, +				lower_32_bits(chan->vblank.offset)); +			nv_wr32(priv, 0x060014, chan->vblank.value);  		} else { -			if (nv_device(priv)->chipset >= 0xc0) { -				nv_wr32(priv, 0x06000c, -					upper_32_bits(chan->vblank.offset)); +			nv_wr32(priv, 0x001704, chan->vblank.channel); +			nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); +			bar->flush(bar); +			if (nv_device(priv)->chipset == 0x50) { +				nv_wr32(priv, 0x001570, chan->vblank.offset); +				nv_wr32(priv, 0x001574, chan->vblank.value); +			} else { +				nv_wr32(priv, 0x060010, chan->vblank.offset); +				nv_wr32(priv, 0x060014, chan->vblank.value);  			} -			nv_wr32(priv, 0x060010, chan->vblank.offset); -			nv_wr32(priv, 0x060014, chan->vblank.value);  		}  		list_del(&chan->vblank.head); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c index e45035efb8c..7bbb1e1b7a8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -669,21 +669,27 @@ nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)  			   });  } -void +int  nv40_grctx_init(struct nouveau_device *device, u32 *size)  { -	u32 ctxprog[256], i; +	u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;  	struct nouveau_grctx ctx = {  		.device = device,  		.mode = NOUVEAU_GRCTX_PROG,  		.data = ctxprog, -		.ctxprog_max = ARRAY_SIZE(ctxprog) +		.ctxprog_max = 256,  	}; +	if (!ctxprog) +		return -ENOMEM; +  	nv40_grctx_generate(&ctx);  	nv_wr32(device, 0x400324, 0);  	for (i = 0; i < ctx.ctxprog_len; i++)  		nv_wr32(device, 0x400328, ctxprog[i]);  	*size = ctx.ctxvals_pos * 4; + +	kfree(ctxprog); +	return 0;  } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 8d0021049ec..cc6574eeb80 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -156,8 +156,8 @@ nv40_graph_context_ctor(struct nouveau_object *parent,  static int  nv40_graph_context_fini(struct nouveau_object *object, bool suspend)  { -	struct nv04_graph_priv *priv = (void *)object->engine; -	struct nv04_graph_chan *chan = (void *)object; +	struct nv40_graph_priv *priv = (void *)object->engine; +	struct nv40_graph_chan *chan = (void *)object;  	u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;  	int ret = 0; @@ -346,7 +346,9 @@ nv40_graph_init(struct nouveau_object *object)  		return ret;  	/* generate and upload context program */ -	nv40_grctx_init(nv_device(priv), &priv->size); +	ret = nv40_grctx_init(nv_device(priv), &priv->size); +	if (ret) +		return ret;  	/* No context present currently */  	nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h index d2ac975afc2..7da35a4e797 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h @@ -15,7 +15,7 @@ nv44_graph_class(void *priv)  	return !(0x0baf & (1 << (device->chipset & 0x0f)));  } -void nv40_grctx_init(struct nouveau_device *, u32 *size); +int  nv40_grctx_init(struct nouveau_device *, u32 *size);  void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);  #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c index 12418574efe..f7c581ad199 100644 --- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c @@ -38,7 +38,7 @@ struct nv40_mpeg_priv {  };  struct nv40_mpeg_chan { -	struct nouveau_mpeg base; +	struct nouveau_mpeg_chan base;  };  /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h index 9ee9bf4028c..975137ba34a 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/mm.h +++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h @@ -19,7 +19,6 @@ struct nouveau_mm {  	u32 block_size;  	int heap_nodes; -	u32 heap_size;  };  int  nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 818feabbf4a..486f1a9217f 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -175,14 +175,18 @@ nv_mo32(void *obj, u32 addr, u32 mask, u32 data)  	return temp;  } -static inline bool -nv_strncmp(void *obj, u32 addr, u32 len, const char *str) +static inline int +nv_memcmp(void *obj, u32 addr, const char *str, u32 len)  { +	unsigned char c1, c2; +  	while (len--) { -		if (nv_ro08(obj, addr++) != *(str++)) -			return false; +		c1 = nv_ro08(obj, addr++); +		c2 = *(str++); +		if (c1 != c2) +			return c1 - c2;  	} -	return true; +	return 0;  }  #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 39e73b91d36..41b7a6a76f1 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -54,6 +54,7 @@ int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,  			int clk, struct nouveau_pll_vals *);  int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,  			struct nouveau_pll_vals *); - +int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, +			int clk, struct nouveau_pll_vals *);  #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index dcb5c2befc9..70ca7d5a1aa 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -72,7 +72,7 @@ nouveau_bios_shadow_of(struct nouveau_bios *bios)  	}  	data = of_get_property(dn, "NVDA,BMP", &size); -	if (data) { +	if (data && size) {  		bios->size = size;  		bios->data = kmalloc(bios->size, GFP_KERNEL);  		if (bios->data) @@ -104,6 +104,9 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios)  		goto out;  	bios->size = nv_rd08(bios, 0x700002) * 512; +	if (!bios->size) +		goto out; +  	bios->data = kmalloc(bios->size, GFP_KERNEL);  	if (bios->data) {  		for (i = 0; i < bios->size; i++) @@ -155,6 +158,9 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)  	/* read entire bios image to system memory */  	bios->size = nv_rd08(bios, 0x300002) * 512; +	if (!bios->size) +		goto out; +  	bios->data = kmalloc(bios->size, GFP_KERNEL);  	if (bios->data) {  		for (i = 0; i < bios->size; i++) @@ -186,14 +192,22 @@ nouveau_bios_shadow_acpi(struct nouveau_bios *bios)  {  	struct pci_dev *pdev = nv_device(bios)->pdev;  	int ret, cnt, i; -	u8  data[3]; -	if (!nouveau_acpi_rom_supported(pdev)) +	if (!nouveau_acpi_rom_supported(pdev)) { +		bios->data = NULL;  		return; +	}  	bios->size = 0; -	if (nouveau_acpi_get_bios_chunk(data, 0, 3) == 3) -		bios->size = data[2] * 512; +	bios->data = kmalloc(4096, GFP_KERNEL); +	if (bios->data) { +		if (nouveau_acpi_get_bios_chunk(bios->data, 0, 4096) == 4096) +			bios->size = bios->data[2] * 512; +		kfree(bios->data); +	} + +	if (!bios->size) +		return;  	bios->data = kmalloc(bios->size, GFP_KERNEL);  	for (i = 0; bios->data && i < bios->size; i += cnt) { @@ -229,12 +243,14 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios)  static int  nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)  { -	if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) { +	if (bios->size < 3 || !bios->data || bios->data[0] != 0x55 || +			bios->data[1] != 0xAA) {  		nv_info(bios, "... signature not found\n");  		return 0;  	} -	if (nvbios_checksum(bios->data, bios->data[2] * 512)) { +	if (nvbios_checksum(bios->data, +			min_t(u32, bios->data[2] * 512, bios->size))) {  		nv_info(bios, "... checksum invalid\n");  		/* if a ro image is somewhat bad, it's probably all rubbish */  		return writeable ? 2 : 1; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 9ed6e728a94..c5119715774 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -43,7 +43,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)  	*ver = nv_ro08(bios, dcb);  	if (*ver >= 0x41) { -		nv_warn(bios, "DCB *ver 0x%02x unknown\n", *ver); +		nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);  		return 0x0000;  	} else  	if (*ver >= 0x30) { @@ -64,7 +64,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)  		}  	} else  	if (*ver >= 0x15) { -		if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { +		if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {  			u16 i2c = nv_ro16(bios, dcb + 2);  			*hdr = 4;  			*cnt = (i2c - dcb) / 10; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c index 5e5f4cddae3..f835501203e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c @@ -157,11 +157,10 @@ pll_map_reg(struct nouveau_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len)  	while (map->reg) {  		if (map->reg == reg && *ver >= 0x20) {  			u16 addr = (data += hdr); +			*type = map->type;  			while (cnt--) { -				if (nv_ro32(bios, data) == map->reg) { -					*type = map->type; +				if (nv_ro32(bios, data) == map->reg)  					return data; -				}  				data += *len;  			}  			return addr; @@ -200,11 +199,10 @@ pll_map_type(struct nouveau_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len)  	while (map->reg) {  		if (map->type == type && *ver >= 0x20) {  			u16 addr = (data += hdr); +			*reg = map->reg;  			while (cnt--) { -				if (nv_ro32(bios, data) == map->reg) { -					*reg = map->reg; +				if (nv_ro32(bios, data) == map->reg)  					return data; -				}  				data += *len;  			}  			return addr; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index cc8d7d162d7..9068c98b96f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -66,6 +66,24 @@ nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)  	return ret;  } +int +nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, +		    int clk, struct nouveau_pll_vals *pv) +{ +	int ret, N, M, P; + +	ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P); + +	if (ret > 0) { +		pv->refclk = info->refclk; +		pv->N1 = N; +		pv->M1 = M; +		pv->log2P = P; +	} +	return ret; +} + +  static int  nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  		struct nouveau_oclass *oclass, void *data, u32 size, @@ -80,6 +98,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  		return ret;  	priv->base.pll_set = nva3_clock_pll_set; +	priv->base.pll_calc = nva3_clock_pll_calc;  	return 0;  } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 5ccce0b17bf..f6962c9b6c3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -79,6 +79,7 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  		return ret;  	priv->base.pll_set = nvc0_clock_pll_set; +	priv->base.pll_calc = nva3_clock_pll_calc;  	return 0;  } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index 436e9efe7ef..5f570806143 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -219,13 +219,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  			     ((priv->base.ram.size & 0x000000ff) << 32);  	tags = nv_rd32(priv, 0x100320); -	if (tags) { -		ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1); -		if (ret) -			return ret; +	ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1); +	if (ret) +		return ret; -		nv_debug(priv, "%d compression tags\n", tags); -	} +	nv_debug(priv, "%d compression tags\n", tags);  	size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;  	switch (device->chipset) { @@ -237,6 +235,7 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  			return ret;  		priv->base.ram.stolen = (u64)nv_rd32(priv, 0x100e10) << 12; +		priv->base.ram.type = NV_MEM_TYPE_STOLEN;  		break;  	default:  		ret = nouveau_mm_init(&priv->base.vram, rsvd_head, size, @@ -277,7 +276,6 @@ nv50_fb_dtor(struct nouveau_object *object)  		__free_page(priv->r100c08_page);  	} -	nouveau_mm_fini(&priv->base.vram);  	nouveau_fb_destroy(&priv->base);  } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index 3d2c88310f9..dbfc2abf0cf 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -292,7 +292,7 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  		case DCB_I2C_NVIO_BIT:  			port->drive = info.drive & 0x0f;  			if (device->card_type < NV_D0) { -				if (info.drive >= ARRAY_SIZE(nv50_i2c_port)) +				if (port->drive >= ARRAY_SIZE(nv50_i2c_port))  					break;  				port->drive = nv50_i2c_port[port->drive];  				port->sense = port->drive; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index b29237970fa..52317868518 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -134,7 +134,7 @@ nouveau_therm_fan_sense(struct nouveau_therm *therm)  	end = ptimer->read(ptimer);  	if (cycles == 5) { -		tach = (u64)60000000000; +		tach = (u64)60000000000ULL;  		do_div(tach, (end - start));  		return tach;  	} else diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c index 0203e1e12ca..9474cfca6e4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c @@ -67,7 +67,7 @@ nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)  static void  nv41_vm_flush(struct nouveau_vm *vm)  { -	struct nv04_vm_priv *priv = (void *)vm->vmm; +	struct nv04_vmmgr_priv *priv = (void *)vm->vmm;  	mutex_lock(&nv_subdev(priv)->mutex);  	nv_wr32(priv, 0x100810, 0x00000022); @@ -92,7 +92,8 @@ nv41_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  	struct nv04_vmmgr_priv *priv;  	int ret; -	if (!nouveau_boolopt(device->cfgopt, "NvPCIE", true)) { +	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || +	    !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {  		return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,  					   data, size, pobject);  	} diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c index 0ac18d05a14..aa8131436e3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c @@ -163,7 +163,8 @@ nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,  	struct nv04_vmmgr_priv *priv;  	int ret; -	if (!nouveau_boolopt(device->cfgopt, "NvPCIE", true)) { +	if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || +	    !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {  		return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,  					   data, size, pobject);  	} diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index cc79c796afe..cbf1fc60a38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -241,6 +241,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)  	if (unlikely(!abi16))  		return -ENOMEM; + +	if (!drm->channel) +		return nouveau_abi16_put(abi16, -ENODEV); +  	client = nv_client(abi16->client);  	if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 259e5f1adf4..35ac57f0aab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -456,6 +456,7 @@ static struct ttm_tt *  nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,  		      uint32_t page_flags, struct page *dummy_read)  { +#if __OS_HAS_AGP  	struct nouveau_drm *drm = nouveau_bdev(bdev);  	struct drm_device *dev = drm->dev; @@ -463,6 +464,7 @@ nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,  		return ttm_agp_tt_create(bdev, dev->agp->bridge, size,  					 page_flags, dummy_read);  	} +#endif  	return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read);  } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9a6e2cb282d..d3595b23434 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -355,7 +355,7 @@ nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)  	 * valid - it's not (rh#613284)  	 */  	if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) { -		if (!(nv_connector->edid = nouveau_acpi_edid(dev, connector))) { +		if ((nv_connector->edid = nouveau_acpi_edid(dev, connector))) {  			status = connector_status_connected;  			goto out;  		} diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 8f98e5a8c48..86124b131f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -290,6 +290,7 @@ nouveau_display_create(struct drm_device *dev)  	struct nouveau_drm *drm = nouveau_drm(dev);  	struct nouveau_disp *pdisp = nouveau_disp(drm->device);  	struct nouveau_display *disp; +	u32 pclass = dev->pdev->class >> 8;  	int ret, gen;  	disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL); @@ -360,23 +361,27 @@ nouveau_display_create(struct drm_device *dev)  	drm_kms_helper_poll_init(dev);  	drm_kms_helper_poll_disable(dev); -	if (nv_device(drm->device)->card_type < NV_50) -		ret = nv04_display_create(dev); -	else -	if (nv_device(drm->device)->card_type < NV_D0) -		ret = nv50_display_create(dev); -	else -		ret = nvd0_display_create(dev); -	if (ret) -		goto disp_create_err; - -	if (dev->mode_config.num_crtc) { -		ret = drm_vblank_init(dev, dev->mode_config.num_crtc); +	if (nouveau_modeset == 1 || +	    (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) { +		if (nv_device(drm->device)->card_type < NV_50) +			ret = nv04_display_create(dev); +		else +		if (nv_device(drm->device)->card_type < NV_D0) +			ret = nv50_display_create(dev); +		else +			ret = nvd0_display_create(dev);  		if (ret) -			goto vblank_err; +			goto disp_create_err; + +		if (dev->mode_config.num_crtc) { +			ret = drm_vblank_init(dev, dev->mode_config.num_crtc); +			if (ret) +				goto vblank_err; +		} + +		nouveau_backlight_init(dev);  	} -	nouveau_backlight_init(dev);  	return 0;  vblank_err: @@ -395,7 +400,8 @@ nouveau_display_destroy(struct drm_device *dev)  	nouveau_backlight_exit(dev);  	drm_vblank_cleanup(dev); -	disp->dtor(dev); +	if (disp->dtor) +		disp->dtor(dev);  	drm_kms_helper_poll_fini(dev);  	drm_mode_config_cleanup(dev); @@ -530,9 +536,11 @@ nouveau_page_flip_reserve(struct nouveau_bo *old_bo,  	if (ret)  		goto fail; -	ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); -	if (ret) -		goto fail_unreserve; +	if (likely(old_bo != new_bo)) { +		ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); +		if (ret) +			goto fail_unreserve; +	}  	return 0; @@ -551,8 +559,10 @@ nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,  	nouveau_bo_fence(new_bo, fence);  	ttm_bo_unreserve(&new_bo->bo); -	nouveau_bo_fence(old_bo, fence); -	ttm_bo_unreserve(&old_bo->bo); +	if (likely(old_bo != new_bo)) { +		nouveau_bo_fence(old_bo, fence); +		ttm_bo_unreserve(&old_bo->bo); +	}  	nouveau_bo_unpin(old_bo);  } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ccae8c26ae2..8503b2ea570 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -63,8 +63,9 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration");  static int nouveau_noaccel = 0;  module_param_named(noaccel, nouveau_noaccel, int, 0400); -MODULE_PARM_DESC(modeset, "enable driver"); -static int nouveau_modeset = -1; +MODULE_PARM_DESC(modeset, "enable driver (default: auto, " +		          "0 = disabled, 1 = enabled, 2 = headless)"); +int nouveau_modeset = -1;  module_param_named(modeset, nouveau_modeset, int, 0400);  static struct drm_driver driver; @@ -128,7 +129,8 @@ nouveau_accel_init(struct nouveau_drm *drm)  	/* initialise synchronisation routines */  	if      (device->card_type < NV_10) ret = nv04_fence_create(drm); -	else if (device->chipset   <  0x84) ret = nv10_fence_create(drm); +	else if (device->card_type < NV_50) ret = nv10_fence_create(drm); +	else if (device->chipset   <  0x84) ret = nv50_fence_create(drm);  	else if (device->card_type < NV_C0) ret = nv84_fence_create(drm);  	else                                ret = nvc0_fence_create(drm);  	if (ret) { @@ -363,7 +365,8 @@ nouveau_drm_unload(struct drm_device *dev)  	nouveau_pm_fini(dev); -	nouveau_display_fini(dev); +	if (dev->mode_config.num_crtc) +		nouveau_display_fini(dev);  	nouveau_display_destroy(dev);  	nouveau_irq_fini(dev); @@ -403,13 +406,15 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)  	    pm_state.event == PM_EVENT_PRETHAW)  		return 0; -	NV_INFO(drm, "suspending fbcon...\n"); -	nouveau_fbcon_set_suspend(dev, 1); +	if (dev->mode_config.num_crtc) { +		NV_INFO(drm, "suspending fbcon...\n"); +		nouveau_fbcon_set_suspend(dev, 1); -	NV_INFO(drm, "suspending display...\n"); -	ret = nouveau_display_suspend(dev); -	if (ret) -		return ret; +		NV_INFO(drm, "suspending display...\n"); +		ret = nouveau_display_suspend(dev); +		if (ret) +			return ret; +	}  	NV_INFO(drm, "evicting buffers...\n");  	ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM); @@ -445,8 +450,10 @@ fail_client:  		nouveau_client_init(&cli->base);  	} -	NV_INFO(drm, "resuming display...\n"); -	nouveau_display_resume(dev); +	if (dev->mode_config.num_crtc) { +		NV_INFO(drm, "resuming display...\n"); +		nouveau_display_resume(dev); +	}  	return ret;  } @@ -486,8 +493,10 @@ nouveau_drm_resume(struct pci_dev *pdev)  	nouveau_irq_postinstall(dev);  	nouveau_pm_resume(dev); -	NV_INFO(drm, "resuming display...\n"); -	nouveau_display_resume(dev); +	if (dev->mode_config.num_crtc) { +		NV_INFO(drm, "resuming display...\n"); +		nouveau_display_resume(dev); +	}  	return 0;  } @@ -662,9 +671,7 @@ nouveau_drm_init(void)  #ifdef CONFIG_VGA_CONSOLE  		if (vgacon_text_force())  			nouveau_modeset = 0; -		else  #endif -			nouveau_modeset = 1;  	}  	if (!nouveau_modeset) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 81947121754..a1016992708 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -141,4 +141,6 @@ int nouveau_drm_resume(struct pci_dev *);  		nv_info((cli), fmt, ##args);                                   \  } while (0) +extern int nouveau_modeset; +  #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c index 9ca8afdb554..1d8cb506a28 100644 --- a/drivers/gpu/drm/nouveau/nouveau_irq.c +++ b/drivers/gpu/drm/nouveau/nouveau_irq.c @@ -61,13 +61,15 @@ nouveau_irq_handler(DRM_IRQ_ARGS)  	nv_subdev(pmc)->intr(nv_subdev(pmc)); -	if (device->card_type >= NV_D0) { -		if (nv_rd32(device, 0x000100) & 0x04000000) -			nvd0_display_intr(dev); -	} else -	if (device->card_type >= NV_50) { -		if (nv_rd32(device, 0x000100) & 0x04000000) -			nv50_display_intr(dev); +	if (dev->mode_config.num_crtc) { +		if (device->card_type >= NV_D0) { +			if (nv_rd32(device, 0x000100) & 0x04000000) +				nvd0_display_intr(dev); +		} else +		if (device->card_type >= NV_50) { +			if (nv_rd32(device, 0x000100) & 0x04000000) +				nv50_display_intr(dev); +		}  	}  	return IRQ_HANDLED; diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c index 0bf64c90aa2..5566172774d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -52,7 +52,7 @@ nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,  {  	struct nouveau_drm *drm = nouveau_drm(dev);  	struct nouveau_pm *pm = nouveau_pm(dev); -	struct nouveau_therm *therm = nouveau_therm(drm); +	struct nouveau_therm *therm = nouveau_therm(drm->device);  	int ret;  	/*XXX: not on all boards, we should control based on temperature @@ -64,7 +64,6 @@ nouveau_pm_perflvl_aux(struct drm_device *dev, struct nouveau_pm_level *perflvl,  		ret = therm->fan_set(therm, perflvl->fanspeed);  		if (ret && ret != -ENODEV) {  			NV_ERROR(drm, "fanspeed set failed: %d\n", ret); -			return ret;  		}  	} @@ -706,8 +705,7 @@ nouveau_hwmon_init(struct drm_device *dev)  	struct device *hwmon_dev;  	int ret = 0; -	if (!therm || !therm->temp_get || !therm->attr_get || -		!therm->attr_set || therm->temp_get(therm) < 0) +	if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set)  		return -ENODEV;  	hwmon_dev = hwmon_device_register(&dev->pdev->dev); diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index 347a3bd78d0..64f7020fb60 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -220,7 +220,7 @@ out:  	NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);  	if (blue == 0x18) { -		NV_INFO(drm, "Load detected on head A\n"); +		NV_DEBUG(drm, "Load detected on head A\n");  		return connector_status_connected;  	} @@ -338,8 +338,8 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)  	if (nv17_dac_sample_load(encoder) &  	    NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { -		NV_INFO(drm, "Load detected on output %c\n", -			'@' + ffs(dcb->or)); +		NV_DEBUG(drm, "Load detected on output %c\n", +			 '@' + ffs(dcb->or));  		return connector_status_connected;  	} else {  		return connector_status_disconnected; @@ -413,9 +413,9 @@ static void nv04_dac_commit(struct drm_encoder *encoder)  	helper->dpms(encoder, DRM_MODE_DPMS_ON); -	NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", -		drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), -		nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); +	NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", +		 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), +		 nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));  }  void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) @@ -461,8 +461,8 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)  		return;  	nv_encoder->last_dpms = mode; -	NV_INFO(drm, "Setting dpms mode %d on vga encoder (output %d)\n", -		     mode, nv_encoder->dcb->index); +	NV_DEBUG(drm, "Setting dpms mode %d on vga encoder (output %d)\n", +		 mode, nv_encoder->dcb->index);  	nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);  } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index da55d7642c8..184cdf80676 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -476,9 +476,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)  	helper->dpms(encoder, DRM_MODE_DPMS_ON); -	NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", -		drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), -		nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); +	NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", +		 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), +		 nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));  }  static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) @@ -520,8 +520,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)  		return;  	nv_encoder->last_dpms = mode; -	NV_INFO(drm, "Setting dpms mode %d on lvds encoder (output %d)\n", -		     mode, nv_encoder->dcb->index); +	NV_DEBUG(drm, "Setting dpms mode %d on lvds encoder (output %d)\n", +		 mode, nv_encoder->dcb->index);  	if (was_powersaving && is_powersaving_dpms(mode))  		return; @@ -565,8 +565,8 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)  		return;  	nv_encoder->last_dpms = mode; -	NV_INFO(drm, "Setting dpms mode %d on tmds encoder (output %d)\n", -		     mode, nv_encoder->dcb->index); +	NV_DEBUG(drm, "Setting dpms mode %d on tmds encoder (output %d)\n", +		 mode, nv_encoder->dcb->index);  	nv04_dfp_update_backlight(encoder, mode);  	nv04_dfp_update_fp_control(encoder, mode); diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index 099fbeda6e2..62e826a139b 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -75,8 +75,8 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)  	struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;  	uint8_t crtc1A; -	NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n", -		mode, nv_encoder->dcb->index); +	NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n", +		 mode, nv_encoder->dcb->index);  	state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK); @@ -167,9 +167,8 @@ static void nv04_tv_commit(struct drm_encoder *encoder)  	helper->dpms(encoder, DRM_MODE_DPMS_ON); -	NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n", -		      drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, -		      '@' + ffs(nv_encoder->dcb->or)); +	NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n", +		 drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));  }  static void nv04_tv_destroy(struct drm_encoder *encoder)  |