mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 16:44:10 +08:00
Merge branch 'linux-5.12' of git://github.com/skeggsb/linux into drm-next
Nothing too major here, I actually thought I'd sent most of these right before the new year, but that apparently got lost in the bustle: - Turing MMU fault recovery fixes - Fix mDP connectors being reported as eDP to userspace - Fixes for audio locking, and other bit-rot from DRM changes since atomic support was written - Misc other minor fixes. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Ben Skeggs <skeggsb@gmail.com> Link: https://patchwork.freedesktop.org/patch/msgid/CACAvsv7yLfhuVbYa-4g0vxVt93OaC7Sodiz2R-TDHu-MoofEdw@mail.gmail.com
This commit is contained in:
commit
af2922fa15
@ -36,7 +36,7 @@ core507d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
|
||||
struct nvif_push *push = core->chan.push;
|
||||
int ret;
|
||||
|
||||
if ((ret = PUSH_WAIT(push, 5)))
|
||||
if ((ret = PUSH_WAIT(push, (ntfy ? 2 : 0) + 3)))
|
||||
return ret;
|
||||
|
||||
if (ntfy) {
|
||||
|
@ -54,7 +54,7 @@ corec37d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
|
||||
struct nvif_push *push = core->chan.push;
|
||||
int ret;
|
||||
|
||||
if ((ret = PUSH_WAIT(push, 9)))
|
||||
if ((ret = PUSH_WAIT(push, (ntfy ? 2 * 2 : 0) + 5)))
|
||||
return ret;
|
||||
|
||||
if (ntfy) {
|
||||
|
@ -220,6 +220,10 @@ nv50_dmac_wait(struct nvif_push *push, u32 size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_PARM_DESC(kms_vram_pushbuf, "Place EVO/NVD push buffers in VRAM (default: auto)");
|
||||
static int nv50_dmac_vram_pushbuf = -1;
|
||||
module_param_named(kms_vram_pushbuf, nv50_dmac_vram_pushbuf, int, 0400);
|
||||
|
||||
int
|
||||
nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
|
||||
const s32 *oclass, u8 head, void *data, u32 size, s64 syncbuf,
|
||||
@ -241,7 +245,8 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
|
||||
*
|
||||
* This appears to match NVIDIA's behaviour on Pascal.
|
||||
*/
|
||||
if (device->info.family == NV_DEVICE_INFO_V0_PASCAL)
|
||||
if ((nv50_dmac_vram_pushbuf > 0) ||
|
||||
(nv50_dmac_vram_pushbuf < 0 && device->info.family == NV_DEVICE_INFO_V0_PASCAL))
|
||||
type |= NVIF_MEM_VRAM;
|
||||
|
||||
ret = nvif_mem_ctor_map(&cli->mmu, "kmsChanPush", type, 0x1000,
|
||||
@ -304,6 +309,14 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
|
||||
/******************************************************************************
|
||||
* Output path helpers
|
||||
*****************************************************************************/
|
||||
static void
|
||||
nv50_outp_dump_caps(struct nouveau_drm *drm,
|
||||
struct nouveau_encoder *outp)
|
||||
{
|
||||
NV_DEBUG(drm, "%s caps: dp_interlace=%d\n",
|
||||
outp->base.base.name, outp->caps.dp_interlace);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_outp_release(struct nouveau_encoder *nv_encoder)
|
||||
{
|
||||
@ -419,8 +432,7 @@ nv50_outp_atomic_check(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
struct nouveau_connector *
|
||||
nv50_outp_get_new_connector(struct nouveau_encoder *outp,
|
||||
struct drm_atomic_state *state)
|
||||
nv50_outp_get_new_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *connector_state;
|
||||
@ -436,8 +448,7 @@ nv50_outp_get_new_connector(struct nouveau_encoder *outp,
|
||||
}
|
||||
|
||||
struct nouveau_connector *
|
||||
nv50_outp_get_old_connector(struct nouveau_encoder *outp,
|
||||
struct drm_atomic_state *state)
|
||||
nv50_outp_get_old_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_connector_state *connector_state;
|
||||
@ -452,27 +463,44 @@ nv50_outp_get_old_connector(struct nouveau_encoder *outp,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nouveau_crtc *
|
||||
nv50_outp_get_new_crtc(const struct drm_atomic_state *state, const struct nouveau_encoder *outp)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
const u32 mask = drm_encoder_mask(&outp->base.base);
|
||||
int i;
|
||||
|
||||
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
||||
if (crtc_state->encoder_mask & mask)
|
||||
return nouveau_crtc(crtc);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* DAC
|
||||
*****************************************************************************/
|
||||
static void
|
||||
nv50_dac_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_dac_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nv50_core *core = nv50_disp(encoder->dev)->core;
|
||||
const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE);
|
||||
if (nv_encoder->crtc)
|
||||
core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL);
|
||||
|
||||
core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL);
|
||||
nv_encoder->crtc = NULL;
|
||||
nv50_outp_release(nv_encoder);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_dac_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_dac_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state);
|
||||
struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder);
|
||||
struct nv50_head_atom *asyh =
|
||||
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base));
|
||||
struct nv50_core *core = nv50_disp(encoder->dev)->core;
|
||||
u32 ctrl = 0;
|
||||
|
||||
@ -493,7 +521,7 @@ nv50_dac_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
core->func->dac->ctrl(core, nv_encoder->or, ctrl, asyh);
|
||||
asyh->or.depth = 0;
|
||||
|
||||
nv_encoder->crtc = encoder->crtc;
|
||||
nv_encoder->crtc = &nv_crtc->base;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
@ -526,8 +554,8 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
|
||||
static const struct drm_encoder_helper_funcs
|
||||
nv50_dac_help = {
|
||||
.atomic_check = nv50_outp_atomic_check,
|
||||
.atomic_enable = nv50_dac_enable,
|
||||
.atomic_disable = nv50_dac_disable,
|
||||
.atomic_enable = nv50_dac_atomic_enable,
|
||||
.atomic_disable = nv50_dac_atomic_disable,
|
||||
.detect = nv50_dac_detect
|
||||
};
|
||||
|
||||
@ -593,34 +621,27 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id,
|
||||
struct nouveau_drm *drm = nouveau_drm(drm_dev);
|
||||
struct drm_encoder *encoder;
|
||||
struct nouveau_encoder *nv_encoder;
|
||||
struct drm_connector *connector;
|
||||
struct nouveau_crtc *nv_crtc;
|
||||
struct drm_connector_list_iter conn_iter;
|
||||
int ret = 0;
|
||||
|
||||
*enabled = false;
|
||||
|
||||
mutex_lock(&drm->audio.lock);
|
||||
|
||||
drm_for_each_encoder(encoder, drm->dev) {
|
||||
struct nouveau_connector *nv_connector = NULL;
|
||||
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST)
|
||||
continue; /* TODO */
|
||||
|
||||
nv_encoder = nouveau_encoder(encoder);
|
||||
nv_connector = nouveau_connector(nv_encoder->audio.connector);
|
||||
nv_crtc = nouveau_crtc(nv_encoder->crtc);
|
||||
|
||||
drm_connector_list_iter_begin(drm_dev, &conn_iter);
|
||||
drm_for_each_connector_iter(connector, &conn_iter) {
|
||||
if (connector->state->best_encoder == encoder) {
|
||||
nv_connector = nouveau_connector(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
drm_connector_list_iter_end(&conn_iter);
|
||||
if (!nv_connector)
|
||||
if (!nv_crtc || nv_encoder->or != port || nv_crtc->index != dev_id)
|
||||
continue;
|
||||
|
||||
nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
if (!nv_crtc || nv_encoder->or != port ||
|
||||
nv_crtc->index != dev_id)
|
||||
continue;
|
||||
*enabled = nv_encoder->audio;
|
||||
*enabled = nv_encoder->audio.enabled;
|
||||
if (*enabled) {
|
||||
ret = drm_eld_size(nv_connector->base.eld);
|
||||
memcpy(buf, nv_connector->base.eld,
|
||||
@ -629,6 +650,8 @@ nv50_audio_component_get_eld(struct device *kdev, int port, int dev_id,
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&drm->audio.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -678,17 +701,22 @@ static const struct component_ops nv50_audio_component_bind_ops = {
|
||||
static void
|
||||
nv50_audio_component_init(struct nouveau_drm *drm)
|
||||
{
|
||||
if (!component_add(drm->dev->dev, &nv50_audio_component_bind_ops))
|
||||
drm->audio.component_registered = true;
|
||||
if (component_add(drm->dev->dev, &nv50_audio_component_bind_ops))
|
||||
return;
|
||||
|
||||
drm->audio.component_registered = true;
|
||||
mutex_init(&drm->audio.lock);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_audio_component_fini(struct nouveau_drm *drm)
|
||||
{
|
||||
if (drm->audio.component_registered) {
|
||||
component_del(drm->dev->dev, &nv50_audio_component_bind_ops);
|
||||
drm->audio.component_registered = false;
|
||||
}
|
||||
if (!drm->audio.component_registered)
|
||||
return;
|
||||
|
||||
component_del(drm->dev->dev, &nv50_audio_component_bind_ops);
|
||||
drm->audio.component_registered = false;
|
||||
mutex_destroy(&drm->audio.lock);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@ -711,24 +739,25 @@ nv50_audio_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
|
||||
(0x0100 << nv_crtc->index),
|
||||
};
|
||||
|
||||
if (!nv_encoder->audio)
|
||||
return;
|
||||
|
||||
nv_encoder->audio = false;
|
||||
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
|
||||
mutex_lock(&drm->audio.lock);
|
||||
if (nv_encoder->audio.enabled) {
|
||||
nv_encoder->audio.enabled = false;
|
||||
nv_encoder->audio.connector = NULL;
|
||||
nvif_mthd(&disp->disp->object, 0, &args, sizeof(args));
|
||||
}
|
||||
mutex_unlock(&drm->audio.lock);
|
||||
|
||||
nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
|
||||
nv_crtc->index);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_audio_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
nv50_audio_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
|
||||
struct nouveau_connector *nv_connector, struct drm_atomic_state *state,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
struct nouveau_connector *nv_connector;
|
||||
struct nv50_disp *disp = nv50_disp(encoder->dev);
|
||||
struct __packed {
|
||||
struct {
|
||||
@ -744,15 +773,19 @@ nv50_audio_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
(0x0100 << nv_crtc->index),
|
||||
};
|
||||
|
||||
nv_connector = nv50_outp_get_new_connector(nv_encoder, state);
|
||||
if (!drm_detect_monitor_audio(nv_connector->edid))
|
||||
return;
|
||||
|
||||
mutex_lock(&drm->audio.lock);
|
||||
|
||||
memcpy(args.data, nv_connector->base.eld, sizeof(args.data));
|
||||
|
||||
nvif_mthd(&disp->disp->object, 0, &args,
|
||||
sizeof(args.base) + drm_eld_size(args.data));
|
||||
nv_encoder->audio = true;
|
||||
nv_encoder->audio.enabled = true;
|
||||
nv_encoder->audio.connector = &nv_connector->base;
|
||||
|
||||
mutex_unlock(&drm->audio.lock);
|
||||
|
||||
nv50_audio_component_eld_notify(drm->audio.component, nv_encoder->or,
|
||||
nv_crtc->index);
|
||||
@ -781,12 +814,12 @@ nv50_hdmi_disable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc)
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc,
|
||||
struct nouveau_connector *nv_connector, struct drm_atomic_state *state,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct nouveau_drm *drm = nouveau_drm(encoder->dev);
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
struct nv50_disp *disp = nv50_disp(encoder->dev);
|
||||
struct {
|
||||
struct nv50_disp_mthd_v1 base;
|
||||
@ -801,7 +834,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
.pwr.state = 1,
|
||||
.pwr.rekey = 56, /* binary driver, and tegra, constant */
|
||||
};
|
||||
struct nouveau_connector *nv_connector;
|
||||
struct drm_hdmi_info *hdmi;
|
||||
u32 max_ac_packet;
|
||||
union hdmi_infoframe avi_frame;
|
||||
@ -811,7 +843,6 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
int ret;
|
||||
int size;
|
||||
|
||||
nv_connector = nv50_outp_get_new_connector(nv_encoder, state);
|
||||
if (!drm_detect_hdmi_monitor(nv_connector->edid))
|
||||
return;
|
||||
|
||||
@ -857,7 +888,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_atomic_state *state,
|
||||
+ args.pwr.vendor_infoframe_length;
|
||||
nvif_mthd(&disp->disp->object, 0, &args, size);
|
||||
|
||||
nv50_audio_enable(encoder, state, mode);
|
||||
nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode);
|
||||
|
||||
/* If SCDC is supported by the downstream monitor, update
|
||||
* divider / scrambling settings to what we programmed above.
|
||||
@ -898,6 +929,7 @@ struct nv50_mstc {
|
||||
struct nv50_msto {
|
||||
struct drm_encoder encoder;
|
||||
|
||||
/* head is statically assigned on msto creation */
|
||||
struct nv50_head *head;
|
||||
struct nv50_mstc *mstc;
|
||||
bool disabled;
|
||||
@ -1056,11 +1088,12 @@ nv50_dp_bpc_to_depth(unsigned int bpc)
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_msto_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_msto_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nv50_head *head = nv50_head(encoder->crtc);
|
||||
struct nv50_head_atom *armh = nv50_head_atom(head->base.base.state);
|
||||
struct nv50_msto *msto = nv50_msto(encoder);
|
||||
struct nv50_head *head = msto->head;
|
||||
struct nv50_head_atom *asyh =
|
||||
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &head->base.base));
|
||||
struct nv50_mstc *mstc = NULL;
|
||||
struct nv50_mstm *mstm = NULL;
|
||||
struct drm_connector *connector;
|
||||
@ -1081,8 +1114,7 @@ nv50_msto_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
if (WARN_ON(!mstc))
|
||||
return;
|
||||
|
||||
r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, armh->dp.pbn,
|
||||
armh->dp.tu);
|
||||
r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, asyh->dp.pbn, asyh->dp.tu);
|
||||
if (!r)
|
||||
DRM_DEBUG_KMS("Failed to allocate VCPI\n");
|
||||
|
||||
@ -1094,15 +1126,15 @@ nv50_msto_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
else
|
||||
proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B;
|
||||
|
||||
mstm->outp->update(mstm->outp, head->base.index, armh, proto,
|
||||
nv50_dp_bpc_to_depth(armh->or.bpc));
|
||||
mstm->outp->update(mstm->outp, head->base.index, asyh, proto,
|
||||
nv50_dp_bpc_to_depth(asyh->or.bpc));
|
||||
|
||||
msto->mstc = mstc;
|
||||
mstm->modified = true;
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_msto_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_msto_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nv50_msto *msto = nv50_msto(encoder);
|
||||
struct nv50_mstc *mstc = msto->mstc;
|
||||
@ -1119,8 +1151,8 @@ nv50_msto_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
|
||||
static const struct drm_encoder_helper_funcs
|
||||
nv50_msto_help = {
|
||||
.atomic_disable = nv50_msto_disable,
|
||||
.atomic_enable = nv50_msto_enable,
|
||||
.atomic_disable = nv50_msto_atomic_disable,
|
||||
.atomic_enable = nv50_msto_atomic_enable,
|
||||
.atomic_check = nv50_msto_atomic_check,
|
||||
};
|
||||
|
||||
@ -1616,43 +1648,38 @@ nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_sor_disable(struct drm_encoder *encoder,
|
||||
struct drm_atomic_state *state)
|
||||
nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc);
|
||||
struct nouveau_connector *nv_connector =
|
||||
nv50_outp_get_old_connector(nv_encoder, state);
|
||||
struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder);
|
||||
struct drm_dp_aux *aux = &nv_connector->aux;
|
||||
u8 pwr;
|
||||
|
||||
nv_encoder->crtc = NULL;
|
||||
if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
|
||||
int ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr);
|
||||
|
||||
if (nv_crtc) {
|
||||
struct drm_dp_aux *aux = &nv_connector->aux;
|
||||
u8 pwr;
|
||||
|
||||
if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
|
||||
int ret = drm_dp_dpcd_readb(aux, DP_SET_POWER, &pwr);
|
||||
|
||||
if (ret == 0) {
|
||||
pwr &= ~DP_SET_POWER_MASK;
|
||||
pwr |= DP_SET_POWER_D3;
|
||||
drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr);
|
||||
}
|
||||
if (ret == 0) {
|
||||
pwr &= ~DP_SET_POWER_MASK;
|
||||
pwr |= DP_SET_POWER_D3;
|
||||
drm_dp_dpcd_writeb(aux, DP_SET_POWER, pwr);
|
||||
}
|
||||
|
||||
nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
|
||||
nv50_audio_disable(encoder, nv_crtc);
|
||||
nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
|
||||
nv50_outp_release(nv_encoder);
|
||||
}
|
||||
|
||||
nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0);
|
||||
nv50_audio_disable(encoder, nv_crtc);
|
||||
nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc);
|
||||
nv50_outp_release(nv_encoder);
|
||||
nv_encoder->crtc = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_sor_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state);
|
||||
struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder);
|
||||
struct nv50_head_atom *asyh =
|
||||
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base));
|
||||
struct drm_display_mode *mode = &asyh->state.adjusted_mode;
|
||||
struct {
|
||||
struct nv50_disp_mthd_v1 base;
|
||||
@ -1672,8 +1699,8 @@ nv50_sor_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM;
|
||||
u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT;
|
||||
|
||||
nv_connector = nv50_outp_get_new_connector(nv_encoder, state);
|
||||
nv_encoder->crtc = encoder->crtc;
|
||||
nv_connector = nv50_outp_get_new_connector(state, nv_encoder);
|
||||
nv_encoder->crtc = &nv_crtc->base;
|
||||
|
||||
if ((disp->disp->object.oclass == GT214_DISP ||
|
||||
disp->disp->object.oclass >= GF110_DISP) &&
|
||||
@ -1699,7 +1726,7 @@ nv50_sor_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B;
|
||||
}
|
||||
|
||||
nv50_hdmi_enable(&nv_encoder->base.base, state, mode);
|
||||
nv50_hdmi_enable(&nv_encoder->base.base, nv_crtc, nv_connector, state, mode);
|
||||
break;
|
||||
case DCB_OUTPUT_LVDS:
|
||||
proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM;
|
||||
@ -1740,7 +1767,7 @@ nv50_sor_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
else
|
||||
proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B;
|
||||
|
||||
nv50_audio_enable(encoder, state, mode);
|
||||
nv50_audio_enable(encoder, nv_crtc, nv_connector, state, mode);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -1753,8 +1780,8 @@ nv50_sor_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
static const struct drm_encoder_helper_funcs
|
||||
nv50_sor_help = {
|
||||
.atomic_check = nv50_outp_atomic_check,
|
||||
.atomic_enable = nv50_sor_enable,
|
||||
.atomic_disable = nv50_sor_disable,
|
||||
.atomic_enable = nv50_sor_atomic_enable,
|
||||
.atomic_disable = nv50_sor_atomic_disable,
|
||||
};
|
||||
|
||||
static void
|
||||
@ -1821,6 +1848,7 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
disp->core->func->sor->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1);
|
||||
nv50_outp_dump_caps(drm, nv_encoder);
|
||||
|
||||
if (dcbe->type == DCB_OUTPUT_DP) {
|
||||
struct nvkm_i2c_aux *aux =
|
||||
@ -1875,23 +1903,24 @@ nv50_pior_atomic_check(struct drm_encoder *encoder,
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_pior_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_pior_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nv50_core *core = nv50_disp(encoder->dev)->core;
|
||||
const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE);
|
||||
if (nv_encoder->crtc)
|
||||
core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL);
|
||||
|
||||
core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL);
|
||||
nv_encoder->crtc = NULL;
|
||||
nv50_outp_release(nv_encoder);
|
||||
}
|
||||
|
||||
static void
|
||||
nv50_pior_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
nv50_pior_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
{
|
||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
|
||||
struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state);
|
||||
struct nouveau_crtc *nv_crtc = nv50_outp_get_new_crtc(state, nv_encoder);
|
||||
struct nv50_head_atom *asyh =
|
||||
nv50_head_atom(drm_atomic_get_new_crtc_state(state, &nv_crtc->base));
|
||||
struct nv50_core *core = nv50_disp(encoder->dev)->core;
|
||||
u32 ctrl = 0;
|
||||
|
||||
@ -1929,8 +1958,8 @@ nv50_pior_enable(struct drm_encoder *encoder, struct drm_atomic_state *state)
|
||||
static const struct drm_encoder_helper_funcs
|
||||
nv50_pior_help = {
|
||||
.atomic_check = nv50_pior_atomic_check,
|
||||
.atomic_enable = nv50_pior_enable,
|
||||
.atomic_disable = nv50_pior_disable,
|
||||
.atomic_enable = nv50_pior_atomic_enable,
|
||||
.atomic_disable = nv50_pior_atomic_disable,
|
||||
};
|
||||
|
||||
static void
|
||||
@ -1991,6 +2020,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1);
|
||||
nv50_outp_dump_caps(drm, nv_encoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
|
||||
const int i = head->base.index;
|
||||
int ret;
|
||||
|
||||
if ((ret = PUSH_WAIT(push, 14)))
|
||||
if ((ret = PUSH_WAIT(push, 13)))
|
||||
return ret;
|
||||
|
||||
PUSH_MTHD(push, NV907D, HEAD_SET_OVERSCAN_COLOR(i),
|
||||
@ -353,14 +353,7 @@ head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
|
||||
PUSH_MTHD(push, NV907D, HEAD_SET_DEFAULT_BASE_COLOR(i),
|
||||
NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
|
||||
NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
|
||||
NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0),
|
||||
|
||||
HEAD_SET_CRC_CONTROL(i),
|
||||
NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) |
|
||||
NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
|
||||
NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) |
|
||||
NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, NONE) |
|
||||
NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE));
|
||||
NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0));
|
||||
|
||||
PUSH_MTHD(push, NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
|
||||
NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000) |
|
||||
|
@ -14,6 +14,7 @@ enum dcb_connector_type {
|
||||
DCB_CONNECTOR_LVDS_SPWG = 0x41,
|
||||
DCB_CONNECTOR_DP = 0x46,
|
||||
DCB_CONNECTOR_eDP = 0x47,
|
||||
DCB_CONNECTOR_mDP = 0x48,
|
||||
DCB_CONNECTOR_HDMI_0 = 0x60,
|
||||
DCB_CONNECTOR_HDMI_1 = 0x61,
|
||||
DCB_CONNECTOR_HDMI_C = 0x63,
|
||||
|
@ -533,6 +533,7 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
|
||||
if (ret) {
|
||||
NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret);
|
||||
nouveau_channel_del(pchan);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst);
|
||||
|
@ -1212,6 +1212,7 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
|
||||
case DCB_CONNECTOR_DMS59_DP0:
|
||||
case DCB_CONNECTOR_DMS59_DP1:
|
||||
case DCB_CONNECTOR_DP :
|
||||
case DCB_CONNECTOR_mDP :
|
||||
case DCB_CONNECTOR_USB_C : return DRM_MODE_CONNECTOR_DisplayPort;
|
||||
case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP;
|
||||
case DCB_CONNECTOR_HDMI_0 :
|
||||
|
@ -221,6 +221,7 @@ struct nouveau_drm {
|
||||
|
||||
struct {
|
||||
struct drm_audio_component *component;
|
||||
struct mutex lock;
|
||||
bool component_registered;
|
||||
} audio;
|
||||
};
|
||||
|
@ -53,7 +53,12 @@ struct nouveau_encoder {
|
||||
* actually programmed on the hw, not the proposed crtc */
|
||||
struct drm_crtc *crtc;
|
||||
u32 ctrl;
|
||||
bool audio;
|
||||
|
||||
/* Protected by nouveau_drm.audio.lock */
|
||||
struct {
|
||||
bool enabled;
|
||||
struct drm_connector *connector;
|
||||
} audio;
|
||||
|
||||
struct drm_display_mode mode;
|
||||
int last_dpms;
|
||||
@ -141,11 +146,9 @@ enum drm_mode_status nv50_dp_mode_valid(struct drm_connector *,
|
||||
unsigned *clock);
|
||||
|
||||
struct nouveau_connector *
|
||||
nv50_outp_get_new_connector(struct nouveau_encoder *outp,
|
||||
struct drm_atomic_state *state);
|
||||
nv50_outp_get_new_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp);
|
||||
struct nouveau_connector *
|
||||
nv50_outp_get_old_connector(struct nouveau_encoder *outp,
|
||||
struct drm_atomic_state *state);
|
||||
nv50_outp_get_old_connector(struct drm_atomic_state *state, struct nouveau_encoder *outp);
|
||||
|
||||
int nv50_mstm_detect(struct nouveau_encoder *encoder);
|
||||
void nv50_mstm_remove(struct nv50_mstm *mstm);
|
||||
|
@ -36,19 +36,7 @@
|
||||
#include <nvif/class.h>
|
||||
#include <nvif/cl0080.h>
|
||||
|
||||
struct gk104_fifo_engine_status {
|
||||
bool busy;
|
||||
bool faulted;
|
||||
bool chsw;
|
||||
bool save;
|
||||
bool load;
|
||||
struct {
|
||||
bool tsg;
|
||||
u32 id;
|
||||
} prev, next, *chan;
|
||||
};
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn,
|
||||
struct gk104_fifo_engine_status *status)
|
||||
{
|
||||
@ -95,7 +83,7 @@ gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn,
|
||||
status->chan == &status->next ? "*" : " ");
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
|
||||
void *argv, u32 argc, struct nvkm_object **pobject)
|
||||
{
|
||||
@ -112,7 +100,7 @@ gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
gk104_fifo_class_get(struct nvkm_fifo *base, int index,
|
||||
struct nvkm_oclass *oclass)
|
||||
{
|
||||
@ -134,14 +122,14 @@ gk104_fifo_class_get(struct nvkm_fifo *base, int index,
|
||||
return c;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_uevent_fini(struct nvkm_fifo *fifo)
|
||||
{
|
||||
struct nvkm_device *device = fifo->engine.subdev.device;
|
||||
nvkm_mask(device, 0x002140, 0x80000000, 0x00000000);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_uevent_init(struct nvkm_fifo *fifo)
|
||||
{
|
||||
struct nvkm_device *device = fifo->engine.subdev.device;
|
||||
@ -556,7 +544,7 @@ gk104_fifo_bind_reason[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_bind(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
@ -627,7 +615,7 @@ gk104_fifo_intr_sched(struct gk104_fifo *fifo)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_chsw(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
@ -637,7 +625,7 @@ gk104_fifo_intr_chsw(struct gk104_fifo *fifo)
|
||||
nvkm_wr32(device, 0x00256c, stat);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
@ -680,7 +668,7 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
@ -729,7 +717,7 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
@ -750,7 +738,7 @@ gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit)
|
||||
nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_runlist(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_device *device = fifo->base.engine.subdev.device;
|
||||
@ -763,7 +751,7 @@ gk104_fifo_intr_runlist(struct gk104_fifo *fifo)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_intr_engine(struct gk104_fifo *fifo)
|
||||
{
|
||||
nvkm_fifo_uevent(&fifo->base);
|
||||
@ -861,7 +849,7 @@ gk104_fifo_intr(struct nvkm_fifo *base)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_fini(struct nvkm_fifo *base)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
@ -871,7 +859,7 @@ gk104_fifo_fini(struct nvkm_fifo *base)
|
||||
nvkm_mask(device, 0x002140, 0x10000000, 0x10000000);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
@ -899,7 +887,7 @@ gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
gk104_fifo_oneinit(struct nvkm_fifo *base)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
@ -974,7 +962,7 @@ gk104_fifo_oneinit(struct nvkm_fifo *base)
|
||||
return nvkm_memory_map(fifo->user.mem, 0, bar, fifo->user.bar, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gk104_fifo_init(struct nvkm_fifo *base)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
@ -1006,7 +994,7 @@ gk104_fifo_init(struct nvkm_fifo *base)
|
||||
nvkm_wr32(device, 0x002140, 0x7fffffff);
|
||||
}
|
||||
|
||||
static void *
|
||||
void *
|
||||
gk104_fifo_dtor(struct nvkm_fifo *base)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
|
@ -87,11 +87,43 @@ struct gk104_fifo_func {
|
||||
bool cgrp_force;
|
||||
};
|
||||
|
||||
struct gk104_fifo_engine_status {
|
||||
bool busy;
|
||||
bool faulted;
|
||||
bool chsw;
|
||||
bool save;
|
||||
bool load;
|
||||
struct {
|
||||
bool tsg;
|
||||
u32 id;
|
||||
} prev, next, *chan;
|
||||
};
|
||||
|
||||
int gk104_fifo_new_(const struct gk104_fifo_func *, struct nvkm_device *,
|
||||
int index, int nr, struct nvkm_fifo **);
|
||||
void gk104_fifo_runlist_insert(struct gk104_fifo *, struct gk104_fifo_chan *);
|
||||
void gk104_fifo_runlist_remove(struct gk104_fifo *, struct gk104_fifo_chan *);
|
||||
void gk104_fifo_runlist_update(struct gk104_fifo *, int runl);
|
||||
void gk104_fifo_engine_status(struct gk104_fifo *fifo, int engn,
|
||||
struct gk104_fifo_engine_status *status);
|
||||
void gk104_fifo_intr_bind(struct gk104_fifo *fifo);
|
||||
void gk104_fifo_intr_chsw(struct gk104_fifo *fifo);
|
||||
void gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo);
|
||||
void gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit);
|
||||
void gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit);
|
||||
void gk104_fifo_intr_runlist(struct gk104_fifo *fifo);
|
||||
void gk104_fifo_intr_engine(struct gk104_fifo *fifo);
|
||||
void *gk104_fifo_dtor(struct nvkm_fifo *base);
|
||||
int gk104_fifo_oneinit(struct nvkm_fifo *base);
|
||||
int gk104_fifo_info(struct nvkm_fifo *base, u64 mthd, u64 *data);
|
||||
void gk104_fifo_init(struct nvkm_fifo *base);
|
||||
void gk104_fifo_fini(struct nvkm_fifo *base);
|
||||
int gk104_fifo_class_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
|
||||
void *argv, u32 argc, struct nvkm_object **pobject);
|
||||
int gk104_fifo_class_get(struct nvkm_fifo *base, int index,
|
||||
struct nvkm_oclass *oclass);
|
||||
void gk104_fifo_uevent_fini(struct nvkm_fifo *fifo);
|
||||
void gk104_fifo_uevent_init(struct nvkm_fifo *fifo);
|
||||
|
||||
extern const struct gk104_fifo_pbdma_func gk104_fifo_pbdma;
|
||||
int gk104_fifo_pbdma_nr(struct gk104_fifo *);
|
||||
|
@ -24,7 +24,13 @@
|
||||
#include "changk104.h"
|
||||
#include "user.h"
|
||||
|
||||
#include <core/client.h>
|
||||
#include <core/gpuobj.h>
|
||||
#include <subdev/bar.h>
|
||||
#include <subdev/fault.h>
|
||||
#include <subdev/top.h>
|
||||
#include <subdev/timer.h>
|
||||
#include <engine/sw.h>
|
||||
|
||||
#include <nvif/class.h>
|
||||
|
||||
@ -109,8 +115,364 @@ tu102_fifo = {
|
||||
.cgrp_force = true,
|
||||
};
|
||||
|
||||
static void
|
||||
tu102_fifo_recover_work(struct work_struct *w)
|
||||
{
|
||||
struct gk104_fifo *fifo = container_of(w, typeof(*fifo), recover.work);
|
||||
struct nvkm_device *device = fifo->base.engine.subdev.device;
|
||||
struct nvkm_engine *engine;
|
||||
unsigned long flags;
|
||||
u32 engm, runm, todo;
|
||||
int engn, runl;
|
||||
|
||||
spin_lock_irqsave(&fifo->base.lock, flags);
|
||||
runm = fifo->recover.runm;
|
||||
engm = fifo->recover.engm;
|
||||
fifo->recover.engm = 0;
|
||||
fifo->recover.runm = 0;
|
||||
spin_unlock_irqrestore(&fifo->base.lock, flags);
|
||||
|
||||
nvkm_mask(device, 0x002630, runm, runm);
|
||||
|
||||
for (todo = engm; engn = __ffs(todo), todo; todo &= ~BIT(engn)) {
|
||||
if ((engine = fifo->engine[engn].engine)) {
|
||||
nvkm_subdev_fini(&engine->subdev, false);
|
||||
WARN_ON(nvkm_subdev_init(&engine->subdev));
|
||||
}
|
||||
}
|
||||
|
||||
for (todo = runm; runl = __ffs(todo), todo; todo &= ~BIT(runl))
|
||||
gk104_fifo_runlist_update(fifo, runl);
|
||||
|
||||
nvkm_mask(device, 0x002630, runm, 0x00000000);
|
||||
}
|
||||
|
||||
static void tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn);
|
||||
|
||||
static void
|
||||
tu102_fifo_recover_runl(struct gk104_fifo *fifo, int runl)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
const u32 runm = BIT(runl);
|
||||
|
||||
assert_spin_locked(&fifo->base.lock);
|
||||
if (fifo->recover.runm & runm)
|
||||
return;
|
||||
fifo->recover.runm |= runm;
|
||||
|
||||
/* Block runlist to prevent channel assignment(s) from changing. */
|
||||
nvkm_mask(device, 0x002630, runm, runm);
|
||||
|
||||
/* Schedule recovery. */
|
||||
nvkm_warn(subdev, "runlist %d: scheduled for recovery\n", runl);
|
||||
schedule_work(&fifo->recover.work);
|
||||
}
|
||||
|
||||
static struct gk104_fifo_chan *
|
||||
tu102_fifo_recover_chid(struct gk104_fifo *fifo, int runl, int chid)
|
||||
{
|
||||
struct gk104_fifo_chan *chan;
|
||||
struct nvkm_fifo_cgrp *cgrp;
|
||||
|
||||
list_for_each_entry(chan, &fifo->runlist[runl].chan, head) {
|
||||
if (chan->base.chid == chid) {
|
||||
list_del_init(&chan->head);
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(cgrp, &fifo->runlist[runl].cgrp, head) {
|
||||
if (cgrp->id == chid) {
|
||||
chan = list_first_entry(&cgrp->chan, typeof(*chan), head);
|
||||
list_del_init(&chan->head);
|
||||
if (!--cgrp->chan_nr)
|
||||
list_del_init(&cgrp->head);
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_recover_chan(struct nvkm_fifo *base, int chid)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
const u32 stat = nvkm_rd32(device, 0x800004 + (chid * 0x08));
|
||||
const u32 runl = (stat & 0x000f0000) >> 16;
|
||||
const bool used = (stat & 0x00000001);
|
||||
unsigned long engn, engm = fifo->runlist[runl].engm;
|
||||
struct gk104_fifo_chan *chan;
|
||||
|
||||
assert_spin_locked(&fifo->base.lock);
|
||||
if (!used)
|
||||
return;
|
||||
|
||||
/* Lookup SW state for channel, and mark it as dead. */
|
||||
chan = tu102_fifo_recover_chid(fifo, runl, chid);
|
||||
if (chan) {
|
||||
chan->killed = true;
|
||||
nvkm_fifo_kevent(&fifo->base, chid);
|
||||
}
|
||||
|
||||
/* Disable channel. */
|
||||
nvkm_wr32(device, 0x800004 + (chid * 0x08), stat | 0x00000800);
|
||||
nvkm_warn(subdev, "channel %d: killed\n", chid);
|
||||
|
||||
/* Block channel assignments from changing during recovery. */
|
||||
tu102_fifo_recover_runl(fifo, runl);
|
||||
|
||||
/* Schedule recovery for any engines the channel is on. */
|
||||
for_each_set_bit(engn, &engm, fifo->engine_nr) {
|
||||
struct gk104_fifo_engine_status status;
|
||||
|
||||
gk104_fifo_engine_status(fifo, engn, &status);
|
||||
if (!status.chan || status.chan->id != chid)
|
||||
continue;
|
||||
tu102_fifo_recover_engn(fifo, engn);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_recover_engn(struct gk104_fifo *fifo, int engn)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
const u32 runl = fifo->engine[engn].runl;
|
||||
const u32 engm = BIT(engn);
|
||||
struct gk104_fifo_engine_status status;
|
||||
|
||||
assert_spin_locked(&fifo->base.lock);
|
||||
if (fifo->recover.engm & engm)
|
||||
return;
|
||||
fifo->recover.engm |= engm;
|
||||
|
||||
/* Block channel assignments from changing during recovery. */
|
||||
tu102_fifo_recover_runl(fifo, runl);
|
||||
|
||||
/* Determine which channel (if any) is currently on the engine. */
|
||||
gk104_fifo_engine_status(fifo, engn, &status);
|
||||
if (status.chan) {
|
||||
/* The channel is not longer viable, kill it. */
|
||||
tu102_fifo_recover_chan(&fifo->base, status.chan->id);
|
||||
}
|
||||
|
||||
/* Preempt the runlist */
|
||||
nvkm_wr32(device, 0x2638, BIT(runl));
|
||||
|
||||
/* Schedule recovery. */
|
||||
nvkm_warn(subdev, "engine %d: scheduled for recovery\n", engn);
|
||||
schedule_work(&fifo->recover.work);
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
const struct nvkm_enum *er, *ee, *ec, *ea;
|
||||
struct nvkm_engine *engine = NULL;
|
||||
struct nvkm_fifo_chan *chan;
|
||||
unsigned long flags;
|
||||
char ct[8] = "HUB/", en[16] = "";
|
||||
int engn;
|
||||
|
||||
er = nvkm_enum_find(fifo->func->fault.reason, info->reason);
|
||||
ee = nvkm_enum_find(fifo->func->fault.engine, info->engine);
|
||||
if (info->hub) {
|
||||
ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client);
|
||||
} else {
|
||||
ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client);
|
||||
snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
|
||||
}
|
||||
ea = nvkm_enum_find(fifo->func->fault.access, info->access);
|
||||
|
||||
if (ee && ee->data2) {
|
||||
switch (ee->data2) {
|
||||
case NVKM_SUBDEV_BAR:
|
||||
nvkm_bar_bar1_reset(device);
|
||||
break;
|
||||
case NVKM_SUBDEV_INSTMEM:
|
||||
nvkm_bar_bar2_reset(device);
|
||||
break;
|
||||
case NVKM_ENGINE_IFB:
|
||||
nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
|
||||
break;
|
||||
default:
|
||||
engine = nvkm_device_engine(device, ee->data2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ee == NULL) {
|
||||
enum nvkm_devidx engidx = nvkm_top_fault(device, info->engine);
|
||||
|
||||
if (engidx < NVKM_SUBDEV_NR) {
|
||||
const char *src = nvkm_subdev_name[engidx];
|
||||
char *dst = en;
|
||||
|
||||
do {
|
||||
*dst++ = toupper(*src++);
|
||||
} while (*src);
|
||||
engine = nvkm_device_engine(device, engidx);
|
||||
}
|
||||
} else {
|
||||
snprintf(en, sizeof(en), "%s", ee->name);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&fifo->base.lock, flags);
|
||||
chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst);
|
||||
|
||||
nvkm_error(subdev,
|
||||
"fault %02x [%s] at %016llx engine %02x [%s] client %02x "
|
||||
"[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
|
||||
info->access, ea ? ea->name : "", info->addr,
|
||||
info->engine, ee ? ee->name : en,
|
||||
info->client, ct, ec ? ec->name : "",
|
||||
info->reason, er ? er->name : "", chan ? chan->chid : -1,
|
||||
info->inst, chan ? chan->object.client->name : "unknown");
|
||||
|
||||
/* Kill the channel that caused the fault. */
|
||||
if (chan)
|
||||
tu102_fifo_recover_chan(&fifo->base, chan->chid);
|
||||
|
||||
/* Channel recovery will probably have already done this for the
|
||||
* correct engine(s), but just in case we can't find the channel
|
||||
* information...
|
||||
*/
|
||||
for (engn = 0; engn < fifo->engine_nr && engine; engn++) {
|
||||
if (fifo->engine[engn].engine == engine) {
|
||||
tu102_fifo_recover_engn(fifo, engn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fifo->base.lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_intr_ctxsw_timeout(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_device *device = fifo->base.engine.subdev.device;
|
||||
unsigned long flags, engm;
|
||||
u32 engn;
|
||||
|
||||
spin_lock_irqsave(&fifo->base.lock, flags);
|
||||
|
||||
engm = nvkm_rd32(device, 0x2a30);
|
||||
nvkm_wr32(device, 0x2a30, engm);
|
||||
|
||||
for_each_set_bit(engn, &engm, 32)
|
||||
tu102_fifo_recover_engn(fifo, engn);
|
||||
|
||||
spin_unlock_irqrestore(&fifo->base.lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_intr_sched(struct gk104_fifo *fifo)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
u32 intr = nvkm_rd32(device, 0x00254c);
|
||||
u32 code = intr & 0x000000ff;
|
||||
|
||||
nvkm_error(subdev, "SCHED_ERROR %02x\n", code);
|
||||
}
|
||||
|
||||
static void
|
||||
tu102_fifo_intr(struct nvkm_fifo *base)
|
||||
{
|
||||
struct gk104_fifo *fifo = gk104_fifo(base);
|
||||
struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
|
||||
struct nvkm_device *device = subdev->device;
|
||||
u32 mask = nvkm_rd32(device, 0x002140);
|
||||
u32 stat = nvkm_rd32(device, 0x002100) & mask;
|
||||
|
||||
if (stat & 0x00000001) {
|
||||
gk104_fifo_intr_bind(fifo);
|
||||
nvkm_wr32(device, 0x002100, 0x00000001);
|
||||
stat &= ~0x00000001;
|
||||
}
|
||||
|
||||
if (stat & 0x00000002) {
|
||||
tu102_fifo_intr_ctxsw_timeout(fifo);
|
||||
stat &= ~0x00000002;
|
||||
}
|
||||
|
||||
if (stat & 0x00000100) {
|
||||
tu102_fifo_intr_sched(fifo);
|
||||
nvkm_wr32(device, 0x002100, 0x00000100);
|
||||
stat &= ~0x00000100;
|
||||
}
|
||||
|
||||
if (stat & 0x00010000) {
|
||||
gk104_fifo_intr_chsw(fifo);
|
||||
nvkm_wr32(device, 0x002100, 0x00010000);
|
||||
stat &= ~0x00010000;
|
||||
}
|
||||
|
||||
if (stat & 0x20000000) {
|
||||
u32 mask = nvkm_rd32(device, 0x0025a0);
|
||||
|
||||
while (mask) {
|
||||
u32 unit = __ffs(mask);
|
||||
|
||||
gk104_fifo_intr_pbdma_0(fifo, unit);
|
||||
gk104_fifo_intr_pbdma_1(fifo, unit);
|
||||
nvkm_wr32(device, 0x0025a0, (1 << unit));
|
||||
mask &= ~(1 << unit);
|
||||
}
|
||||
stat &= ~0x20000000;
|
||||
}
|
||||
|
||||
if (stat & 0x40000000) {
|
||||
gk104_fifo_intr_runlist(fifo);
|
||||
stat &= ~0x40000000;
|
||||
}
|
||||
|
||||
if (stat & 0x80000000) {
|
||||
nvkm_wr32(device, 0x002100, 0x80000000);
|
||||
gk104_fifo_intr_engine(fifo);
|
||||
stat &= ~0x80000000;
|
||||
}
|
||||
|
||||
if (stat) {
|
||||
nvkm_error(subdev, "INTR %08x\n", stat);
|
||||
nvkm_mask(device, 0x002140, stat, 0x00000000);
|
||||
nvkm_wr32(device, 0x002100, stat);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct nvkm_fifo_func
|
||||
tu102_fifo_ = {
|
||||
.dtor = gk104_fifo_dtor,
|
||||
.oneinit = gk104_fifo_oneinit,
|
||||
.info = gk104_fifo_info,
|
||||
.init = gk104_fifo_init,
|
||||
.fini = gk104_fifo_fini,
|
||||
.intr = tu102_fifo_intr,
|
||||
.fault = tu102_fifo_fault,
|
||||
.uevent_init = gk104_fifo_uevent_init,
|
||||
.uevent_fini = gk104_fifo_uevent_fini,
|
||||
.recover_chan = tu102_fifo_recover_chan,
|
||||
.class_get = gk104_fifo_class_get,
|
||||
.class_new = gk104_fifo_class_new,
|
||||
};
|
||||
|
||||
int
|
||||
tu102_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo)
|
||||
{
|
||||
return gk104_fifo_new_(&tu102_fifo, device, index, 4096, pfifo);
|
||||
struct gk104_fifo *fifo;
|
||||
|
||||
if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
fifo->func = &tu102_fifo;
|
||||
INIT_WORK(&fifo->recover.work, tu102_fifo_recover_work);
|
||||
*pfifo = &fifo->base;
|
||||
|
||||
return nvkm_fifo_ctor(&tu102_fifo_, device, index, 4096, &fifo->base);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "priv.h"
|
||||
|
||||
#include <core/memory.h>
|
||||
#include <subdev/mc.h>
|
||||
#include <subdev/mmu.h>
|
||||
#include <engine/fifo.h>
|
||||
|
||||
@ -34,6 +35,9 @@ tu102_fault_buffer_intr(struct nvkm_fault_buffer *buffer, bool enable)
|
||||
* which don't appear to actually work anymore, but newer
|
||||
* versions of RM don't appear to touch anything at all..
|
||||
*/
|
||||
struct nvkm_device *device = buffer->fault->subdev.device;
|
||||
|
||||
nvkm_mc_intr_mask(device, NVKM_SUBDEV_FAULT, enable);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -41,6 +45,11 @@ tu102_fault_buffer_fini(struct nvkm_fault_buffer *buffer)
|
||||
{
|
||||
struct nvkm_device *device = buffer->fault->subdev.device;
|
||||
const u32 foff = buffer->id * 0x20;
|
||||
|
||||
/* Disable the fault interrupts */
|
||||
nvkm_wr32(device, 0xb81408, 0x1);
|
||||
nvkm_wr32(device, 0xb81410, 0x10);
|
||||
|
||||
nvkm_mask(device, 0xb83010 + foff, 0x80000000, 0x00000000);
|
||||
}
|
||||
|
||||
@ -50,6 +59,10 @@ tu102_fault_buffer_init(struct nvkm_fault_buffer *buffer)
|
||||
struct nvkm_device *device = buffer->fault->subdev.device;
|
||||
const u32 foff = buffer->id * 0x20;
|
||||
|
||||
/* Enable the fault interrupts */
|
||||
nvkm_wr32(device, 0xb81208, 0x1);
|
||||
nvkm_wr32(device, 0xb81210, 0x10);
|
||||
|
||||
nvkm_mask(device, 0xb83010 + foff, 0xc0000000, 0x40000000);
|
||||
nvkm_wr32(device, 0xb83004 + foff, upper_32_bits(buffer->addr));
|
||||
nvkm_wr32(device, 0xb83000 + foff, lower_32_bits(buffer->addr));
|
||||
@ -109,14 +122,20 @@ tu102_fault_intr(struct nvkm_fault *fault)
|
||||
}
|
||||
|
||||
if (stat & 0x00000200) {
|
||||
/* Clear the associated interrupt flag */
|
||||
nvkm_wr32(device, 0xb81010, 0x10);
|
||||
|
||||
if (fault->buffer[0]) {
|
||||
nvkm_event_send(&fault->event, 1, 0, NULL, 0);
|
||||
stat &= ~0x00000200;
|
||||
}
|
||||
}
|
||||
|
||||
/*XXX: guess, can't confirm until we get fw... */
|
||||
/* Replayable MMU fault */
|
||||
if (stat & 0x00000100) {
|
||||
/* Clear the associated interrupt flag */
|
||||
nvkm_wr32(device, 0xb81008, 0x1);
|
||||
|
||||
if (fault->buffer[1]) {
|
||||
nvkm_event_send(&fault->event, 1, 1, NULL, 0);
|
||||
stat &= ~0x00000100;
|
||||
|
@ -108,9 +108,6 @@ nvkm_mc_intr(struct nvkm_device *device, bool *handled)
|
||||
if (stat)
|
||||
nvkm_error(&mc->subdev, "intr %08x\n", stat);
|
||||
*handled = intr != 0;
|
||||
|
||||
if (mc->func->intr_hack)
|
||||
mc->func->intr_hack(mc, handled);
|
||||
}
|
||||
|
||||
static u32
|
||||
|
@ -26,7 +26,6 @@ struct nvkm_mc_func {
|
||||
void (*intr_mask)(struct nvkm_mc *, u32 mask, u32 stat);
|
||||
/* retrieve pending interrupt mask (NV_PMC_INTR) */
|
||||
u32 (*intr_stat)(struct nvkm_mc *);
|
||||
void (*intr_hack)(struct nvkm_mc *, bool *handled);
|
||||
const struct nvkm_mc_map *reset;
|
||||
void (*unk260)(struct nvkm_mc *, u32);
|
||||
};
|
||||
|
@ -19,37 +19,118 @@
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#define tu102_mc(p) container_of((p), struct tu102_mc, base)
|
||||
#include "priv.h"
|
||||
|
||||
struct tu102_mc {
|
||||
struct nvkm_mc base;
|
||||
spinlock_t lock;
|
||||
bool intr;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
static void
|
||||
tu102_mc_intr_hack(struct nvkm_mc *mc, bool *handled)
|
||||
tu102_mc_intr_update(struct tu102_mc *mc)
|
||||
{
|
||||
struct nvkm_device *device = mc->base.subdev.device;
|
||||
u32 mask = mc->intr ? mc->mask : 0, i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
nvkm_wr32(device, 0x000180 + (i * 0x04), ~mask);
|
||||
nvkm_wr32(device, 0x000160 + (i * 0x04), mask);
|
||||
}
|
||||
|
||||
if (mask & 0x00000200)
|
||||
nvkm_wr32(device, 0xb81608, 0x6);
|
||||
else
|
||||
nvkm_wr32(device, 0xb81610, 0x6);
|
||||
}
|
||||
|
||||
void
|
||||
tu102_mc_intr_unarm(struct nvkm_mc *base)
|
||||
{
|
||||
struct tu102_mc *mc = tu102_mc(base);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mc->lock, flags);
|
||||
mc->intr = false;
|
||||
tu102_mc_intr_update(mc);
|
||||
spin_unlock_irqrestore(&mc->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
tu102_mc_intr_rearm(struct nvkm_mc *base)
|
||||
{
|
||||
struct tu102_mc *mc = tu102_mc(base);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mc->lock, flags);
|
||||
mc->intr = true;
|
||||
tu102_mc_intr_update(mc);
|
||||
spin_unlock_irqrestore(&mc->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
tu102_mc_intr_mask(struct nvkm_mc *base, u32 mask, u32 intr)
|
||||
{
|
||||
struct tu102_mc *mc = tu102_mc(base);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mc->lock, flags);
|
||||
mc->mask = (mc->mask & ~mask) | intr;
|
||||
tu102_mc_intr_update(mc);
|
||||
spin_unlock_irqrestore(&mc->lock, flags);
|
||||
}
|
||||
|
||||
static u32
|
||||
tu102_mc_intr_stat(struct nvkm_mc *mc)
|
||||
{
|
||||
struct nvkm_device *device = mc->subdev.device;
|
||||
u32 stat = nvkm_rd32(device, 0xb81010);
|
||||
if (stat & 0x00000050) {
|
||||
struct nvkm_subdev *subdev =
|
||||
nvkm_device_subdev(device, NVKM_SUBDEV_FAULT);
|
||||
nvkm_wr32(device, 0xb81010, stat & 0x00000050);
|
||||
if (subdev)
|
||||
nvkm_subdev_intr(subdev);
|
||||
*handled = true;
|
||||
}
|
||||
u32 intr0 = nvkm_rd32(device, 0x000100);
|
||||
u32 intr1 = nvkm_rd32(device, 0x000104);
|
||||
u32 intr_top = nvkm_rd32(device, 0xb81600);
|
||||
|
||||
/* Turing and above route the MMU fault interrupts via a different
|
||||
* interrupt tree with different control registers. For the moment remap
|
||||
* them back to the old PMC vector.
|
||||
*/
|
||||
if (intr_top & 0x00000006)
|
||||
intr0 |= 0x00000200;
|
||||
|
||||
return intr0 | intr1;
|
||||
}
|
||||
|
||||
|
||||
static const struct nvkm_mc_func
|
||||
tu102_mc = {
|
||||
.init = nv50_mc_init,
|
||||
.intr = gp100_mc_intr,
|
||||
.intr_unarm = gp100_mc_intr_unarm,
|
||||
.intr_rearm = gp100_mc_intr_rearm,
|
||||
.intr_mask = gp100_mc_intr_mask,
|
||||
.intr_stat = gf100_mc_intr_stat,
|
||||
.intr_hack = tu102_mc_intr_hack,
|
||||
.intr_unarm = tu102_mc_intr_unarm,
|
||||
.intr_rearm = tu102_mc_intr_rearm,
|
||||
.intr_mask = tu102_mc_intr_mask,
|
||||
.intr_stat = tu102_mc_intr_stat,
|
||||
.reset = gk104_mc_reset,
|
||||
};
|
||||
|
||||
int
|
||||
tu102_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device,
|
||||
int index, struct nvkm_mc **pmc)
|
||||
{
|
||||
struct tu102_mc *mc;
|
||||
|
||||
if (!(mc = kzalloc(sizeof(*mc), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
nvkm_mc_ctor(func, device, index, &mc->base);
|
||||
*pmc = &mc->base;
|
||||
|
||||
spin_lock_init(&mc->lock);
|
||||
mc->intr = false;
|
||||
mc->mask = 0x7fffffff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tu102_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc)
|
||||
{
|
||||
return gp100_mc_new_(&tu102_mc, device, index, pmc);
|
||||
return tu102_mc_new_(&tu102_mc, device, index, pmc);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user