Browse Source

Merge pull request #370 from kanoi/mmq

API V1.23 - new pgaset command, to be used soon + MMQ add api pgaset for clock + ensure delta clock can never exceed limits
nfactor-troky
Con Kolivas 12 years ago
parent
commit
34b15a6d46
  1. 25
      API-README
  2. 78
      api.c
  3. 79
      driver-modminer.c
  4. 1
      miner.h

25
API-README

@ -330,9 +330,23 @@ The list of requests - a (*) means it requires privileged access - and replies a
queue, scantime, expiry queue, scantime, expiry
N is an integer in the range 0 to 9999 N is an integer in the range 0 to 9999
substats USBSTATS Stats of all LIBUSB mining devices except ztex usbstats USBSTATS Stats of all LIBUSB mining devices except ztex
e.g. Name=MMQ,ID=0,Stat=SendWork,Count=99,...| e.g. Name=MMQ,ID=0,Stat=SendWork,Count=99,...|
pgaset|N,opt[,val] (*)
none There is no reply section just the STATUS section
stating the results of setting PGA N with opt[,val]
This is only available if PGA mining is enabled
If the PGA does not support any set options, it will
always return a WARN stating pgaset isn't supported
If opt=help it will return an INFO status with a
help message about the options available
The current options are:
MMQ opt=clock val=160 to 230 (and a multiple of 2)
When you enable, disable or restart a GPU or PGA, you will also get Thread messages When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window in the cgminer status window
@ -386,7 +400,14 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.22 API V1.23
Added API commands:
'pgaset' - with: MMQ opt=clock val=160 to 230 (and a multiple of 2)
----------
API V1.22 (cgminer v2.10.1)
Enforced output limitation: Enforced output limitation:
all extra records beyond the output limit of the API (~64k) are ignored all extra records beyond the output limit of the API (~64k) are ignored

78
api.c

@ -133,7 +133,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.22"; static const char *APIVERSION = "1.23";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *SICK = "Sick"; static const char *SICK = "Sick";
@ -379,6 +379,14 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_USBSTA 87 #define MSG_USBSTA 87
#define MSG_NOUSTA 88 #define MSG_NOUSTA 88
#ifdef HAVE_AN_FPGA
#define MSG_MISPGAOPT 89
#define MSG_PGANOSET 90
#define MSG_PGAHELP 91
#define MSG_PGASETOK 92
#define MSG_PGASETERR 93
#endif
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
SEVERITY_WARN, SEVERITY_WARN,
@ -544,6 +552,13 @@ struct CODES {
{ SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" },
{ SEVERITY_SUCC, MSG_USBSTA, PARAM_NONE, "USB Statistics" }, { SEVERITY_SUCC, MSG_USBSTA, PARAM_NONE, "USB Statistics" },
{ SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" },
#ifdef HAVE_AN_FPGA
{ SEVERITY_ERR, MSG_MISPGAOPT, PARAM_NONE, "Missing option after PGA number" },
{ SEVERITY_WARN, MSG_PGANOSET, PARAM_PGA, "PGA %d does not support pgaset" },
{ SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" },
{ SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" },
{ SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" },
#endif
{ SEVERITY_FAIL, 0, 0, NULL } { SEVERITY_FAIL, 0, 0, NULL }
}; };
@ -3142,6 +3157,64 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
#endif #endif
} }
#ifdef HAVE_AN_FPGA
static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{
char buf[TMPBUFSIZ];
int numpga = numpgas();
if (numpga == 0) {
message(io_data, MSG_PGANON, 0, NULL, isjson);
return;
}
if (param == NULL || *param == '\0') {
message(io_data, MSG_MISID, 0, NULL, isjson);
return;
}
char *opt = strchr(param, ',');
if (opt)
*(opt++) = '\0';
if (!opt || !*opt) {
message(io_data, MSG_MISPGAOPT, 0, NULL, isjson);
return;
}
int id = atoi(param);
if (id < 0 || id >= numpga) {
message(io_data, MSG_INVPGA, id, NULL, isjson);
return;
}
int dev = pgadevice(id);
if (dev < 0) { // Should never happen
message(io_data, MSG_INVPGA, id, NULL, isjson);
return;
}
struct cgpu_info *cgpu = devices[dev];
struct device_api *api = cgpu->api;
char *set = strchr(opt, ',');
if (set)
*(set++) = '\0';
if (!api->set_device)
message(io_data, MSG_PGANOSET, id, NULL, isjson);
else {
char *ret = api->set_device(cgpu, opt, set, buf);
if (ret) {
if (strcasecmp(opt, "help") == 0)
message(io_data, MSG_PGAHELP, id, ret, isjson);
else
message(io_data, MSG_PGASETERR, id, ret, isjson);
} else
message(io_data, MSG_PGASETOK, id, NULL, isjson);
}
}
#endif
static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS { struct CMDS {
@ -3198,6 +3271,9 @@ struct CMDS {
{ "debug", debugstate, true }, { "debug", debugstate, true },
{ "setconfig", setconfig, true }, { "setconfig", setconfig, true },
{ "usbstats", usbstats, false }, { "usbstats", usbstats, false },
#ifdef HAVE_AN_FPGA
{ "pgaset", pgaset, true },
#endif
{ NULL, NULL, false } { NULL, NULL, false }
}; };

79
driver-modminer.c

@ -599,7 +599,13 @@ static bool modminer_fpga_prepare(struct thr_info *thr)
* *
* N.B. clock must always be a multiple of 2 * N.B. clock must always be a multiple of 2
*/ */
static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp) static const char *clockoldwork = "clock already changed for this work";
static const char *clocktoolow = "clock too low";
static const char *clocktoohi = "clock too high";
static const char *clocksetfail = "clock set command failed";
static const char *clockreplyfail = "clock reply failed";
static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool temp, bool force)
{ {
struct cgpu_info *modminer = thr->cgpu; struct cgpu_info *modminer = thr->cgpu;
struct modminer_fpga_state *state = thr->cgpu_data; struct modminer_fpga_state *state = thr->cgpu_data;
@ -607,8 +613,8 @@ static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp)
int err, amount; int err, amount;
// Only do once if multiple shares per work or multiple reasons // Only do once if multiple shares per work or multiple reasons
if (!state->new_work) if (!state->new_work && !force)
return false; return clockoldwork;
state->new_work = false; state->new_work = false;
@ -617,11 +623,11 @@ static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp)
state->hw_errors = 0; state->hw_errors = 0;
// FYI clock drop has little effect on temp // FYI clock drop has little effect on temp
if (delta < 0 && modminer->clock <= MODMINER_MIN_CLOCK) if (delta < 0 && (modminer->clock + delta) < MODMINER_MIN_CLOCK)
return false; return clocktoolow;
if (delta > 0 && modminer->clock >= MODMINER_MAX_CLOCK) if (delta > 0 && (modminer->clock + delta) > MODMINER_MAX_CLOCK)
return false; return clocktoohi;
if (delta < 0) { if (delta < 0) {
if (temp) if (temp)
@ -649,7 +655,7 @@ static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp)
applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->api->name, modminer->device_id, amount, err);
return false; return clocksetfail;
} }
if ((err = usb_read(modminer, (char *)(&buf), 1, &amount, C_REPLYSETCLOCK)) < 0 || amount != 1) { if ((err = usb_read(modminer, (char *)(&buf), 1, &amount, C_REPLYSETCLOCK)) < 0 || amount != 1) {
@ -658,7 +664,7 @@ static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp)
applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->api->name, modminer->device_id, amount, err);
return false; return clockreplyfail;
} }
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
@ -668,7 +674,7 @@ static bool modminer_delta_clock(struct thr_info *thr, int delta, bool temp)
(delta < 0) ? "down " : (delta > 0 ? "up " : ""), (delta < 0) ? "down " : (delta > 0 ? "up " : ""),
modminer->clock); modminer->clock);
return true; return NULL;
} }
static bool modminer_fpga_init(struct thr_info *thr) static bool modminer_fpga_init(struct thr_info *thr)
@ -715,7 +721,7 @@ static bool modminer_fpga_init(struct thr_info *thr)
} }
modminer->clock = MODMINER_DEF_CLOCK; modminer->clock = MODMINER_DEF_CLOCK;
modminer_delta_clock(thr, MODMINER_CLOCK_SET, false); modminer_delta_clock(thr, MODMINER_CLOCK_SET, false, false);
thr->primary_thread = true; thr->primary_thread = true;
@ -831,7 +837,7 @@ static void check_temperature(struct thr_info *thr)
modminer->api->name, modminer->device_id, modminer->api->name, modminer->device_id,
MODMINER_CUTOFF_TEMP, modminer->temp); MODMINER_CUTOFF_TEMP, modminer->temp);
modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true); modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false);
state->overheated = true; state->overheated = true;
dev_error(modminer, REASON_DEV_THERMAL_CUTOFF); dev_error(modminer, REASON_DEV_THERMAL_CUTOFF);
} else { } else {
@ -841,7 +847,7 @@ static void check_temperature(struct thr_info *thr)
// If it's defined to be 0 then don't call modminer_delta_clock() // If it's defined to be 0 then don't call modminer_delta_clock()
if (MODMINER_CLOCK_OVERHEAT != 0) if (MODMINER_CLOCK_OVERHEAT != 0)
modminer_delta_clock(thr, MODMINER_CLOCK_OVERHEAT, true); modminer_delta_clock(thr, MODMINER_CLOCK_OVERHEAT, true, false);
state->overheated = true; state->overheated = true;
dev_error(modminer, REASON_DEV_OVER_HEAT); dev_error(modminer, REASON_DEV_OVER_HEAT);
} }
@ -950,7 +956,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
if (modminer->clock > MODMINER_DEF_CLOCK || state->hw_errors > 1) { if (modminer->clock > MODMINER_DEF_CLOCK || state->hw_errors > 1) {
float pct = (state->hw_errors * 100.0 / (state->shares ? : 1.0)); float pct = (state->hw_errors * 100.0 / (state->shares ? : 1.0));
if (pct >= MODMINER_HW_ERROR_PERCENT) if (pct >= MODMINER_HW_ERROR_PERCENT)
modminer_delta_clock(thr, MODMINER_CLOCK_DOWN, false); modminer_delta_clock(thr, MODMINER_CLOCK_DOWN, false, false);
} }
} }
} else { } else {
@ -959,7 +965,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
// If we've reached the required good shares in a row then clock up // If we've reached the required good shares in a row then clock up
if (((state->shares - state->shares_last_hw) >= state->shares_to_good) && if (((state->shares - state->shares_last_hw) >= state->shares_to_good) &&
modminer->temp < MODMINER_TEMP_UP_LIMIT) modminer->temp < MODMINER_TEMP_UP_LIMIT)
modminer_delta_clock(thr, MODMINER_CLOCK_UP, false); modminer_delta_clock(thr, MODMINER_CLOCK_UP, false, false);
} }
} else { } else {
// on rare occasions - the MMQ can just stop returning valid nonces // on rare occasions - the MMQ can just stop returning valid nonces
@ -967,7 +973,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
if (tdiff(&now, &state->last_nonce) >= death) { if (tdiff(&now, &state->last_nonce) >= death) {
if (state->death_stage_one) { if (state->death_stage_one) {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: DEATH clock down", applog(LOG_ERR, "%s%u: DEATH clock down",
modminer->api->name, modminer->device_id); modminer->api->name, modminer->device_id);
@ -977,7 +983,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
state->death_stage_one = false; state->death_stage_one = false;
return -1; return -1;
} else { } else {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: death clock down", applog(LOG_ERR, "%s%u: death clock down",
modminer->api->name, modminer->device_id); modminer->api->name, modminer->device_id);
@ -1097,11 +1103,50 @@ static void modminer_fpga_shutdown(struct thr_info *thr)
free(thr->cgpu_data); free(thr->cgpu_data);
} }
static char *modminer_set_device(struct cgpu_info *modminer, char *option, char *setting, char *replybuf)
{
const char *ret;
int val;
if (strcasecmp(option, "help") == 0) {
sprintf(replybuf, "clock: range %d-%d and a multiple of 2",
MODMINER_MIN_CLOCK, MODMINER_MAX_CLOCK);
return replybuf;
}
if (strcasecmp(option, "clock") == 0) {
if (!setting || !*setting) {
sprintf(replybuf, "missing clock setting");
return replybuf;
}
val = atoi(setting);
if (val < MODMINER_MIN_CLOCK || val > MODMINER_MAX_CLOCK || (val & 1) != 0) {
sprintf(replybuf, "invalid clock: '%s' valid range %d-%d and a multiple of 2",
setting, MODMINER_MIN_CLOCK, MODMINER_MAX_CLOCK);
return replybuf;
}
val -= (int)(modminer->clock);
ret = modminer_delta_clock(modminer->thr[0], val, false, true);
if (ret) {
sprintf(replybuf, "Set clock failed: %s", ret);
return replybuf;
} else
return NULL;
}
sprintf(replybuf, "Unknown option: %s", option);
return replybuf;
}
struct device_api modminer_api = { struct device_api modminer_api = {
.dname = "modminer", .dname = "modminer",
.name = "MMQ", .name = "MMQ",
.api_detect = modminer_detect, .api_detect = modminer_detect,
.get_statline_before = get_modminer_statline_before, .get_statline_before = get_modminer_statline_before,
.set_device = modminer_set_device,
.thread_prepare = modminer_fpga_prepare, .thread_prepare = modminer_fpga_prepare,
.thread_init = modminer_fpga_init, .thread_init = modminer_fpga_init,
.scanhash = modminer_scanhash, .scanhash = modminer_scanhash,

1
miner.h

@ -277,6 +277,7 @@ struct device_api {
struct api_data *(*get_api_stats)(struct cgpu_info *); struct api_data *(*get_api_stats)(struct cgpu_info *);
bool (*get_stats)(struct cgpu_info *); bool (*get_stats)(struct cgpu_info *);
void (*identify_device)(struct cgpu_info *); // e.g. to flash a led void (*identify_device)(struct cgpu_info *); // e.g. to flash a led
char *(*set_device)(struct cgpu_info *, char *option, char *setting, char *replybuf);
// Thread-specific functions // Thread-specific functions
bool (*thread_prepare)(struct thr_info *); bool (*thread_prepare)(struct thr_info *);

Loading…
Cancel
Save