mirror of
https://github.com/torvalds/linux.git
synced 2024-11-05 03:21:32 +00:00
Merge remote branch 'nouveau/for-airlied' of ../drm-nouveau-next into drm-linus
* 'nouveau/for-airlied' of ../drm-nouveau-next: drm/nv50: prevent switching off SOR when in use for DVI-over-DP drm/nv50: fail auxch transaction if reply count not what we expect drm/nouveau: fix failure path if userspace specifies no valid memtypes drm/nouveau: report LVDS as disconnected if lid closed drm/nv50: prevent accidently turning off encoders we're actually using drm/nv50: fix alignment of per-channel fifo cache drm/nouveau: Evict buffers in VRAM before freeing sgdma drm/nouveau: Acknowledge DMA_VTX_PROTECTION PGRAPH interrupts drm/nouveau: fix thinko in nv04_instmem.c drm/nouveau: fix a race condition in nouveau_dma_wait()
This commit is contained in:
commit
8d586fe65a
@ -24,9 +24,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <acpi/button.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_edid.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "nouveau_reg.h"
|
||||
#include "nouveau_drv.h"
|
||||
#include "nouveau_encoder.h"
|
||||
@ -235,6 +238,10 @@ nouveau_connector_detect(struct drm_connector *connector)
|
||||
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
|
||||
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
|
||||
if (nv_encoder && nv_connector->native_mode) {
|
||||
#ifdef CONFIG_ACPI
|
||||
if (!nouveau_ignorelid && !acpi_lid_open())
|
||||
return connector_status_disconnected;
|
||||
#endif
|
||||
nouveau_connector_set_encoder(connector, nv_encoder);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
@ -126,47 +126,52 @@ OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
|
||||
chan->dma.cur += nr_dwords;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
READ_GET(struct nouveau_channel *chan, uint32_t *get)
|
||||
/* Fetch and adjust GPU GET pointer
|
||||
*
|
||||
* Returns:
|
||||
* value >= 0, the adjusted GET pointer
|
||||
* -EINVAL if GET pointer currently outside main push buffer
|
||||
* -EBUSY if timeout exceeded
|
||||
*/
|
||||
static inline int
|
||||
READ_GET(struct nouveau_channel *chan, uint32_t *prev_get, uint32_t *timeout)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
val = nvchan_rd32(chan, chan->user_get);
|
||||
if (val < chan->pushbuf_base ||
|
||||
val > chan->pushbuf_base + (chan->dma.max << 2)) {
|
||||
/* meaningless to dma_wait() except to know whether the
|
||||
* GPU has stalled or not
|
||||
*/
|
||||
*get = val;
|
||||
return false;
|
||||
|
||||
/* reset counter as long as GET is still advancing, this is
|
||||
* to avoid misdetecting a GPU lockup if the GPU happens to
|
||||
* just be processing an operation that takes a long time
|
||||
*/
|
||||
if (val != *prev_get) {
|
||||
*prev_get = val;
|
||||
*timeout = 0;
|
||||
}
|
||||
|
||||
*get = (val - chan->pushbuf_base) >> 2;
|
||||
return true;
|
||||
if ((++*timeout & 0xff) == 0) {
|
||||
DRM_UDELAY(1);
|
||||
if (*timeout > 100000)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (val < chan->pushbuf_base ||
|
||||
val > chan->pushbuf_base + (chan->dma.max << 2))
|
||||
return -EINVAL;
|
||||
|
||||
return (val - chan->pushbuf_base) >> 2;
|
||||
}
|
||||
|
||||
int
|
||||
nouveau_dma_wait(struct nouveau_channel *chan, int size)
|
||||
{
|
||||
uint32_t get, prev_get = 0, cnt = 0;
|
||||
bool get_valid;
|
||||
uint32_t prev_get = 0, cnt = 0;
|
||||
int get;
|
||||
|
||||
while (chan->dma.free < size) {
|
||||
/* reset counter as long as GET is still advancing, this is
|
||||
* to avoid misdetecting a GPU lockup if the GPU happens to
|
||||
* just be processing an operation that takes a long time
|
||||
*/
|
||||
get_valid = READ_GET(chan, &get);
|
||||
if (get != prev_get) {
|
||||
prev_get = get;
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
if ((++cnt & 0xff) == 0) {
|
||||
DRM_UDELAY(1);
|
||||
if (cnt > 100000)
|
||||
return -EBUSY;
|
||||
}
|
||||
get = READ_GET(chan, &prev_get, &cnt);
|
||||
if (unlikely(get == -EBUSY))
|
||||
return -EBUSY;
|
||||
|
||||
/* loop until we have a usable GET pointer. the value
|
||||
* we read from the GPU may be outside the main ring if
|
||||
@ -177,7 +182,7 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
|
||||
* from the SKIPS area, so the code below doesn't have to deal
|
||||
* with some fun corner cases.
|
||||
*/
|
||||
if (!get_valid || get < NOUVEAU_DMA_SKIPS)
|
||||
if (unlikely(get == -EINVAL) || get < NOUVEAU_DMA_SKIPS)
|
||||
continue;
|
||||
|
||||
if (get <= chan->dma.cur) {
|
||||
@ -203,6 +208,19 @@ nouveau_dma_wait(struct nouveau_channel *chan, int size)
|
||||
* after processing the currently pending commands.
|
||||
*/
|
||||
OUT_RING(chan, chan->pushbuf_base | 0x20000000);
|
||||
|
||||
/* wait for GET to depart from the skips area.
|
||||
* prevents writing GET==PUT and causing a race
|
||||
* condition that causes us to think the GPU is
|
||||
* idle when it's not.
|
||||
*/
|
||||
do {
|
||||
get = READ_GET(chan, &prev_get, &cnt);
|
||||
if (unlikely(get == -EBUSY))
|
||||
return -EBUSY;
|
||||
if (unlikely(get == -EINVAL))
|
||||
continue;
|
||||
} while (get <= NOUVEAU_DMA_SKIPS);
|
||||
WRITE_PUT(NOUVEAU_DMA_SKIPS);
|
||||
|
||||
/* we're now submitting commands at the start of
|
||||
|
@ -490,7 +490,8 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
|
||||
if (!nv_wait(NV50_AUXCH_CTRL(index), 0x00010000, 0x00000000)) {
|
||||
NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n",
|
||||
nv_rd32(dev, NV50_AUXCH_CTRL(index)));
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
udelay(400);
|
||||
@ -501,6 +502,11 @@ nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr,
|
||||
break;
|
||||
}
|
||||
|
||||
if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) {
|
||||
ret = -EREMOTEIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cmd & 1) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i));
|
||||
|
@ -71,6 +71,10 @@ MODULE_PARM_DESC(uscript_tmds, "TMDS output script table ID (>=GeForce 8)");
|
||||
int nouveau_uscript_tmds = -1;
|
||||
module_param_named(uscript_tmds, nouveau_uscript_tmds, int, 0400);
|
||||
|
||||
MODULE_PARM_DESC(ignorelid, "Ignore ACPI lid status");
|
||||
int nouveau_ignorelid = 0;
|
||||
module_param_named(ignorelid, nouveau_ignorelid, int, 0400);
|
||||
|
||||
MODULE_PARM_DESC(tv_norm, "Default TV norm.\n"
|
||||
"\t\tSupported: PAL, PAL-M, PAL-N, PAL-Nc, NTSC-M, NTSC-J,\n"
|
||||
"\t\t\thd480i, hd480p, hd576i, hd576p, hd720p, hd1080i.\n"
|
||||
|
@ -677,6 +677,7 @@ extern char *nouveau_tv_norm;
|
||||
extern int nouveau_reg_debug;
|
||||
extern char *nouveau_vbios;
|
||||
extern int nouveau_ctxfw;
|
||||
extern int nouveau_ignorelid;
|
||||
|
||||
/* nouveau_state.c */
|
||||
extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
|
||||
|
@ -321,6 +321,7 @@ retry:
|
||||
else {
|
||||
NV_ERROR(dev, "invalid valid domains: 0x%08x\n",
|
||||
b->valid_domains);
|
||||
list_add_tail(&nvbo->entry, &op->both_list);
|
||||
validate_fini(op, NULL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -483,6 +483,13 @@ nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
|
||||
if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
|
||||
if (nouveau_pgraph_intr_swmthd(dev, &trap))
|
||||
unhandled = 1;
|
||||
} else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
|
||||
uint32_t v = nv_rd32(dev, 0x402000);
|
||||
nv_wr32(dev, 0x402000, v);
|
||||
|
||||
/* dump the error anyway for now: it's useful for
|
||||
Gallium development */
|
||||
unhandled = 1;
|
||||
} else {
|
||||
unhandled = 1;
|
||||
}
|
||||
|
@ -386,7 +386,6 @@ void nouveau_mem_close(struct drm_device *dev)
|
||||
nouveau_bo_unpin(dev_priv->vga_ram);
|
||||
nouveau_bo_ref(NULL, &dev_priv->vga_ram);
|
||||
|
||||
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
|
||||
ttm_bo_device_release(&dev_priv->ttm.bdev);
|
||||
|
||||
nouveau_ttm_global_release(dev_priv);
|
||||
|
@ -525,6 +525,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
|
||||
engine->mc.takedown(dev);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
|
||||
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
nouveau_sgdma_takedown(dev);
|
||||
|
@ -30,7 +30,7 @@ nv04_instmem_determine_amount(struct drm_device *dev)
|
||||
* of vram. For now, only reserve a small piece until we know
|
||||
* more about what each chipset requires.
|
||||
*/
|
||||
switch (dev_priv->chipset & 0xf0) {
|
||||
switch (dev_priv->chipset) {
|
||||
case 0x40:
|
||||
case 0x47:
|
||||
case 0x49:
|
||||
|
@ -432,6 +432,7 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_encoder *encoder;
|
||||
uint32_t dac = 0, sor = 0;
|
||||
|
||||
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
|
||||
|
||||
@ -439,9 +440,28 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
|
||||
if (drm_helper_encoder_in_use(encoder))
|
||||
if (!drm_helper_encoder_in_use(encoder))
|
||||
continue;
|
||||
|
||||
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
|
||||
nv_encoder->dcb->type == OUTPUT_TV)
|
||||
dac |= (1 << nv_encoder->or);
|
||||
else
|
||||
sor |= (1 << nv_encoder->or);
|
||||
}
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
|
||||
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
|
||||
nv_encoder->dcb->type == OUTPUT_TV) {
|
||||
if (dac & (1 << nv_encoder->or))
|
||||
continue;
|
||||
} else {
|
||||
if (sor & (1 << nv_encoder->or))
|
||||
continue;
|
||||
}
|
||||
|
||||
nv_encoder->disconnect(nv_encoder);
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
|
||||
return ret;
|
||||
ramfc = chan->ramfc->gpuobj;
|
||||
|
||||
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 256,
|
||||
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, 4096, 1024,
|
||||
0, &chan->cache);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -90,11 +90,24 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct drm_encoder *enc;
|
||||
uint32_t val;
|
||||
int or = nv_encoder->or;
|
||||
|
||||
NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
|
||||
|
||||
nv_encoder->last_dpms = mode;
|
||||
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
|
||||
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
|
||||
|
||||
if (nvenc == nv_encoder ||
|
||||
nvenc->dcb->or != nv_encoder->dcb->or)
|
||||
continue;
|
||||
|
||||
if (nvenc->last_dpms == DRM_MODE_DPMS_ON)
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait for it to be done */
|
||||
if (!nv_wait(NV50_PDISPLAY_SOR_DPMS_CTRL(or),
|
||||
NV50_PDISPLAY_SOR_DPMS_CTRL_PENDING, 0)) {
|
||||
|
Loading…
Reference in New Issue
Block a user