summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2021-09-24 12:40:42 +0200
committerSimon Rettberg2021-09-24 12:40:42 +0200
commitc32dd3654eaf99121cc44a3f828883a69e7760e5 (patch)
treefee100b5ed24a9a5c679c586e72194b59e03221f
parent[statistics/passthrough] Fixes (diff)
downloadslx-admin-c32dd3654eaf99121cc44a3f828883a69e7760e5.tar.gz
slx-admin-c32dd3654eaf99121cc44a3f828883a69e7760e5.tar.xz
slx-admin-c32dd3654eaf99121cc44a3f828883a69e7760e5.zip
[statistics/passthrough] WIP
-rw-r--r--modules-available/passthrough/inc/passthrough.inc.php17
-rw-r--r--modules-available/passthrough/page.inc.php39
-rw-r--r--modules-available/passthrough/templates/hardware-list.html39
-rw-r--r--modules-available/statistics/api.inc.php2
-rw-r--r--modules-available/statistics/inc/hardwareinfo.inc.php19
-rw-r--r--modules-available/statistics/inc/hardwareparser.inc.php6
-rw-r--r--modules-available/statistics/inc/hardwarequery.inc.php22
-rw-r--r--modules-available/statistics/inc/pciid.inc.php15
-rw-r--r--modules-available/statistics/page.inc.php24
9 files changed, 156 insertions, 27 deletions
diff --git a/modules-available/passthrough/inc/passthrough.inc.php b/modules-available/passthrough/inc/passthrough.inc.php
index 51fe7214..524aea5e 100644
--- a/modules-available/passthrough/inc/passthrough.inc.php
+++ b/modules-available/passthrough/inc/passthrough.inc.php
@@ -3,16 +3,27 @@
class Passthrough
{
- public static function getGroupDropdown(array $row): array
+ public static function getGroupDropdown(array &$row): array
{
+ $out = [];
+ if ($row['class'] === '0300') {
+ foreach (['GPU', 'GVT'] as $id) {
+ $out[] = [
+ 'ptid' => $id,
+ 'ptname' => $id,
+ 'selected' => ($row['@PASSTHROUGH'] === $id ? 'selected' : ''),
+ ];
+ }
+ return $out;
+ }
static $list = false;
if ($list === false) {
$list = Database::queryKeyValueList("SELECT groupid, title FROM passthrough_group ORDER BY groupid");
self::ensurePrepopulated($list);
}
- $out = [];
+ $row['custom_groups'] = true;
foreach ($list as $id => $title) {
- if ($row['class'] !== '0300' && ($id === 'GPU' || $id === 'GVT'))
+ if ($id === 'GPU' || $id === 'GVT')
continue;
$item = ['ptid' => $id, 'ptname' => $id . ' (' . $title . ')'];
if ($row['@PASSTHROUGH'] === $id) {
diff --git a/modules-available/passthrough/page.inc.php b/modules-available/passthrough/page.inc.php
index 33f2e4a3..0911550c 100644
--- a/modules-available/passthrough/page.inc.php
+++ b/modules-available/passthrough/page.inc.php
@@ -87,11 +87,42 @@ class Page_Passthrough extends Page
return 1;
return hexdec($a) - hexdec($b);
});
- foreach ($rows as &$row) {
- $row['vendor_name'] = PciId::getPciId(PciId::VENDOR, $row['vendor'] ?? '', true);
- $row['device_name'] = PciId::getPciId(PciId::DEVICE, $row['vendor'] . ':' . $row['device'], true);
+ $finalRows = [];
+ $missing = [];
+ $lastClass = '';
+ foreach ($rows as $row) {
+ if ($row['class'] !== $lastClass) {
+ // Add class row header
+ $lastClass = $row['class'];
+ $finalRows[] = [
+ 'class' => $row['class'],
+ 'class_name' => PciId::getPciId(PciId::DEVCLASS, $row['class'], true) ?: 'Unknown',
+ ];
+ }
+ $row['vendor_name'] = PciId::getPciId(PciId::VENDOR, $row['vendor'] ?? '');
+ $row['device_name'] = PciId::getPciId(PciId::DEVICE, $row['vendor'] . ':' . $row['device']);
+ $finalRows[] = $row;
+ // Build up query
+ if ($row['vendor_name'] === false) {
+ $missing[$row['vendor']] = true;
+ }
+ if ($row['device_name'] === false) {
+ $missing[$row['vendor'] . ':' . $row['device']] = true;
+ }
}
- Render::addTemplate('hardware-list', ['list' => $rows]);
+ Render::addTemplate('hardware-list', [
+ 'list' => $finalRows,
+ 'missing_ids' => json_encode(array_keys($missing)),
+ ]);
+ }
+
+ /*
+ *
+ */
+
+ protected function doAjax()
+ {
+ //
}
} \ No newline at end of file
diff --git a/modules-available/passthrough/templates/hardware-list.html b/modules-available/passthrough/templates/hardware-list.html
index 2450e457..d331acb5 100644
--- a/modules-available/passthrough/templates/hardware-list.html
+++ b/modules-available/passthrough/templates/hardware-list.html
@@ -3,7 +3,6 @@
<table class="table">
<thead>
<tr>
- <th class="slx-smallcol">{{lang_class}}</th>
<th class="slx-smallcol">{{lang_deviceIdNumeric}}</th>
<th>{{lang_deviceName}}</th>
<th class="slx-smallcol">{{lang_useCount}}</th>
@@ -13,25 +12,35 @@
<tbody>
{{#list}}
<tr>
- <td>{{class}}</td>
+ {{#class_name}}
+ <td colspan="4">
+ <span>{{class}}</span> – <strong>{{class_name}}</strong>
+ </td>
+ {{/class_name}}
+ {{^class_name}}
<td>{{vendor}}:{{device}}</td>
<td>
<table class="slx-ellipsis">
<tr>
- <td>{{device_name}}</td>
+ <td {{^device_name}}class="query-{{vendor}}-{{device}}"{{/device_name}}>
+ {{device_name}}
+ </td>
</tr>
</table>
- <div class="small">{{vendor_name}}</div>
+ <div class="small {{^vendor_name}}query-{{vendor}}{{/vendor_name}}">
+ {{vendor_name}}
+ </div>
</td>
<td class="text-right">{{connected_count}}</td>
<td>
- <select name="ptgroup[{{hwid}}]" class="form-control ptgroup-select">
+ <select name="ptgroup[{{hwid}}]" class="form-control {{#custom_groups}}ptgroup-select{{/custom_groups}}">
<option value="">{{lang_noPassthroughGroup}}</option>
{{#ptlist}}
<option value="{{ptid}}" {{selected}}>{{ptname}}</option>
{{/ptlist}}
</select>
</td>
+ {{/class_name}}
</tr>
{{/list}}
</tbody>
@@ -92,5 +101,25 @@
$(this).append($('<option>').attr('value', gid).text(gid + ' (' + title + ')'));
});
});
+ var missing = {{{missing_ids}}};
+ var doQuery = function() {
+ if (missing && missing.length > 0) {
+ $.ajax({
+ url: '?do=statistics', dataType: "json", method: "POST", data: {
+ token: TOKEN,
+ action: 'json-lookup',
+ list: missing.splice(0, 10) // Query 10 at a time max
+ }
+ }).done(function (data) {
+ if (!data)
+ return;
+ for (var k in data) {
+ $('.query-' + k.replace(':', '-')).text(data[k]);
+ }
+ doQuery();
+ });
+ }
+ }
+ doQuery();
});
</script> \ No newline at end of file
diff --git a/modules-available/statistics/api.inc.php b/modules-available/statistics/api.inc.php
index 749557a6..b06d4503 100644
--- a/modules-available/statistics/api.inc.php
+++ b/modules-available/statistics/api.inc.php
@@ -1,7 +1,7 @@
<?php
if (Request::any('action') === 'test' && isLocalExecution()) {
- error_log(HardwareInfo::getKclModifications('0A5D9E23-80F4-9C43-912C-96D80AE7E80B'));
+ error_log(HardwareInfo::getKclModifications());
exit;
$x = new HardwareQuery(HardwareInfo::PCI_DEVICE);
//$x->addCompare(false, 'Memory Slot Occupied', '>=', true, 'Memory Slot Count');
diff --git a/modules-available/statistics/inc/hardwareinfo.inc.php b/modules-available/statistics/inc/hardwareinfo.inc.php
index 90b8975b..5f1a4372 100644
--- a/modules-available/statistics/inc/hardwareinfo.inc.php
+++ b/modules-available/statistics/inc/hardwareinfo.inc.php
@@ -44,14 +44,18 @@ class HardwareInfo
$hw->addWhere(true, '@PASSTHROUGH', 'IN', ['GPU', 'GVT']);
$hw->addColumn(true, 'vendor');
$hw->addColumn(true, 'device');
+ $hw->addColumn(false, 'slot');
$res = $hw->query();
$passthrough = [];
+ $slots = [];
$gvt = false;
foreach ($res as $row) {
if ($row['@PASSTHROUGH'] === 'GVT') {
$gvt = true;
} else {
- $passthrough[] = $row['vendor'] . ':' . $row['device'];
+ $passthrough[$row['vendor'] . ':' . $row['device']] = 1;
+ error_log('Passthouorgh: ' . $row['vendor'] . ':' . $row['device']);
+ $slots[preg_replace('/\.[0-9]+$/', '', $row['slot'])] = 1;
}
}
$kcl = '';
@@ -59,7 +63,18 @@ class HardwareInfo
$kcl = '-iommu -intel_iommu iommu=pt intel_iommu=on'; // TODO AMD
}
if (!empty($passthrough)) {
- $kcl .= ' vfio-pci.ids=' . implode(',', $passthrough);
+ foreach (array_keys($slots) as $slot) {
+ error_log('Querying slot ' . $slot);
+ $hw = new HardwareQuery(self::PCI_DEVICE, $best['machineuuid'], true);
+ $hw->addWhere(false, 'slot', 'LIKE', $slot . '.%');
+ $hw->addColumn(true, 'vendor');
+ $hw->addColumn(true, 'device');
+ foreach ($hw->query() as $row) {
+ $passthrough[$row['vendor'] . ':' . $row['device']] = 1;
+ error_log('Extra PT: ' . $row['vendor'] . ':' . $row['device']);
+ }
+ }
+ $kcl .= ' vfio-pci.ids=' . implode(',', array_keys($passthrough));
}
if ($gvt) {
$kcl .= ' i915.enable_gvt=1';
diff --git a/modules-available/statistics/inc/hardwareparser.inc.php b/modules-available/statistics/inc/hardwareparser.inc.php
index 562c5948..5ba1e3dd 100644
--- a/modules-available/statistics/inc/hardwareparser.inc.php
+++ b/modules-available/statistics/inc/hardwareparser.inc.php
@@ -714,8 +714,10 @@ class HardwareParser
// ---- lspci ------------------------------------
$pciHwIds = [];
foreach (($data['lspci'] ?? []) as $dev) {
- $hwid = self::writeGlobalHardwareData(HardwareInfo::PCI_DEVICE,
- self::propsFromArray($dev, 'vendor', 'device', 'rev', 'class'));
+ $props = self::propsFromArray($dev, 'vendor', 'device', 'rev', 'class');
+ if (!isset($props['vendor']) || !isset($props['device']))
+ continue;
+ $hwid = self::writeGlobalHardwareData(HardwareInfo::PCI_DEVICE, $props);
$mappingId = self::writeLocalHardwareData($uuid, $hwid, $dev['slot'] ?? 'unknown',
self::propsFromArray($dev, 'slot', 'subsystem', 'subsystem_vendor', 'iommu_group'));
$pciHwIds[] = $mappingId;
diff --git a/modules-available/statistics/inc/hardwarequery.inc.php b/modules-available/statistics/inc/hardwarequery.inc.php
index b0b7d6ee..c7ecb35e 100644
--- a/modules-available/statistics/inc/hardwarequery.inc.php
+++ b/modules-available/statistics/inc/hardwarequery.inc.php
@@ -68,6 +68,18 @@ class HardwareQuery
$this->columns[$prop] = "$tid.`value` AS `$prop`";
}
+ public function addMachineWhere(string $column, string $op, $value)
+ {
+ if (isset($this->columns[$column]))
+ return;
+ $valueCol = ($op === '<' || $op === '>' || $op === '<=' || $op === '>=') ? 'numeric' : 'value';
+ $vid = $this->id();
+ $this->joins['machine'] = 'INNER JOIN machine m USING (machineuuid)';
+ $this->where[] = "m.$column $op :$vid";
+ $this->args[$vid] = $value;
+ $this->columns[$column] = "m.$column";
+ }
+
public function addCompare(bool $global1, string $prop1, string $op, string $global2, string $prop2)
{
$this->fillTableVars($global1, $srcTable1, $table1, $column1);
@@ -86,6 +98,16 @@ class HardwareQuery
$this->columns[$prop1] = "$tid1.`value` AS `$prop1`";
}
+ public function addGlobalColumn(string $prop)
+ {
+ $this->addColumn(true, $prop);
+ }
+
+ public function addLocalColumn(string $prop)
+ {
+ $this->addColumn(false, $prop);
+ }
+
public function addColumn(bool $global, string $prop)
{
if (isset($this->columns[$prop]))
diff --git a/modules-available/statistics/inc/pciid.inc.php b/modules-available/statistics/inc/pciid.inc.php
index 6bf852e6..65edf570 100644
--- a/modules-available/statistics/inc/pciid.inc.php
+++ b/modules-available/statistics/inc/pciid.inc.php
@@ -6,10 +6,11 @@ class PciId
const DEVICE = 'DEVICE';
const VENDOR = 'VENDOR';
const DEVCLASS = 'CLASS';
+ const AUTO = 'AUTO';
/**
- * @param string $cat type of query - self::DEVICE, self::VENDOR or self::DEVCLASS
+ * @param string $cat type of query - self::DEVICE, self::VENDOR, self::DEVCLASS or self::AUTO for auto detection
* @param string $id the id to query - depends on $cat
* @return string|false Name of Class/Vendor/Device, false if not found
*/
@@ -19,6 +20,18 @@ class PciId
if ($cat === self::DEVCLASS && $id[1] !== '.') {
$id = 'c.' . $id;
}
+ if ($cat === self::AUTO) {
+ if (preg_match('/^([a-f0-9]{4}):([a-f0-9]{4})$/', $id, $out)) {
+ $cat = 'DEVICE';
+ } elseif (preg_match('/^([a-f0-9]{4})$/', $id, $out)) {
+ $cat = 'VENDOR';
+ } elseif (preg_match('/^c\.([a-f0-9]{2})([a-f0-9]{2})$/', $id, $out)) {
+ $cat = 'CLASS';
+ } else {
+ error_log('Invalid PCIID lookup format: ' . $id);
+ return false;
+ }
+ }
$key = $cat . '-' . $id;
if (isset($cache[$key]))
return $cache[$key];
diff --git a/modules-available/statistics/page.inc.php b/modules-available/statistics/page.inc.php
index d26649b6..baddd093 100644
--- a/modules-available/statistics/page.inc.php
+++ b/modules-available/statistics/page.inc.php
@@ -251,11 +251,24 @@ class Page_Statistics extends Page
{
if (!User::load())
return;
- if (Request::any('action') === 'bios') {
+ $action = Request::any('action');
+ if ($action === 'bios') {
require_once 'modules/statistics/pages/machine.inc.php';
SubPage::ajaxCheckBios();
return;
}
+ if ($action === 'json-lookup') {
+ $reply = [];
+ foreach (Request::post('list', [], 'array') as $item) {
+ $name = PciId::getPciId(PciId::AUTO, $item, true);
+ if ($name === false) {
+ $name = '?????';
+ }
+ $reply[$item] = $name;
+ }
+ header('Content-Type: application/json');
+ die(json_encode($reply));
+ }
$param = Request::any('lookup', false, 'string');
if ($param === false) {
@@ -263,16 +276,9 @@ class Page_Statistics extends Page
}
$add = '';
if (preg_match('/^([a-f0-9]{4}):([a-f0-9]{4})$/', $param, $out)) {
- $cat = 'DEVICE';
$add = ' (' . $param . ')';
- } elseif (preg_match('/^([a-f0-9]{4})$/', $param, $out)) {
- $cat = 'VENDOR';
- } elseif (preg_match('/^c\.([a-f0-9]{2})([a-f0-9]{2})$/', $param, $out)) {
- $cat = 'CLASS';
- } else {
- die('Invalid format requested');
}
- $cached = PciId::getPciId($cat, $param, true);
+ $cached = PciId::getPciId(PciId::AUTO, $param, true);
if ($cached === false) {
$cached = 'Unknown';
}