|
@@ -16,6 +16,7 @@
|
|
|
#include <sys/types.h>
|
|
#include <sys/types.h>
|
|
|
#include <sys/stat.h>
|
|
#include <sys/stat.h>
|
|
|
#include <fcntl.h>
|
|
#include <fcntl.h>
|
|
|
|
|
+#include <math.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_LINUX_I2C_DEV_USER_H
|
|
#ifdef HAVE_LINUX_I2C_DEV_USER_H
|
|
|
#include <linux/i2c-dev-user.h>
|
|
#include <linux/i2c-dev-user.h>
|
|
@@ -70,6 +71,9 @@ struct knc_device {
|
|
|
struct knc_core {
|
|
struct knc_core {
|
|
|
int asicno;
|
|
int asicno;
|
|
|
int coreno;
|
|
int coreno;
|
|
|
|
|
+
|
|
|
|
|
+ float volt;
|
|
|
|
|
+ float current;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static
|
|
static
|
|
@@ -568,19 +572,36 @@ void knc_core_enable(struct thr_info * const thr)
|
|
|
_knc_core_setstatus(thr, 1);
|
|
_knc_core_setstatus(thr, 1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static
|
|
|
|
|
+float knc_dcdc_decode_5_11(uint16_t raw)
|
|
|
|
|
+{
|
|
|
|
|
+ if (raw == 0)
|
|
|
|
|
+ return 0.0;
|
|
|
|
|
+
|
|
|
|
|
+ int dcdc_vin_exp = (raw & 0xf800) >> 11;
|
|
|
|
|
+ float dcdc_vin_man = raw & 0x07ff;
|
|
|
|
|
+ if (dcdc_vin_exp >= 16)
|
|
|
|
|
+ dcdc_vin_exp = -32 + dcdc_vin_exp;
|
|
|
|
|
+ float dcdc_vin = dcdc_vin_man * exp2(dcdc_vin_exp);
|
|
|
|
|
+ return dcdc_vin;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static
|
|
static
|
|
|
bool knc_get_stats(struct cgpu_info * const cgpu)
|
|
bool knc_get_stats(struct cgpu_info * const cgpu)
|
|
|
{
|
|
{
|
|
|
if (cgpu->device != cgpu)
|
|
if (cgpu->device != cgpu)
|
|
|
return true;
|
|
return true;
|
|
|
|
|
|
|
|
- struct knc_core * const knccore = cgpu->thr[0]->cgpu_data;
|
|
|
|
|
|
|
+ struct thr_info *thr = cgpu->thr[0];
|
|
|
|
|
+ struct knc_core *knccore = thr->cgpu_data;
|
|
|
struct cgpu_info *proc;
|
|
struct cgpu_info *proc;
|
|
|
const int i2cdev = knccore->asicno + 3;
|
|
const int i2cdev = knccore->asicno + 3;
|
|
|
- const int i2cslave = 0x48;
|
|
|
|
|
|
|
+ const int i2cslave_temp = 0x48;
|
|
|
|
|
+ const int i2cslave_dcdc[] = {0x10, 0x12, 0x14, 0x17};
|
|
|
|
|
+ int die, i;
|
|
|
int i2c;
|
|
int i2c;
|
|
|
- int32_t rawtemp;
|
|
|
|
|
- float temp;
|
|
|
|
|
|
|
+ int32_t rawtemp, rawvolt, rawcurrent;
|
|
|
|
|
+ float temp, volt, current;
|
|
|
bool rv = false;
|
|
bool rv = false;
|
|
|
|
|
|
|
|
char i2cpath[sizeof(KNC_I2C_TEMPLATE)];
|
|
char i2cpath[sizeof(KNC_I2C_TEMPLATE)];
|
|
@@ -593,10 +614,10 @@ bool knc_get_stats(struct cgpu_info * const cgpu)
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (ioctl(i2c, I2C_SLAVE, i2cslave))
|
|
|
|
|
|
|
+ if (ioctl(i2c, I2C_SLAVE, i2cslave_temp))
|
|
|
{
|
|
{
|
|
|
applog(LOG_DEBUG, "%s: %s: Failed to select i2c slave 0x%x",
|
|
applog(LOG_DEBUG, "%s: %s: Failed to select i2c slave 0x%x",
|
|
|
- cgpu->dev_repr, __func__, i2cslave);
|
|
|
|
|
|
|
+ cgpu->dev_repr, __func__, i2cslave_temp);
|
|
|
goto out;
|
|
goto out;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -604,11 +625,52 @@ bool knc_get_stats(struct cgpu_info * const cgpu)
|
|
|
if (rawtemp == -1)
|
|
if (rawtemp == -1)
|
|
|
goto out;
|
|
goto out;
|
|
|
temp = ((float)(rawtemp & 0xff));
|
|
temp = ((float)(rawtemp & 0xff));
|
|
|
- if (rawtemp & 0x100)
|
|
|
|
|
|
|
+ if (rawtemp & 0x8000)
|
|
|
temp += 0.5;
|
|
temp += 0.5;
|
|
|
|
|
|
|
|
- for (proc = cgpu; proc && proc->device == cgpu; proc = proc->next_proc)
|
|
|
|
|
|
|
+ /* DCDC i2c slaves are on 0x10 + [0-7]
|
|
|
|
|
+ 8 DCDC boards have all populated
|
|
|
|
|
+ 4 DCDC boards only have 0,2,4,7 populated
|
|
|
|
|
+ Only 0,2,4,7 are used
|
|
|
|
|
+ Each DCDC powers one die in the chip, each die has 48 cores
|
|
|
|
|
+
|
|
|
|
|
+ Datasheet at http://www.lineagepower.com/oem/pdf/MDT040A0X.pdf
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ for (proc = cgpu, i = 0; proc && proc->device == cgpu; proc = proc->next_proc, ++i)
|
|
|
|
|
+ {
|
|
|
|
|
+ thr = proc->thr[0];
|
|
|
|
|
+ knccore = thr->cgpu_data;
|
|
|
|
|
+ die = i / 0x30;
|
|
|
|
|
+
|
|
|
|
|
+ if (0 == i % 0x30)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (ioctl(i2c, I2C_SLAVE, i2cslave_dcdc[die]))
|
|
|
|
|
+ {
|
|
|
|
|
+ applog(LOG_DEBUG, "%s: %s: Failed to select i2c slave 0x%x",
|
|
|
|
|
+ cgpu->dev_repr, __func__, i2cslave_dcdc[die]);
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ rawvolt = i2c_smbus_read_word_data(i2c, 0x8b); // VOUT
|
|
|
|
|
+ if (rawvolt == -1)
|
|
|
|
|
+ goto out;
|
|
|
|
|
+
|
|
|
|
|
+ rawcurrent = i2c_smbus_read_word_data(i2c, 0x8c); // IOUT
|
|
|
|
|
+ if (rawcurrent == -1)
|
|
|
|
|
+ goto out;
|
|
|
|
|
+
|
|
|
|
|
+ volt = (float)rawvolt * exp2(-10);
|
|
|
|
|
+ current = (float)knc_dcdc_decode_5_11(rawcurrent);
|
|
|
|
|
+
|
|
|
|
|
+ applog(LOG_DEBUG, "%s: die %d %6.3fV %5.2fA",
|
|
|
|
|
+ cgpu->dev_repr, die, volt, current);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
proc->temp = temp;
|
|
proc->temp = temp;
|
|
|
|
|
+ knccore->volt = volt;
|
|
|
|
|
+ knccore->current = current;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
rv = true;
|
|
rv = true;
|
|
|
out:
|
|
out:
|
|
@@ -616,6 +678,31 @@ out:
|
|
|
return rv;
|
|
return rv;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static
|
|
|
|
|
+struct api_data *knc_api_extra_device_status(struct cgpu_info * const cgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct api_data *root = NULL;
|
|
|
|
|
+ struct thr_info * const thr = cgpu->thr[0];
|
|
|
|
|
+ struct knc_core * const knccore = thr->cgpu_data;
|
|
|
|
|
+
|
|
|
|
|
+ root = api_add_volts(root, "Voltage", &knccore->volt, false);
|
|
|
|
|
+ root = api_add_volts(root, "DCDC Current", &knccore->current, false);
|
|
|
|
|
+
|
|
|
|
|
+ return root;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#ifdef HAVE_CURSES
|
|
|
|
|
+static
|
|
|
|
|
+void knc_wlogprint_status(struct cgpu_info * const cgpu)
|
|
|
|
|
+{
|
|
|
|
|
+ struct thr_info * const thr = cgpu->thr[0];
|
|
|
|
|
+ struct knc_core * const knccore = thr->cgpu_data;
|
|
|
|
|
+
|
|
|
|
|
+ wlogprint("Voltage: %.3f DCDC Current: %.3f\n",
|
|
|
|
|
+ knccore->volt, knccore->current);
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
struct device_drv knc_drv = {
|
|
struct device_drv knc_drv = {
|
|
|
.dname = "knc",
|
|
.dname = "knc",
|
|
|
.name = "KNC",
|
|
.name = "KNC",
|
|
@@ -631,4 +718,8 @@ struct device_drv knc_drv = {
|
|
|
.poll = knc_poll,
|
|
.poll = knc_poll,
|
|
|
|
|
|
|
|
.get_stats = knc_get_stats,
|
|
.get_stats = knc_get_stats,
|
|
|
|
|
+ .get_api_extra_device_status = knc_api_extra_device_status,
|
|
|
|
|
+#ifdef HAVE_CURSES
|
|
|
|
|
+ .proc_wlogprint_status = knc_wlogprint_status,
|
|
|
|
|
+#endif
|
|
|
};
|
|
};
|