Пример #1
0
int
nouveau_therm_fan_set_mode(struct nouveau_therm *therm,
			   enum nouveau_therm_fan_mode mode)
{
	struct nouveau_therm_priv *priv = (void *)therm;

	if (priv->fan.mode == mode)
		return 0;

	if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR)
		return -EINVAL;

	switch (mode)
	{
	case FAN_CONTROL_NONE:
		nv_info(therm, "switch fan to no-control mode\n");
		break;
	case FAN_CONTROL_MANUAL:
		nv_info(therm, "switch fan to manual mode\n");
		break;
	case FAN_CONTROL_NR:
		break;
	}

	priv->fan.mode = mode;
	return 0;
}
Пример #2
0
void nouveau_therm_sensor_event(struct nouveau_therm *therm,
			        enum nouveau_therm_thrs thrs,
			        enum nouveau_therm_thrs_direction dir)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	bool active;
	const char *thresolds[] = {
		"fanboost", "downclock", "critical", "shutdown"
	};
	int temperature = therm->temp_get(therm);

	if (thrs < 0 || thrs > 3)
		return;

	if (dir == NOUVEAU_THERM_THRS_FALLING)
		nv_info(therm, "temperature (%i C) went below the '%s' threshold\n",
			temperature, thresolds[thrs]);
	else
		nv_info(therm, "temperature (%i C) hit the '%s' threshold\n",
			temperature, thresolds[thrs]);

	active = (dir == NOUVEAU_THERM_THRS_RISING);
	switch (thrs) {
	case NOUVEAU_THERM_THRS_FANBOOST:
		if (active) {
			nouveau_therm_fan_set(therm, true, 100);
			nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
		}
		break;
	case NOUVEAU_THERM_THRS_DOWNCLOCK:
		if (priv->emergency.downclock)
			priv->emergency.downclock(therm, active);
		break;
	case NOUVEAU_THERM_THRS_CRITICAL:
		if (priv->emergency.pause)
			priv->emergency.pause(therm, active);
		break;
	case NOUVEAU_THERM_THRS_SHUTDOWN:
		if (active) {
			struct work_struct *work;

			work = kmalloc(sizeof(*work), GFP_ATOMIC);
			if (work) {
				INIT_WORK(work, nv_poweroff_work);
				schedule_work(work);
			}
		}
		break;
	case NOUVEAU_THERM_THRS_NR:
		break;
	}

}
Пример #3
0
void
nv50_mpeg_intr(struct nvkm_subdev *subdev)
{
	struct nv50_mpeg_priv *priv = (void *)subdev;
	u32 stat = nv_rd32(priv, 0x00b100);
	u32 type = nv_rd32(priv, 0x00b230);
	u32 mthd = nv_rd32(priv, 0x00b234);
	u32 data = nv_rd32(priv, 0x00b238);
	u32 show = stat;

	if (stat & 0x01000000) {
		/* happens on initial binding of the object */
		if (type == 0x00000020 && mthd == 0x0000) {
			nv_wr32(priv, 0x00b308, 0x00000100);
			show &= ~0x01000000;
		}
	}

	if (show) {
		nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
			stat, type, mthd, data);
	}

	nv_wr32(priv, 0x00b100, stat);
	nv_wr32(priv, 0x00b230, 0x00000001);
}
Пример #4
0
int
nouveau_fb_created(struct nouveau_fb *pfb)
{
	static const char *name[] = {
		[NV_MEM_TYPE_UNKNOWN] = "unknown",
		[NV_MEM_TYPE_STOLEN ] = "stolen system memory",
		[NV_MEM_TYPE_SGRAM  ] = "SGRAM",
		[NV_MEM_TYPE_SDRAM  ] = "SDRAM",
		[NV_MEM_TYPE_DDR1   ] = "DDR1",
		[NV_MEM_TYPE_DDR2   ] = "DDR2",
		[NV_MEM_TYPE_DDR3   ] = "DDR3",
		[NV_MEM_TYPE_GDDR2  ] = "GDDR2",
		[NV_MEM_TYPE_GDDR3  ] = "GDDR3",
		[NV_MEM_TYPE_GDDR4  ] = "GDDR4",
		[NV_MEM_TYPE_GDDR5  ] = "GDDR5",
	};

	if (pfb->ram.size == 0) {
		nv_fatal(pfb, "no vram detected!!\n");
		return -ERANGE;
	}

	nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
	nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
	return 0;
}
Пример #5
0
static bool
probe_monitoring_device(struct nouveau_i2c_port *i2c,
			struct i2c_board_info *info, void *data)
{
	struct nouveau_therm_priv *priv = data;
	struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
	struct i2c_client *client;

	request_module("%s%s", I2C_MODULE_PREFIX, info->type);

	client = i2c_new_device(&i2c->adapter, info);
	if (!client)
		return false;

	if (!client->dev.driver ||
	    to_i2c_driver(client->dev.driver)->detect(client, info)) {
		i2c_unregister_device(client);
		return false;
	}

	nv_info(priv,
		"Found an %s at address 0x%x (controlled by lm_sensors, "
		"temp offset %+i C)\n",
		info->type, info->addr, sensor->offset_constant);
	priv->ic = client;

	return true;
}
Пример #6
0
int
nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
{
    struct nouveau_therm_priv *priv = (void *)therm;
    struct nouveau_device *device = nv_device(therm);
    static const char *name[] = {
        "disabled",
        "manual",
        "automatic"
    };

    /* The default PDAEMON ucode interferes with fan management */
    if ((mode >= ARRAY_SIZE(name)) ||
            (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0))
        return -EINVAL;

    /* do not allow automatic fan management if the thermal sensor is
     * not available */
    if (priv->mode == 2 && therm->temp_get(therm) < 0)
        return -EINVAL;

    if (priv->mode == mode)
        return 0;

    nv_info(therm, "fan management: %s\n", name[mode]);
    nouveau_therm_update(therm, mode);
    return 0;
}
Пример #7
0
int
nouveau_therm_fan_ctor(struct nouveau_therm *therm)
{
	struct nouveau_therm_priv *priv = (void *)therm;
	struct nouveau_gpio *gpio = nouveau_gpio(therm);
	struct nouveau_bios *bios = nouveau_bios(therm);
	struct dcb_gpio_func func;
	int ret;

	/* attempt to locate a drivable fan, and determine control method */
	ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
	if (ret == 0) {
		/* FIXME: is this really the place to perform such checks ? */
		if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
			nv_debug(therm, "GPIO_FAN is in input mode\n");
			ret = -EINVAL;
		} else {
			ret = nouveau_fanpwm_create(therm, &func);
			if (ret != 0)
				ret = nouveau_fantog_create(therm, &func);
		}
	}

	/* no controllable fan found, create a dummy fan module */
	if (ret != 0) {
		ret = nouveau_fannil_create(therm);
		if (ret)
			return ret;
	}

	nv_info(therm, "FAN control: %s\n", priv->fan->type);

	/* read the current speed, it is useful when resuming */
	priv->fan->percent = nouveau_therm_fan_get(therm);

	/* attempt to detect a tachometer connection */
	ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
	if (ret)
		priv->fan->tach.func = DCB_GPIO_UNUSED;

	/* initialise fan bump/slow update handling */
	priv->fan->parent = therm;
	nouveau_alarm_init(&priv->fan->alarm, nouveau_fan_alarm);
	spin_lock_init(&priv->fan->lock);

	/* other random init... */
	nouveau_therm_fan_set_defaults(therm);
	nvbios_perf_fan_parse(bios, &priv->fan->perf);
	if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
		nv_debug(therm, "parsing the fan table failed\n");
		if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
			nv_error(therm, "parsing both fan tables failed\n");
	}
	nouveau_therm_fan_safety_checks(therm);
	return 0;
}
Пример #8
0
void
nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
{
	const char *sensor_avail = "yes";

	if (therm->temp_get(therm) < 0)
		sensor_avail = "no";

	nv_info(therm, "internal sensor: %s\n", sensor_avail);
}
Пример #9
0
static int
nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)
{
	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,
			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;
	}

	nv_info(bios, "... appears to be valid\n");
	return 3;
}
Пример #10
0
static void
gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
{
	u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
	u32 stat = nv_rd32(priv, base + 0x00c);

	if (stat) {
		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
		nv_wr32(priv, base + 0x00c, stat);
	}
}
Пример #11
0
static void
nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp)
{
	u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400);
	u32 stat = nv_rd32(priv, subp_base + 0x020);

	if (stat) {
		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat);
		nv_wr32(priv, subp_base + 0x020, stat);
	}
}
Пример #12
0
static void
gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts)
{
	u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
	u32 stat = nv_rd32(priv, base + 0x020);

	if (stat) {
		nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
		nv_wr32(priv, base + 0x020, stat);
	}
}
Пример #13
0
static void
nv50_vpe_intr(struct nvkm_subdev *subdev)
{
	struct nv50_mpeg_priv *priv = (void *)subdev;

	if (nv_rd32(priv, 0x00b100))
		nv50_mpeg_intr(subdev);

	if (nv_rd32(priv, 0x00b800)) {
		u32 stat = nv_rd32(priv, 0x00b800);
		nv_info(priv, "PMSRCH: 0x%08x\n", stat);
		nv_wr32(priv, 0xb800, stat);
	}
}
Пример #14
0
static void
gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
{
	u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
	u32 intr = nv_rd32(priv, base + 0x020);
	u32 stat = intr & 0x0000ffff;

	if (stat) {
		nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
		nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat);
		pr_cont("\n");
	}

	nv_wr32(priv, base + 0x020, intr);
}
Пример #15
0
static unsigned long
get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info)
{
	struct nouveau_device *device = nv_device(drm->device);
	struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list;
	int agpmode = nouveau_agpmode;
	unsigned long mode = info->mode;

	/*
	 * FW seems to be broken on nv18, it makes the card lock up
	 * randomly.
	 */
	if (device->chipset == 0x18)
		mode &= ~PCI_AGP_COMMAND_FW;

	/*
	 * Go through the quirks list and adjust the agpmode accordingly.
	 */
	while (agpmode == -1 && quirk->hostbridge_vendor) {
		if (info->id_vendor == quirk->hostbridge_vendor &&
		    info->id_device == quirk->hostbridge_device &&
		    device->pdev->vendor == quirk->chip_vendor &&
		    device->pdev->device == quirk->chip_device) {
			agpmode = quirk->mode;
			nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n",
				agpmode);
			break;
		}
		++quirk;
	}

	/*
	 * AGP mode set in the command line.
	 */
	if (agpmode > 0) {
		bool agpv3 = mode & 0x8;
		int rate = agpv3 ? agpmode / 4 : agpmode;

		mode = (mode & ~0x7) | (rate & 0x7);
	}

	return mode;
}
Пример #16
0
int
nv04_devinit_init(struct nouveau_object *object)
{
	struct nv04_devinit_priv *priv = (void *)object;

	if (!priv->base.post) {
		u32 htotal = nv_rdvgac(priv, 0, 0x06);
		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
		htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
		htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
		htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
		if (!htotal) {
			nv_info(priv, "adaptor not initialised\n");
			priv->base.post = true;
		}
	}

	return nouveau_devinit_init(&priv->base);
}
Пример #17
0
int
_nouveau_volt_init(struct nouveau_object *object)
{
	struct nouveau_volt *volt = (void *)object;
	int ret;

	ret = nouveau_subdev_init(&volt->base);
	if (ret)
		return ret;

	ret = volt->get(volt);
	if (ret < 0) {
		if (ret != -ENODEV)
			nv_debug(volt, "current voltage unknown\n");
		return 0;
	}

	nv_info(volt, "GPU voltage: %duv\n", ret);
	return 0;
}
Пример #18
0
static void
nouveau_bios_shadow_of(struct nouveau_bios *bios)
{
	struct pci_dev *pdev = nv_device(bios)->pdev;
	struct device_node *dn;
	const u32 *data;
	int size;

	dn = pci_device_to_OF_node(pdev);
	if (!dn) {
		nv_info(bios, "Unable to get the OF node\n");
		return;
	}

	data = of_get_property(dn, "NVDA,BMP", &size);
	if (data && size) {
		bios->size = size;
		bios->data = kmalloc(bios->size, GFP_KERNEL);
		if (bios->data)
			memcpy(bios->data, data, size);
	}
}
Пример #19
0
static int
gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
		struct nvkm_oclass *oclass, void *data, u32 size,
		struct nvkm_object **pobject)
{
	struct gk20a_volt_priv *priv;
	struct nvkm_volt *volt;
	struct nouveau_platform_device *plat;
	int i, ret, uv;

	ret = nvkm_volt_create(parent, engine, oclass, &priv);
	*pobject = nv_object(priv);
	if (ret)
		return ret;

	volt = &priv->base;

	plat = nv_device_to_platform(nv_device(parent));

	uv = regulator_get_voltage(plat->gpu->vdd);
	nv_info(priv, "The default voltage is %duV\n", uv);

	priv->vdd = plat->gpu->vdd;
	priv->base.vid_get = gk20a_volt_vid_get;
	priv->base.vid_set = gk20a_volt_vid_set;
	priv->base.set_id = gk20a_volt_set_id;

	volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
	nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
	for (i = 0; i < volt->vid_nr; i++) {
		volt->vid[i].vid = i;
		volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
					plat->gpu_speedo);
		nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
					volt->vid[i].uv);
	}

	return 0;
}
bool GeforceSensors::start(IOService *provider)
{
	HWSensorsDebugLog("Starting...");
	
	if (!super::start(provider))
        return false;
        
    struct nouveau_device *device = &card;
    
    // map device memory
    if ((device->pcidev = (IOPCIDevice*)provider)) {
        
        device->pcidev->setMemoryEnable(true);
        
        if ((device->mmio = device->pcidev->mapDeviceMemoryWithIndex(0))) {
            nv_debug(device, "memory mapped successfully\n");
        }
        else {
            HWSensorsFatalLog("failed to map memory");
            return false;
        }
    }
    else {
        HWSensorsFatalLog("failed to assign PCI device");
        return false;
    }
    
    card.card_index = -1;

    if (OSData *multiboard_capable = OSDynamicCast(OSData, provider->getProperty("rm_multiboard_capable"))) {
        if (0x1 == *((UInt32*)multiboard_capable->getBytesNoCopy())) {
            if (OSData *board_number = OSDynamicCast(OSData, provider->getProperty("rm_board_number"))) {
                UInt8 index = *((UInt32*)board_number->getBytesNoCopy());
                card.card_index = takeGPUIndex(index);
            }
        }
    }
    
    if (card.card_index < 0)
        card.card_index = takeVacantGPUIndex();
    
    if (card.card_index < 0) {
        HWSensorsFatalLog("failed to take vacant GPU index");
        return false;
    }
    
    // identify chipset
    if (!nouveau_identify(device)) {
        releaseGPUIndex(card.card_index);
        return false;
    }
    
    // shadow and parse bios
    
    //try to load bios from registry first from "vbios" property created by Chameleon boolloader
    if (OSData *vbios = OSDynamicCast(OSData, provider->getProperty("vbios"))) {
        device->bios.size = vbios->getLength();
        device->bios.data = (u8*)IOMalloc(card.bios.size);
        memcpy(device->bios.data, vbios->getBytesNoCopy(), device->bios.size);
    }
    
    if (!device->bios.data || !device->bios.size || nouveau_bios_score(device, true) < 1)
        if (!nouveau_bios_shadow(device)) {
            if (device->bios.data && device->bios.size) {
                IOFree(card.bios.data, card.bios.size);
                device->bios.data = NULL;
                device->bios.size = 0;
            }
            
            nv_fatal(device, "unable to shadow VBIOS\n");
            
            releaseGPUIndex(card.card_index);
            card.card_index = -1;
            return false;
        }
    
    nouveau_vbios_init(device);
    nouveau_bios_parse(device);
    
    // initialize funcs and variables
    if (!nouveau_init(device)) {
        nv_error(device, "unable to initialize monitoring driver\n");
        releaseGPUIndex(card.card_index);
        card.card_index = -1;
        return false;
    }
    
    nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro);
    
    if (device->card_type < NV_C0) {
        // init i2c structures
        nouveau_i2c_create(device);
        
        // setup nouveau i2c sensors
        nouveau_i2c_probe(device);
    }
    
    // Register sensors
    char key[5];
    if (card.core_temp_get || card.board_temp_get) {
        nv_debug(device, "registering i2c temperature sensors...\n");
        
        if (card.core_temp_get && card.board_temp_get) {
            snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
            addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core);
            
            snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index);
            addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board);
        }
        else if (card.core_temp_get) {
            snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
            addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core);
        }
        else if (card.board_temp_get) {
            snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index);
            addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board);
        }
    }
    else if (card.temp_get)
    {
        nv_debug(device, "registering temperature sensors...\n");
        
        snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
        addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_diode);
    }
    
    int arg_value = 1;

    if (card.clocks_get && !PE_parse_boot_argn("-gpusensors-no-clocks", &arg_value, sizeof(arg_value))) {
        nv_debug(device, "registering clocks sensors...\n");
        
        if (card.clocks_get(&card, nouveau_clock_core) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index);
            addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_core);
        }
        
//        if (card.clocks_get(&card, nouveau_clock_shader) > 0) {
//            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index);
//            addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_shader);
//        }
        
        if (card.clocks_get(&card, nouveau_clock_rop) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index);
            addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_rop);
        }
        
        if (card.clocks_get(&card, nouveau_clock_memory) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index);
            addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_memory);
        }
    }
    
    if (card.fan_pwm_get || card.fan_rpm_get) {
        nv_debug(device, "registering PWM sensors...\n");

        char title[DIAG_FUNCTION_STR_LEN];
        snprintf (title, DIAG_FUNCTION_STR_LEN, "GPU %X", card.card_index + 1);
        
        if (card.fan_rpm_get && card.fan_rpm_get(device) >= 0)
            addTachometer(nouveau_fan_rpm, title, GPU_FAN_RPM, card.card_index);
        
        if (card.fan_pwm_get && card.fan_pwm_get(device) >= 0)
            addTachometer(nouveau_fan_pwm, title, GPU_FAN_PWM_CYCLE, card.card_index);
    }
    
    if (card.voltage_get && card.voltage.supported) {
        nv_debug(device, "registering voltage sensors...\n");
        snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index);
        addSensor(key, TYPE_FP2E, TYPE_FPXX_SIZE, kFakeSMCVoltageSensor, 0);
    }
    
    registerService();
    
    nv_info(device, "started\n");
    
    return true;
}
Пример #21
0
static int
nouveau_bios_shadow(struct nouveau_bios *bios)
{
	struct methods shadow_methods[] = {
#if defined(__powerpc__)
		{ "OpenFirmware", nouveau_bios_shadow_of, true, 0, 0, NULL },
#endif
		{ "PRAMIN", nouveau_bios_shadow_pramin, true, 0, 0, NULL },
		{ "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL },
		{ "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL },
		{ "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL },
		{ "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL },
		{}
	};
	struct methods *mthd, *best;
	const struct firmware *fw;
	const char *optarg;
	int optlen, ret;
	char *source;

	optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
	source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
	if (source) {
		/* try to match one of the built-in methods */
		mthd = shadow_methods;
		do {
			if (strcasecmp(source, mthd->desc))
				continue;
			nv_info(bios, "source: %s\n", mthd->desc);

			mthd->shadow(bios);
			mthd->score = nouveau_bios_score(bios, mthd->rw);
			if (mthd->score) {
				kfree(source);
				return 0;
			}
		} while ((++mthd)->shadow);

		/* attempt to load firmware image */
		ret = request_firmware(&fw, source, &nv_device(bios)->pdev->dev);
		if (ret == 0) {
			bios->size = fw->size;
			bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
			release_firmware(fw);

			nv_info(bios, "image: %s\n", source);
			if (nouveau_bios_score(bios, 1)) {
				kfree(source);
				return 0;
			}

			kfree(bios->data);
			bios->data = NULL;
		}

		nv_error(bios, "source \'%s\' invalid\n", source);
		kfree(source);
	}

	mthd = shadow_methods;
	do {
		nv_info(bios, "checking %s for image...\n", mthd->desc);
		mthd->shadow(bios);
		mthd->score = nouveau_bios_score(bios, mthd->rw);
		mthd->size = bios->size;
		mthd->data = bios->data;
		bios->data = NULL;
	} while (mthd->score != 3 && (++mthd)->shadow);

	mthd = shadow_methods;
	best = mthd;
	do {
		if (mthd->score > best->score) {
			kfree(best->data);
			best = mthd;
		}
	} while ((++mthd)->shadow);

	if (best->score) {
		nv_info(bios, "using image from %s\n", best->desc);
		bios->size = best->size;
		bios->data = best->data;
		return 0;
	}

	nv_error(bios, "unable to locate usable image\n");
	return -EINVAL;
}
Пример #22
0
int
nv50_devinit_init(struct nouveau_object *object)
{
	struct nouveau_bios *bios = nouveau_bios(object);
	struct nv50_devinit_priv *priv = (void *)object;
	struct nvbios_outp info;
	struct dcb_output outp;
	u8  ver = 0xff, hdr, cnt, len;
	int ret, i = 0;

	if (!priv->base.post) {
		if (!nv_rdvgac(priv, 0, 0x00) &&
		    !nv_rdvgac(priv, 0, 0x1a)) {
			nv_info(priv, "adaptor not initialised\n");
			priv->base.post = true;
		}
	}

	ret = nouveau_devinit_init(&priv->base);
	if (ret)
		return ret;

	/* if we ran the init tables, we have to execute the first script
	 * pointer of each dcb entry's display encoder table in order
	 * to properly initialise each encoder.
	 */
	while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
		if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
				     &ver, &hdr, &cnt, &len, &info)) {
			struct nvbios_init init = {
				.subdev = nv_subdev(priv),
				.bios = bios,
				.offset = info.script[0],
				.outp = &outp,
				.crtc = -1,
				.execute = 1,
			};

			nvbios_exec(&init);
		}
		i++;
	}

	return 0;
}

static int
nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
		  struct nouveau_oclass *oclass, void *data, u32 size,
		  struct nouveau_object **pobject)
{
	struct nv50_devinit_priv *priv;
	int ret;

	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
	*pobject = nv_object(priv);
	if (ret)
		return ret;

	priv->base.pll_set = nv50_devinit_pll_set;
	return 0;
}

struct nouveau_oclass
nv50_devinit_oclass = {
	.handle = NV_SUBDEV(DEVINIT, 0x50),
	.ofuncs = &(struct nouveau_ofuncs) {
		.ctor = nv50_devinit_ctor,
		.dtor = _nouveau_devinit_dtor,
		.init = nv50_devinit_init,
		.fini = _nouveau_devinit_fini,
	},
};
Пример #23
0
int
nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
		   struct nouveau_oclass *bclass, int length, void **pobject)
{
	const struct nouveau_mc_oclass *oclass = (void *)bclass;
	struct nouveau_device *device = nv_device(parent);
	struct nouveau_mc *pmc;
	int ret;

	ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC",
				     "master", length, pobject);
	pmc = *pobject;
	if (ret)
		return ret;

	if (nv_device_is_pci(device))
		switch (device->pdev->device & 0x0ff0) {
		case 0x00f0:
		case 0x02e0:
			/* BR02? NFI how these would be handled yet exactly */
			break;
		default:
			switch (device->chipset) {
			case 0xaa:
				/* reported broken, nv also disable it */
				break;
			default:
				pmc->use_msi = true;
				break;
		}

		pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI",
					       pmc->use_msi);

		if (pmc->use_msi && oclass->msi_rearm) {
			pmc->use_msi = pci_enable_msi(device->pdev) == 0;
			if (pmc->use_msi) {
				nv_info(pmc, "MSI interrupts enabled\n");
				oclass->msi_rearm(pmc);
			}
		} else {
			pmc->use_msi = false;
		}
	}

#if defined(__NetBSD__)
	if (nv_device_is_pci(device)) {
		const pci_chipset_tag_t pc = device->pdev->pd_pa.pa_pc;
		pci_intr_handle_t ih;

		if (pci_intr_map(&device->pdev->pd_pa, &ih))
			return -EIO;

		pmc->irq_cookie = pci_intr_establish(pc, ih, IPL_VM,
		    &nouveau_mc_intr, pmc);
		if (pmc->irq_cookie == NULL)
			return -EIO;
#if defined (__arm__)
	} else {
		pmc->irq_cookie = intr_establish(TEGRA_INTR_GPU,
		    IPL_VM, IST_LEVEL, nouveau_mc_intr, pmc);
		if (pmc->irq_cookie == NULL)
			return -EIO;
#endif
	}
#else
	ret = nv_device_get_irq(device, true);
	if (ret < 0)
		return ret;
	pmc->irq = ret;

	ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau",
			  pmc);

	if (ret < 0)
		return ret;
#endif

	return 0;
}
Пример #24
0
bool nvclock_i2c_sensor_init(nouveau_device *device)
{
    int num_busses = 0;
    I2CBusPtr busses[4];
    
    struct nouveau_i2c_port *port = NULL;
    
    for (int i = 0; i <= 4; i++) {
        if ((port = nouveau_i2c_find(&device->i2c, NV_I2C_DEFAULT(i)))) {
            char name[16];
            
            snprintf(name, 16, "NV_I2C_DEFAULT%X", i);
            
            busses[num_busses++] = nvclock_i2c_create_bus_ptr(device, STRDUP(name, sizeof(name)), port->drive);
        }
    }
    
    if (num_busses > 0) {
        device->nvclock_i2c_sensor = nvclock_i2c_probe_devices(device, busses, num_busses);
        
        /* When a sensor is available, enable the correct function pointers */
        if(device->nvclock_i2c_sensor) {
            nv_info(device, "found %s monitoring chip\n", device->nvclock_i2c_sensor->chip_name);
            
            switch(device->nvclock_i2c_sensor->chip_id)
            {
                case LM99:
                case MAX6559:
                    device->board_temp_get = lm99_get_board_temp;
                    device->diode_temp_get = lm99_get_gpu_temp;
                    break;
                case F75375:
                    device->board_temp_get = f75375_get_board_temp;
                    device->diode_temp_get = f75375_get_gpu_temp;
                    device->rpm_fan_get = f75375_get_fanspeed_rpm;
                    device->pwm_fan_get = f75375_get_fanspeed_pwm;
                    break;
                case W83781D:
                    device->board_temp_get = w83781d_get_board_temp;
                    device->diode_temp_get = w83781d_get_gpu_temp;
                    //nv_card->get_i2c_fanspeed_rpm = w83781d_get_fanspeed_rpm;
                    //nv_card->get_i2c_fanspeed_pwm = w83781d_get_fanspeed_pwm;
                    break;
                case W83L785R:
                    device->board_temp_get = w83l785r_get_board_temp;
                    device->diode_temp_get = w83l785r_get_gpu_temp;
                    device->rpm_fan_get = w83l785r_get_fanspeed_rpm;
                    device->pwm_fan_get = w83l785r_get_fanspeed_pwm;
                    break;
                case ADT7473:
                    device->board_temp_get = adt7473_get_board_temp;
                    device->diode_temp_get = adt7473_get_gpu_temp;
                    device->rpm_fan_get = adt7473_get_fanspeed_rpm;
                    device->pwm_fan_get = adt7473_get_fanspeed_pwm;
                    break;
                default:
                    break;
            }
        }
            
        return true;
    }
    
    return false;
}
Пример #25
0
bool GeforceSensors::managedStart(IOService *provider)
{
    HWSensorsDebugLog("Starting...");

    struct nouveau_device *device = &card;

    if (!device->bios.data || !device->bios.size) {
        if (!shadowBios()) {
            nv_fatal(device, "unable to shadow VBIOS\n");
            releaseGPUIndex(card.card_index);
            card.card_index = -1;
            return false;
        }
    }

    nouveau_vbios_init(device);
    nouveau_bios_parse(device);
    
    // initialize funcs and variables
    if (!nouveau_init(device)) {
        nv_error(device, "unable to initialize monitoring driver\n");
        releaseGPUIndex(card.card_index);
        card.card_index = -1;
        return false;
    }
    
    nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro);
    
    if (device->card_type < NV_C0) {
        // init i2c structures
        nouveau_i2c_create(device);
        
        // setup nouveau i2c sensors
        nouveau_i2c_probe(device);
    }
    
    // Register sensors
    char key[5];

    if (card.core_temp_get || card.board_temp_get) {
        nv_debug(device, "registering i2c temperature sensors...\n");
        
        if (card.core_temp_get) {
            snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
            addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core);
        }
        else if (card.board_temp_get) {
            snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index);
            addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board);
        }
    }
    else if (card.temp_get)
    {
        nv_debug(device, "registering temperature sensors...\n");
        
        snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
        addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_diode);
    }
    
    int arg_value = 1;
    
    if (card.clocks_get && !PE_parse_boot_argn("-gpusensors-no-clocks", &arg_value, sizeof(arg_value))) {
        nv_debug(device, "registering clocks sensors...\n");
        
        if (card.clocks_get(&card, nouveau_clock_core) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index);
            addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_core);
        }
        
        //        if (card.clocks_get(&card, nouveau_clock_shader) > 0) {
        //            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index);
        //            addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_shader);
        //        }
        
        if (card.clocks_get(&card, nouveau_clock_rop) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index);
            addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_rop);
        }
        
        if (card.clocks_get(&card, nouveau_clock_memory) > 0) {
            snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index);
            addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_memory);
        }
    }
    
    if (card.fan_pwm_get || card.fan_rpm_get) {
        nv_debug(device, "registering PWM sensors...\n");
        
        char title[DIAG_FUNCTION_STR_LEN];
        snprintf (title, DIAG_FUNCTION_STR_LEN, "GPU %X", card.card_index + 1);
        
        if (card.fan_rpm_get && card.fan_rpm_get(&card) >= 0)
            addTachometer(nouveau_fan_rpm, title, GPU_FAN_RPM, card.card_index);
        
        if (card.fan_pwm_get && card.fan_pwm_get(&card) >= 0)
            addTachometer(nouveau_fan_pwm, title, GPU_FAN_PWM_CYCLE, card.card_index);
    }
    
    if (card.volt.get && card.volt.get(&card) >= 0/*card.voltage_get && card.voltage.supported*/) {
        nv_debug(device, "registering voltage sensors...\n");
        snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index);
        addSensorForKey(key, TYPE_FP2E, TYPE_FPXX_SIZE, kFakeSMCVoltageSensor, 0);
    }
    
    registerService();
    
    nv_info(device, "started\n");
    
    return true;
}
Пример #26
0
bool GeforceSensors::start(IOService * provider)
{
	DebugLog("Starting...");
	
	if (!super::start(provider)) 
    return false;
  
  if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) {
		WarningLog("Can't locate fake SMC device, kext will not load");
		return false;
	}  
  
  struct nouveau_device *device = &card;
  
  //Find card number
  card.card_index = getVacantGPUIndex();
  
  if (card.card_index < 0) {
    nv_error(device, "failed to obtain vacant GPU index\n");
    return false;
  }
  
  // map device memory
//  device->pcidev = (IOPCIDevice*)provider;
  if (device->pcidev) {
    
    device->pcidev->setMemoryEnable(true);
    
    if ((device->mmio = device->pcidev->mapDeviceMemoryWithIndex(0))) {
      nv_debug(device, "memory mapped successfully\n");
    }
    else {
      nv_error(device, "failed to map memory\n");
      return false;
    }
  }
  else {
    nv_error(device, "failed to assign PCI device\n");
    return false;
  }
  
  // identify chipset
  if (!nouveau_identify(device))
    return false;
  
  // shadow and parse bios
  
  //try to load bios from registry first from "vbios" property created by Chameleon boolloader
  if (OSData *vbios = OSDynamicCast(OSData, provider->getProperty("vbios"))) {
    device->bios.size = vbios->getLength();
    device->bios.data = (u8*)IOMalloc(card.bios.size);
    memcpy(device->bios.data, vbios->getBytesNoCopy(), device->bios.size);
  }
  
  if (!device->bios.data || !device->bios.size || nouveau_bios_score(device, true) < 1)
    if (!nouveau_bios_shadow(device)) {
      if (device->bios.data && device->bios.size) {
        IOFree(card.bios.data, card.bios.size);
        device->bios.data = NULL;
        device->bios.size = 0;
      }
      
      nv_error(device, "unable to shadow VBIOS\n");
      
      return false;
    }
  
  nouveau_vbios_init(device);
  nouveau_bios_parse(device);
  
  // initialize funcs and variables
  if (!nouveau_init(device)) {
    nv_error(device, "unable to initialize monitoring driver\n");
    return false;
  }
  
  nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, (unsigned int)device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro);
  
  if (device->card_type < NV_C0) {
    // init i2c structures
    nouveau_i2c_create(device);
    
    // setup nouveau i2c sensors
    nouveau_i2c_probe(device);
  }
  
  // Register sensors
  char key[5];
  
  if (card.core_temp_get || card.board_temp_get) {
    nv_debug(device, "registering i2c temperature sensors...\n");
    
    if (card.core_temp_get && card.board_temp_get) {
      snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index);
      this->addSensor(key, TYPE_SP78, 2, 0);
      
      snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index);
      addSensor(key, TYPE_SP78, 2, 0);
    }
    else if (card.core_temp_get) {
      snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index);
      addSensor(key, TYPE_SP78, 2, 0);
    }
    else if (card.board_temp_get) {
      snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index);
      addSensor(key, TYPE_SP78, 2, 0);
    }
  }
  else if (card.temp_get)
  {
    nv_debug(device, "registering temperature sensors...\n");
    
    snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index);
    addSensor(key, TYPE_SP78, 2, 0);
  }
  
  if (card.clocks_get) {
    nv_debug(device, "registering clocks sensors...\n");
    
    if (card.clocks_get(&card, nouveau_clock_core) > 0) {
      snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index);
      addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_core);
    }
    
    if (card.clocks_get(&card, nouveau_clock_shader) > 0) {
      snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index);
      addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_shader);
    }
    
    if (card.clocks_get(&card, nouveau_clock_rop) > 0) {
      snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index);
      addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_rop);
    }
    
    if (card.clocks_get(&card, nouveau_clock_memory) > 0) {
      snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index);
      addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_memory);
    }
  }
  
  if (card.fan_pwm_get || card.fan_rpm_get) {
    nv_debug(device, "registering PWM sensors...\n");
    
    if (card.fan_rpm_get && card.fan_rpm_get(device) > 0) {
      char title[6];
      snprintf (title, 6, "GPU %X", card.card_index + 1);
      
      UInt8 fanIndex = 0;
      
      if (addTachometer( fanIndex)) {
        if (card.fan_pwm_get && card.fan_pwm_get(device) > 0) {
          snprintf(key, 5, KEY_FAKESMC_FORMAT_GPUPWM, fanIndex);
          addSensor(key, TYPE_UI8, TYPE_UI8_SIZE, 0);
        }
      }
    }
  }
  
  if (card.voltage_get && card.voltage.supported) {
    nv_debug(device, "registering voltage sensors...\n");
    snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index);
    addSensor(key, TYPE_FP2E, TYPE_FPXX_SIZE, 0);
  }
  
  nv_info(device, "started\n");
  
  return true;
}