Commit 89039fd2 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

sdb: support v2 API which reports MSI addresses

parent 095efd27
......@@ -177,7 +177,8 @@ static void eb_sdb_component_decode(struct sdb_component* component, eb_address_
static void eb_sdb_decode(eb_sdb_scan_t scanp, eb_device_t device, uint8_t* buf, uint16_t size, eb_operation_t ops) {
eb_user_data_t data;
sdb_callback_t cb;
sdb_callback_t cb1;
sdb_callback2_t cb2;
eb_address_t bus_base;
eb_address_t msi_base;
struct sdb_table* sdb;
......@@ -188,13 +189,15 @@ static void eb_sdb_decode(eb_sdb_scan_t scanp, eb_device_t device, uint8_t* buf,
scan = EB_SDB_SCAN(scanp);
meta = EB_SDB_SCAN_META(scan->meta);
cb = scan->cb;
data = scan->user_data;
cb1 = scan->cb1;
cb2 = scan->cb2;
data = meta->user_data;
bus_base = meta->bus_base;
msi_base = meta->msi_base;
if (eb_sdb_fill_block(buf, size, ops) != 0) {
(*cb)(data, device, 0, EB_FAIL);
if (cb1) (*cb1)(data, device, 0, EB_FAIL);
if (cb2) (*cb2)(data, device, 0, 0, EB_FAIL);
return;
}
......@@ -206,7 +209,8 @@ static void eb_sdb_decode(eb_sdb_scan_t scanp, eb_device_t device, uint8_t* buf,
eb_sdb_component_decode(&sdb->interconnect.sdb_component, bus_base);
if (sizeof(struct sdb_device) * sdb->interconnect.sdb_records > size) {
(*cb)(data, device, 0, EB_FAIL);
if (cb1) (*cb1)(data, device, 0, EB_FAIL);
if (cb2) (*cb2)(data, device, 0, 0, EB_FAIL);
return;
}
......@@ -230,6 +234,9 @@ static void eb_sdb_decode(eb_sdb_scan_t scanp, eb_device_t device, uint8_t* buf,
r->msi.msi_flags = be32toh(r->msi.msi_flags);
r->msi.bus_specific = be32toh(r->msi.bus_specific);
eb_sdb_component_decode(&r->msi.sdb_component, msi_base);
/* If this is the active crossbar, include the MSI target */
if ((r->msi.msi_flags >> 31) != 0)
msi_base += r->msi.sdb_component.addr_first;
break;
case sdb_record_integration:
......@@ -245,7 +252,8 @@ static void eb_sdb_decode(eb_sdb_scan_t scanp, eb_device_t device, uint8_t* buf,
}
}
(*cb)(data, device, sdb, EB_OK);
if (cb1) (*cb1)(data, device, sdb, EB_OK);
if (cb2) (*cb2)(data, device, sdb, msi_base, EB_OK);
}
/* We allocate buffer on the stack to hack around missing alloca */
......@@ -272,6 +280,7 @@ EB_SDB_DECODE(256)
static void eb_sdb_got_record(eb_user_data_t mydata, eb_device_t device, eb_operation_t ops, eb_status_t status) {
struct eb_sdb_record* record;
struct eb_sdb_scan* scan;
struct eb_sdb_scan_meta* meta;
struct eb_operation* op;
struct eb_operation* op2;
struct eb_operation* opi;
......@@ -281,7 +290,8 @@ static void eb_sdb_got_record(eb_user_data_t mydata, eb_device_t device, eb_oper
eb_operation_t op2p;
eb_operation_t opip;
eb_user_data_t data;
sdb_callback_t cb;
sdb_callback_t cb1;
sdb_callback2_t cb2;
uint16_t devices;
recordp = (eb_sdb_record_t)(uintptr_t)mydata;
......@@ -321,11 +331,15 @@ static void eb_sdb_got_record(eb_user_data_t mydata, eb_device_t device, eb_oper
scanp = record->scan;
scan = EB_SDB_SCAN(scanp);
metap = scan->meta;
cb = scan->cb;
data = scan->user_data;
cb1 = scan->cb1;
cb2 = scan->cb2;
meta = EB_SDB_SCAN_META(metap);
data = meta->user_data;
if (record->status != EB_OK) {
(*cb)(data, device, 0, record->status);
if (cb1) (*cb1)(data, device, 0, record->status);
if (cb2) (*cb2)(data, device, 0, 0, record->status);
} else {
devices = record->records - 1;
......@@ -336,7 +350,10 @@ static void eb_sdb_got_record(eb_user_data_t mydata, eb_device_t device, eb_oper
else if (devices < 64) eb_sdb_decode64(scanp, device, record->ops);
else if (devices < 128) eb_sdb_decode128(scanp, device, record->ops);
else if (devices < 256) eb_sdb_decode256(scanp, device, record->ops);
else (*cb)(data, device, 0, EB_OOM);
else {
if (cb1) (*cb1)(data, device, 0, EB_OOM);
if (cb2) (*cb2)(data, device, 0, 0, EB_OOM);
}
}
/* Free everything */
......@@ -358,12 +375,14 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
uint8_t bytes[1];
} header;
struct eb_sdb_scan* scan;
struct eb_sdb_scan_meta* meta;
struct eb_sdb_record* record;
eb_sdb_scan_t scanp;
eb_sdb_scan_meta_t metap;
eb_sdb_record_t recordp;
eb_user_data_t data;
sdb_callback_t cb;
sdb_callback_t cb1;
sdb_callback2_t cb2;
eb_address_t address, end;
eb_cycle_t cycle;
int stride;
......@@ -371,17 +390,20 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
scanp = (eb_sdb_scan_t)(uintptr_t)mydata;
scan = EB_SDB_SCAN(scanp);
cb = scan->cb;
data = scan->user_data;
cb1 = scan->cb1;
cb2 = scan->cb2;
metap = scan->meta;
meta = EB_SDB_SCAN_META(metap);
data = meta->user_data;
stride = (eb_device_width(device) & EB_DATAX);
if (status != EB_OK) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, status);
if (cb1) (*cb1)(data, device, 0, status);
if (cb2) (*cb2)(data, device, 0, 0, status);
return;
}
......@@ -389,7 +411,8 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
if (eb_sdb_fill_block(&header.bytes[0], sizeof(header), ops) != 0) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, EB_FAIL);
if (cb1) (*cb1)(data, device, 0, EB_FAIL);
if (cb2) (*cb2)(data, device, 0, 0, EB_FAIL);
return;
}
......@@ -397,7 +420,8 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
if (be32toh(header.interconnect.sdb_magic) != SDB_MAGIC) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, EB_FAIL);
if (cb1) (*cb1)(data, device, 0, EB_FAIL);
if (cb2) (*cb2)(data, device, 0, 0, EB_FAIL);
return;
}
......@@ -405,7 +429,8 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
if ((recordp = eb_new_sdb_record()) == EB_NULL) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, EB_OOM);
if (cb1) (*cb1)(data, device, 0, EB_OOM);
if (cb2) (*cb2)(data, device, 0, 0, EB_OOM);
return;
}
......@@ -435,7 +460,7 @@ static void eb_sdb_got_header(eb_user_data_t mydata, eb_device_t device, eb_oper
}
}
eb_status_t eb_sdb_scan_bus(eb_device_t device, const struct sdb_bridge* bridge, eb_user_data_t data, sdb_callback_t cb) {
static eb_status_t eb_sdb_scan_bus_real(eb_device_t device, const struct sdb_bridge* bridge, eb_address_t msi_base, eb_user_data_t data, sdb_callback_t cb1, sdb_callback2_t cb2) {
struct eb_sdb_scan* scan;
struct eb_sdb_scan_meta* meta;
eb_cycle_t cycle;
......@@ -457,13 +482,14 @@ eb_status_t eb_sdb_scan_bus(eb_device_t device, const struct sdb_bridge* bridge,
}
scan = EB_SDB_SCAN(scanp);
scan->cb = cb;
scan->user_data = data;
scan->cb1 = cb1;
scan->cb2 = cb2;
scan->meta = metap;
meta = EB_SDB_SCAN_META(metap);
meta->bus_base = bridge->sdb_component.addr_first;
meta->msi_base = 0; // !!!
meta->msi_base = msi_base;
meta->user_data = data;
stride = (eb_device_width(device) & EB_DATAX);
......@@ -483,30 +509,43 @@ eb_status_t eb_sdb_scan_bus(eb_device_t device, const struct sdb_bridge* bridge,
return EB_OK;
}
eb_status_t eb_sdb_scan_bus(eb_device_t device, const struct sdb_bridge* bridge, eb_user_data_t data, sdb_callback_t cb) {
return eb_sdb_scan_bus_real(device, bridge, 0, data, cb, 0);
}
eb_status_t eb_sdb_scan_bus2(eb_device_t device, const struct sdb_bridge* bridge, eb_address_t msi_base, eb_user_data_t data, sdb_callback2_t cb) {
return eb_sdb_scan_bus_real(device, bridge, msi_base, data, 0, cb);
}
static void eb_sdb_got_header_ptr(eb_user_data_t mydata, eb_device_t device, eb_operation_t ops, eb_status_t status) {
struct eb_sdb_scan* scan;
struct eb_sdb_scan_meta* meta;
eb_sdb_scan_t scanp;
eb_sdb_scan_meta_t metap;
eb_user_data_t data;
eb_address_t header_address;
eb_address_t header_end;
sdb_callback_t cb;
sdb_callback_t cb1;
sdb_callback2_t cb2;
eb_cycle_t cycle;
int stride;
scanp = (eb_sdb_scan_t)(uintptr_t)mydata;
scan = EB_SDB_SCAN(scanp);
cb = scan->cb;
data = scan->user_data;
cb1 = scan->cb1;
cb2 = scan->cb2;
metap = scan->meta;
meta = EB_SDB_SCAN_META(metap);
data = meta->user_data;
stride = (eb_device_width(device) & EB_DATAX);
if (status != EB_OK) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, status);
if (cb1) (*cb1)(data, device, 0, status);
if (cb2) (*cb2)(data, device, 0, 0, status);
return;
}
......@@ -516,7 +555,8 @@ static void eb_sdb_got_header_ptr(eb_user_data_t mydata, eb_device_t device, eb_
if (eb_operation_had_error(ops)) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, EB_FAIL);
if (cb1) (*cb1)(data, device, 0, EB_FAIL);
if (cb2) (*cb2)(data, device, 0, 0, EB_FAIL);
return;
}
header_address <<= (stride*8);
......@@ -527,7 +567,8 @@ static void eb_sdb_got_header_ptr(eb_user_data_t mydata, eb_device_t device, eb_
if ((status = eb_cycle_open(device, (eb_user_data_t)(uintptr_t)scanp, &eb_sdb_got_header, &cycle)) != EB_OK) {
eb_free_sdb_scan(scanp);
eb_free_sdb_scan_meta(metap);
(*cb)(data, device, 0, status);
if (cb1) (*cb1)(data, device, 0, status);
if (cb2) (*cb2)(data, device, 0, 0, status);
return;
}
......@@ -537,7 +578,7 @@ static void eb_sdb_got_header_ptr(eb_user_data_t mydata, eb_device_t device, eb_
eb_cycle_close(cycle);
}
eb_status_t eb_sdb_scan_root(eb_device_t device, eb_user_data_t data, sdb_callback_t cb) {
static eb_status_t eb_sdb_scan_root_real(eb_device_t device, eb_user_data_t data, sdb_callback_t cb1, sdb_callback2_t cb2) {
struct eb_sdb_scan* scan;
struct eb_sdb_scan_meta* meta;
eb_cycle_t cycle;
......@@ -554,13 +595,14 @@ eb_status_t eb_sdb_scan_root(eb_device_t device, eb_user_data_t data, sdb_callba
}
scan = EB_SDB_SCAN(scanp);
scan->cb = cb;
scan->user_data = data;
scan->cb1 = cb1;
scan->cb2 = cb2;
scan->meta = metap;
meta = EB_SDB_SCAN_META(metap);
meta->bus_base = 0;
meta->msi_base = 0;
meta->user_data = data;
stride = (eb_device_width(device) & EB_DATAX);
......@@ -579,13 +621,22 @@ eb_status_t eb_sdb_scan_root(eb_device_t device, eb_user_data_t data, sdb_callba
return EB_OK;
}
eb_status_t eb_sdb_scan_root(eb_device_t device, eb_user_data_t data, sdb_callback_t cb) {
return eb_sdb_scan_root_real(device, data, cb, 0);
}
eb_status_t eb_sdb_scan_root2(eb_device_t device, eb_user_data_t data, sdb_callback2_t cb) {
return eb_sdb_scan_root_real(device, data, 0, cb);
}
struct eb_find_by_address {
eb_address_t address;
struct sdb_device* output;
eb_address_t* msi_base;
eb_status_t status;
};
static void eb_cb_find_by_address(eb_user_data_t data, eb_device_t dev, const struct sdb_table* sdb, eb_status_t status) {
static void eb_cb_find_by_address(eb_user_data_t data, eb_device_t dev, const struct sdb_table* sdb, eb_address_t msi_base, eb_status_t status) {
int i, devices;
const union sdb_record* des;
struct eb_find_by_address* record;
......@@ -604,7 +655,7 @@ static void eb_cb_find_by_address(eb_user_data_t data, eb_device_t dev, const st
if (des->empty.record_type == sdb_record_bridge &&
des->bridge.sdb_component.addr_first <= record->address && record->address <= des->bridge.sdb_component.addr_last) {
if ((status = eb_sdb_scan_bus(dev, &des->bridge, data, &eb_cb_find_by_address)) != EB_OK) {
if ((status = eb_sdb_scan_bus2(dev, &des->bridge, msi_base, data, &eb_cb_find_by_address)) != EB_OK) {
record->status = status;
}
return;
......@@ -613,6 +664,7 @@ static void eb_cb_find_by_address(eb_user_data_t data, eb_device_t dev, const st
if (des->empty.record_type == sdb_record_device &&
des->device.sdb_component.addr_first <= record->address && record->address <= des->device.sdb_component.addr_last) {
memcpy(record->output, des, sizeof(struct sdb_device));
*record->msi_base = msi_base;
record->status = EB_OK;
return;
}
......@@ -624,13 +676,14 @@ static void eb_cb_find_by_address(eb_user_data_t data, eb_device_t dev, const st
record->status = EB_ADDRESS;
}
eb_status_t eb_sdb_find_by_address(eb_device_t device, eb_address_t address, struct sdb_device* output) {
eb_status_t eb_sdb_find_by_address2(eb_device_t device, eb_address_t address, struct sdb_device* output, eb_address_t* msi_base) {
struct eb_find_by_address record;
record.address = address;
record.output = output;
record.msi_base= msi_base;
if ((record.status = eb_sdb_scan_root(device, &record, eb_cb_find_by_address)) == EB_OK) {
if ((record.status = eb_sdb_scan_root2(device, &record, eb_cb_find_by_address)) == EB_OK) {
record.status = 1;
while (record.status > 0) {
eb_socket_run(eb_device_socket(device), -1);
......@@ -640,17 +693,25 @@ eb_status_t eb_sdb_find_by_address(eb_device_t device, eb_address_t address, str
return record.status;
}
eb_status_t eb_sdb_find_by_address(eb_device_t device, eb_address_t address, struct sdb_device* output) {
eb_address_t null;
return eb_sdb_find_by_address2(device, address, output, &null);
}
struct eb_find_by_identity {
uint64_t vendor_id;
struct sdb_device* output;
eb_address_t* output_msi;
uint32_t device_id;
int size;
int fill;
int size_output;
int size_msi;
int fill_output;
int fill_msi;
int pending;
eb_status_t status;
};
static void eb_cb_find_by_identity(eb_user_data_t data, eb_device_t dev, const struct sdb_table* sdb, eb_status_t status) {
static void eb_cb_find_by_identity(eb_user_data_t data, eb_device_t dev, const struct sdb_table* sdb, eb_address_t msi_base, eb_status_t status) {
int i, devices;
const union sdb_record* des;
struct eb_find_by_identity* record;
......@@ -669,7 +730,7 @@ static void eb_cb_find_by_identity(eb_user_data_t data, eb_device_t dev, const s
des = &sdb->record[i];
if (des->empty.record_type == sdb_record_bridge) {
if ((status = eb_sdb_scan_bus(dev, &des->bridge, data, &eb_cb_find_by_identity)) == EB_OK) {
if ((status = eb_sdb_scan_bus2(dev, &des->bridge, msi_base, data, &eb_cb_find_by_identity)) == EB_OK) {
++record->pending;
} else {
record->status = status;
......@@ -681,45 +742,65 @@ static void eb_cb_find_by_identity(eb_user_data_t data, eb_device_t dev, const s
des->empty.record_type == sdb_record_msi) &&
des->device.sdb_component.product.vendor_id == record->vendor_id &&
des->device.sdb_component.product.device_id == record->device_id) {
if (record->fill < record->size)
memcpy(record->output+record->fill, des, sizeof(struct sdb_device));
++record->fill;
if (record->fill_output < record->size_output)
memcpy(record->output+record->fill_output, des, sizeof(struct sdb_device));
++record->fill_output;
if (record->fill_msi < record->size_msi)
record->output_msi[record->fill_msi] = msi_base;
}
}
}
eb_status_t eb_sdb_find_by_identity(eb_device_t device, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, int* devices) {
static eb_status_t eb_sdb_find_by_identity_real(
eb_device_t device,
uint64_t vendor_id,
uint32_t device_id,
const struct sdb_bridge* bridge,
eb_address_t msi_base,
struct sdb_device* output,
eb_address_t* output_msi,
int* devices,
int msis)
{
struct eb_find_by_identity record;
record.vendor_id = vendor_id;
record.device_id = device_id;
record.size = *devices;
record.fill = 0;
record.size_output = *devices;
record.size_msi = msis;
record.fill_output = 0;
record.fill_msi = 0;
record.pending = 1;
record.output = output;
record.output_msi = output_msi;
if ((record.status = eb_sdb_scan_root(device, &record, eb_cb_find_by_identity)) == EB_OK)
while (record.pending > 0)
eb_socket_run(eb_device_socket(device), -1);
if (bridge) {
if ((record.status = eb_sdb_scan_root2(device, &record, eb_cb_find_by_identity)) == EB_OK)
while (record.pending > 0)
eb_socket_run(eb_device_socket(device), -1);
} else {
if ((record.status = eb_sdb_scan_bus2(device, bridge, msi_base, &record, eb_cb_find_by_identity)) == EB_OK)
while (record.pending > 0)
eb_socket_run(eb_device_socket(device), -1);
*devices = record.fill;
}
*devices = record.fill_output;
return record.status;
}
eb_status_t eb_sdb_find_by_identity_at(eb_device_t device, const struct sdb_bridge* bridge, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, int* devices) {
struct eb_find_by_identity record;
record.vendor_id = vendor_id;
record.device_id = device_id;
record.size = *devices;
record.fill = 0;
record.pending = 1;
record.output = output;
eb_status_t eb_sdb_find_by_identity2(eb_device_t device, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, eb_address_t* output_msi, int* devices) {
return eb_sdb_find_by_identity_real(device, vendor_id, device_id, 0, 0, output, output_msi, devices, *devices);
}
if ((record.status = eb_sdb_scan_bus(device, bridge, &record, eb_cb_find_by_identity)) == EB_OK)
while (record.pending > 0)
eb_socket_run(eb_device_socket(device), -1);
*devices = record.fill;
return record.status;
eb_status_t eb_sdb_find_by_identity(eb_device_t device, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, int* devices) {
return eb_sdb_find_by_identity_real(device, vendor_id, device_id, 0, 0, output, 0, devices, 0);
}
eb_status_t eb_sdb_find_by_identity_at2(eb_device_t device, const struct sdb_bridge* bridge, eb_address_t msi_base, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, eb_address_t* output_msi, int* devices) {
return eb_sdb_find_by_identity_real(device, vendor_id, device_id, bridge, msi_base, output, output_msi, devices, *devices);
}
eb_status_t eb_sdb_find_by_identity_at(eb_device_t device, const struct sdb_bridge* bridge, uint64_t vendor_id, uint32_t device_id, struct sdb_device* output, int* devices) {
return eb_sdb_find_by_identity_real(device, vendor_id, device_id, bridge, 0, output, 0, devices, 0);
}
......@@ -34,12 +34,13 @@ typedef EB_POINTER(eb_sdb_scan_meta) eb_sdb_scan_meta_t;
struct eb_sdb_scan_meta {
eb_address_t msi_base;
eb_address_t bus_base;
eb_user_data_t user_data;
};
typedef EB_POINTER(eb_sdb_scan) eb_sdb_scan_t;
struct eb_sdb_scan {
eb_user_data_t user_data;
sdb_callback_t cb;
sdb_callback_t cb1;
sdb_callback2_t cb2;
eb_sdb_scan_meta_t meta;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment