Commit ef16dc27 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/gr/gf100-: select implementation based on available FW



This will allow for further customisation of the subdev depending on what
firmware is available.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent a096ff19
Loading
Loading
Loading
Loading
+67 −89
Original line number Diff line number Diff line
@@ -2055,86 +2055,8 @@ gf100_gr_ = {
};

int
gf100_gr_ctor_fw_legacy(struct gf100_gr *gr, const char *fwname,
			struct nvkm_blob *fuc, int ret)
{
	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
	const struct firmware *fw;
	char f[32];

	/* see if this firmware has a legacy path */
	if (!strcmp(fwname, "fecs_inst"))
		fwname = "fuc409c";
	else if (!strcmp(fwname, "fecs_data"))
		fwname = "fuc409d";
	else if (!strcmp(fwname, "gpccs_inst"))
		fwname = "fuc41ac";
	else if (!strcmp(fwname, "gpccs_data"))
		fwname = "fuc41ad";
	else {
		/* nope, let's just return the error we got */
		nvkm_error(subdev, "failed to load %s\n", fwname);
		return ret;
	}

	/* yes, try to load from the legacy path */
	nvkm_debug(subdev, "%s: falling back to legacy path\n", fwname);

	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
	ret = request_firmware(&fw, f, device->dev);
	if (ret) {
		snprintf(f, sizeof(f), "nouveau/%s", fwname);
		ret = request_firmware(&fw, f, device->dev);
		if (ret) {
			nvkm_error(subdev, "failed to load %s\n", fwname);
			return ret;
		}
	}

	fuc->size = fw->size;
	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
	release_firmware(fw);
	return (fuc->data != NULL) ? 0 : -ENOMEM;
}

int
gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname,
		 struct nvkm_blob *fuc)
{
	const struct firmware *fw;
	int ret;

	ret = nvkm_firmware_get(&gr->base.engine.subdev, fwname, &fw);
	if (ret) {
		ret = gf100_gr_ctor_fw_legacy(gr, fwname, fuc, ret);
		if (ret)
			return -ENODEV;
		return 0;
	}

	fuc->size = fw->size;
	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
	nvkm_firmware_put(fw);
	return (fuc->data != NULL) ? 0 : -ENOMEM;
}

int
gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device,
	      int index, struct gf100_gr *gr)
{
	gr->func = func;
	gr->firmware = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
				    func->fecs.ucode == NULL);

	return nvkm_gr_ctor(&gf100_gr_, device, index,
			    gr->firmware || func->fecs.ucode != NULL,
			    &gr->base);
}

int
gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
	      int index, struct nvkm_gr **pgr)
gf100_gr_new_(const struct gf100_gr_fwif *fwif,
	      struct nvkm_device *device, int index, struct nvkm_gr **pgr)
{
	struct gf100_gr *gr;
	int ret;
@@ -2143,18 +2065,15 @@ gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
		return -ENOMEM;
	*pgr = &gr->base;

	ret = gf100_gr_ctor(func, device, index, gr);
	ret = nvkm_gr_ctor(&gf100_gr_, device, index, true, &gr->base);
	if (ret)
		return ret;

	if (gr->firmware) {
		if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fecs.inst) ||
		    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fecs.data) ||
		    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->gpccs.inst) ||
		    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->gpccs.data))
	fwif = nvkm_firmware_load(&gr->base.engine.subdev, fwif, "Gr", gr);
	if (IS_ERR(fwif))
		return -ENODEV;
	}

	gr->func = fwif->func;
	return 0;
}

@@ -2457,8 +2376,67 @@ gf100_gr = {
	}
};

int
gf100_gr_nofw(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif)
{
	gr->firmware = false;
	return 0;
}

static int
gf100_gr_load_fw(struct gf100_gr *gr, const char *name,
		 struct nvkm_blob *blob)
{
	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
	const struct firmware *fw;
	char f[32];
	int ret;

	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, name);
	ret = request_firmware(&fw, f, device->dev);
	if (ret) {
		snprintf(f, sizeof(f), "nouveau/%s", name);
		ret = request_firmware(&fw, f, device->dev);
		if (ret) {
			nvkm_error(subdev, "failed to load %s\n", name);
			return ret;
		}
	}

	blob->size = fw->size;
	blob->data = kmemdup(fw->data, blob->size, GFP_KERNEL);
	release_firmware(fw);
	return (blob->data != NULL) ? 0 : -ENOMEM;
}

int
gf100_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif)
{
	struct nvkm_device *device = gr->base.engine.subdev.device;

	if (!nvkm_boolopt(device->cfgopt, "NvGrUseFW", false))
		return -EINVAL;

	if (gf100_gr_load_fw(gr, "fuc409c", &gr->fecs.inst) ||
	    gf100_gr_load_fw(gr, "fuc409d", &gr->fecs.data) ||
	    gf100_gr_load_fw(gr, "fuc41ac", &gr->gpccs.inst) ||
	    gf100_gr_load_fw(gr, "fuc41ad", &gr->gpccs.data))
		return -ENOENT;

	gr->firmware = true;
	return 0;
}

static const struct gf100_gr_fwif
gf100_gr_fwif[] = {
	{ -1, gf100_gr_load, &gf100_gr },
	{ -1, gf100_gr_nofw, &gf100_gr },
	{}
};

int
gf100_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
{
	return gf100_gr_new_(&gf100_gr, device, index, pgr);
	return gf100_gr_new_(gf100_gr_fwif, device, index, pgr);
}
+25 −13
Original line number Diff line number Diff line
@@ -136,12 +136,6 @@ struct gf100_gr {
	u32 size_pm;
};

int gf100_gr_ctor(const struct gf100_gr_func *, struct nvkm_device *,
		  int, struct gf100_gr *);
int gf100_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
		  int, struct nvkm_gr **);
void *gf100_gr_dtor(struct nvkm_gr *);

int gf100_gr_fecs_bind_pointer(struct gf100_gr *, u32 inst);

struct gf100_gr_func_zbc {
@@ -247,8 +241,6 @@ extern const struct gf100_gr_func_zbc gp102_gr_zbc;

extern const struct gf100_gr_func gp107_gr;

int gk20a_gr_load_sw(struct gf100_gr *, const char *path, int ver);

#define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object)
#include <core/object.h>

@@ -269,8 +261,6 @@ struct gf100_gr_chan {

void gf100_gr_ctxctl_debug(struct gf100_gr *);

int  gf100_gr_ctor_fw(struct gf100_gr *, const char *,
		      struct nvkm_blob *);
u64  gf100_gr_units(struct nvkm_gr *);
void gf100_gr_zbc_init(struct gf100_gr *);

@@ -309,9 +299,6 @@ void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *);
void gf100_gr_mthd(struct gf100_gr *, const struct gf100_gr_pack *);
int  gf100_gr_init_ctxctl(struct gf100_gr *);

int gm200_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, int,
		  struct nvkm_gr **);

/* register init value lists */

extern const struct gf100_gr_init gf100_gr_init_main_0[];
@@ -394,4 +381,29 @@ extern const struct gf100_gr_init gm107_gr_init_cbm_0[];
void gm107_gr_init_bios(struct gf100_gr *);

void gm200_gr_init_gpc_mmu(struct gf100_gr *);

struct gf100_gr_fwif {
	int version;
	int (*load)(struct gf100_gr *, int ver, const struct gf100_gr_fwif *);
	const struct gf100_gr_func *func;
	const struct nvkm_acr_lsf_func *fecs;
	const struct nvkm_acr_lsf_func *gpccs;
};

int gf100_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *);
int gf100_gr_nofw(struct gf100_gr *, int, const struct gf100_gr_fwif *);

int gk20a_gr_load_sw(struct gf100_gr *, const char *path, int ver);

int gm200_gr_load(struct gf100_gr *, int, const struct gf100_gr_fwif *);
extern const struct nvkm_acr_lsf_func gm200_gr_gpccs_acr;
extern const struct nvkm_acr_lsf_func gm200_gr_fecs_acr;

extern const struct nvkm_acr_lsf_func gm20b_gr_fecs_acr;

extern const struct nvkm_acr_lsf_func gp108_gr_gpccs_acr;
extern const struct nvkm_acr_lsf_func gp108_gr_fecs_acr;

int gf100_gr_new_(const struct gf100_gr_fwif *, struct nvkm_device *, int,
		  struct nvkm_gr **);
#endif
+8 −1
Original line number Diff line number Diff line
@@ -144,8 +144,15 @@ gf104_gr = {
	}
};

static const struct gf100_gr_fwif
gf104_gr_fwif[] = {
	{ -1, gf100_gr_load, &gf104_gr },
	{ -1, gf100_gr_nofw, &gf104_gr },
	{}
};

int
gf104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
{
	return gf100_gr_new_(&gf104_gr, device, index, pgr);
	return gf100_gr_new_(gf104_gr_fwif, device, index, pgr);
}
+8 −1
Original line number Diff line number Diff line
@@ -143,8 +143,15 @@ gf108_gr = {
	}
};

const struct gf100_gr_fwif
gf108_gr_fwif[] = {
	{ -1, gf100_gr_load, &gf108_gr },
	{ -1, gf100_gr_nofw, &gf108_gr },
	{}
};

int
gf108_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
{
	return gf100_gr_new_(&gf108_gr, device, index, pgr);
	return gf100_gr_new_(gf108_gr_fwif, device, index, pgr);
}
+8 −1
Original line number Diff line number Diff line
@@ -119,8 +119,15 @@ gf110_gr = {
	}
};

static const struct gf100_gr_fwif
gf110_gr_fwif[] = {
	{ -1, gf100_gr_load, &gf110_gr },
	{ -1, gf100_gr_nofw, &gf110_gr },
	{}
};

int
gf110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
{
	return gf100_gr_new_(&gf110_gr, device, index, pgr);
	return gf100_gr_new_(gf110_gr_fwif, device, index, pgr);
}
Loading