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:
Dave Airlie 2010-01-25 16:04:11 +10:00
Родитель 1a961ce09f 162265367a
Коммит 8d586fe65a
13 изменённых файлов: 111 добавлений и 34 удалений

Просмотреть файл

@ -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)) {