Commit fdd4b706 authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

sdb: move record out of the way of attached slave devices

parent ade1b729
......@@ -35,12 +35,16 @@
eb_status_t eb_socket_attach(eb_socket_t socketp, const struct eb_handler* handler) {
eb_handler_address_t addressp, i;
eb_handler_address_t *prev_ptr;
eb_handler_callback_t callbackp;
struct eb_socket* socket;
struct eb_socket_aux* aux;
struct eb_handler_address* address;
struct eb_handler_callback* callback;
eb_address_t new_first, new_last;
eb_address_t dev_first, dev_last;
eb_address_t scan_last;
int num_devices;
/* Get memory */
addressp = eb_new_handler_address();
......@@ -56,16 +60,38 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, const struct eb_handler* handl
new_first = handler->device->sdb_component.addr_first;
new_last = handler->device->sdb_component.addr_last;
/* Is the address range supported by our bus size? */
if (new_first != handler->device->sdb_component.addr_first || new_last != handler->device->sdb_component.addr_last)
/* Is the user an idiot? */
if (new_first > new_last) {
eb_free_handler_callback(callbackp);
eb_free_handler_address(addressp);
return EB_ADDRESS;
}
/* Does it overlap out reserved memory range? */
if (new_first < 0x4000) return EB_ADDRESS;
/* Is the address range supported by our bus size? */
if (new_first != handler->device->sdb_component.addr_first || new_last != handler->device->sdb_component.addr_last) {
eb_free_handler_callback(callbackp);
eb_free_handler_address(addressp);
return EB_ADDRESS;
}
socket = EB_SOCKET(socketp);
aux = EB_SOCKET_AUX(socket->aux);
/* See if there are already too many devices */
num_devices = 0;
for (i = socket->first_handler; i != EB_NULL; i = address->next) {
address = EB_HANDLER_ADDRESS(i);
++num_devices;
}
if (num_devices >= SDB_REQUIRED_SIZE/sizeof(struct sdb_empty)) {
eb_free_handler_callback(callbackp);
eb_free_handler_address(addressp);
return EB_OOM;
}
/* See if it overlaps other devices */
prev_ptr = &socket->first_handler;
for (i = socket->first_handler; i != EB_NULL; i = address->next) {
address = EB_HANDLER_ADDRESS(i);
......@@ -78,6 +104,13 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, const struct eb_handler* handl
eb_free_handler_address(addressp);
return EB_ADDRESS;
}
/* Is this the point for insert? */
if (new_first < dev_last) {
break;
} else {
prev_ptr = &address->next;
}
}
/* Insert the new virtual device */
......@@ -86,12 +119,42 @@ eb_status_t eb_socket_attach(eb_socket_t socketp, const struct eb_handler* handl
address->device = handler->device;
address->callback = callbackp;
callback->data = handler->data;
callback->read = handler->read;
callback->write = handler->write;
address->next = socket->first_handler;
socket->first_handler = addressp;
*prev_ptr = addressp;
address->next = i;
/* Find a good place for the SDB record */
scan_last = 0;
for (i = socket->first_handler; i != EB_NULL; i = address->next) {
address = EB_HANDLER_ADDRESS(i);
if ((eb_address_t)address->device->sdb_component.addr_first - scan_last >= SDB_REQUIRED_SIZE) {
aux->sdb_offset = scan_last;
break;
} else {
scan_last = address->device->sdb_component.addr_last+1;
scan_last = (scan_last+7) & ~(eb_address_t)7; // align upwards to 8-bytes
}
}
if (i == EB_NULL) {
if (socket->first_handler != EB_NULL &&
scan_last > (eb_address_t)(-1) - SDB_REQUIRED_SIZE) {
/* No space => abort! */
*prev_ptr = address->next;
eb_free_handler_callback(callbackp);
eb_free_handler_address(addressp);
return EB_ADDRESS;
} else {
/* No gaps big enough, but after them all, there is */
aux->sdb_offset = scan_last;
}
}
return EB_OK;
}
......
......@@ -143,12 +143,6 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr_b
eb_address_t dev_first, dev_last;
int fail;
/* SDB address? It's read only ... */
if (addr_b < 0x4000) {
*error = (*error << 1) | 1;
return;
}
socket = EB_SOCKET(socketp);
for (addressp = socket->first_handler; addressp != EB_NULL; addressp = address->next) {
address = EB_HANDLER_ADDRESS(addressp);
......@@ -179,19 +173,28 @@ void eb_socket_write(eb_socket_t socketp, eb_width_t widths, eb_address_t addr_b
}
eb_data_t eb_socket_read_config(eb_socket_t socketp, eb_width_t widths, eb_address_t addr, uint64_t error) {
/* We only support reading from the error shift register so far */
struct eb_socket* socket;
struct eb_socket_aux* aux;
eb_address_t sdb;
socket = EB_SOCKET(socketp);
aux = EB_SOCKET_AUX(socket->aux);
sdb = aux->sdb_offset;
/* We only support reading from the error shift register and SDB so far */
eb_data_t out;
int len;
uint8_t buf[16] = {
error >> 56, error >> 48, error >> 40, error >> 32,
error >> 24, error >> 16, error >> 8, error >> 0,
0, 0, 0, 0, 0, 0, 0, 0
sdb >> 56, sdb >> 48, sdb >> 40, sdb >> 32,
sdb >> 24, sdb >> 16, sdb >> 8, sdb >> 0,
};
len = (widths & EB_DATAX);
/* Read out of bounds */
if (addr >= 8) return 0;
if (addr >= 16) return 0;
/* Read memory -- config space always bigendian */
out = 0;
......@@ -209,16 +212,21 @@ eb_data_t eb_socket_read(eb_socket_t socketp, eb_width_t widths, eb_address_t ad
eb_handler_address_t addressp;
struct eb_handler_address* address;
struct eb_socket* socket;
struct eb_socket_aux* aux;
eb_address_t dev_first, dev_last;
eb_address_t sdb;
int fail;
socket = EB_SOCKET(socketp);
aux = EB_SOCKET_AUX(socket->aux);
sdb = aux->sdb_offset;
/* SDB address? */
if (addr_b < 0x4000) {
if (addr_b >= sdb && addr_b < sdb + SDB_REQUIRED_SIZE) {
*error = (*error << 1);
return eb_sdb(socketp, widths, addr_b); /* always bigendian */
return eb_sdb(socketp, widths, addr_b-sdb); /* always bigendian */
}
socket = EB_SOCKET(socketp);
for (addressp = socket->first_handler; addressp != EB_NULL; addressp = address->next) {
address = EB_HANDLER_ADDRESS(addressp);
dev_first = address->device->sdb_component.addr_first;
......
......@@ -141,6 +141,7 @@ eb_status_t eb_socket_open(uint16_t abi_code, const char* port, eb_width_t suppo
aux->time_cache = 0;
aux->rba = 0x8000;
aux->first_transport = first_transport;
aux->sdb_offset = 0;
if (link_type != eb_transport_size) {
eb_socket_close(socketp);
......
......@@ -34,6 +34,9 @@
#include "../transport/transport.h"
#include "handler.h"
/* The size of space that sdb_offset points to */
#define SDB_REQUIRED_SIZE 65536
typedef EB_POINTER(eb_response) eb_response_t;
struct eb_response {
/* xxxxxxxxxxxxxxxL
......@@ -52,6 +55,7 @@ struct eb_response {
typedef EB_POINTER(eb_socket_aux) eb_socket_aux_t;
struct eb_socket_aux {
eb_address_t sdb_offset;
uint32_t time_cache;
uint16_t rba;
......@@ -60,7 +64,7 @@ struct eb_socket_aux {
struct eb_socket {
eb_device_t first_device;
eb_handler_address_t first_handler;
eb_handler_address_t first_handler; /* in ascending order, non-overlapping */
/* Functional-style queue using lists */
eb_response_t first_response;
......
......@@ -139,9 +139,6 @@ Record::Record(width_t width_) {
address &= (address_t)(~0) >> ((sizeof(address)-addrw)*8);
error = (seed & 3) == 1;
seed >>= 2;
/* Don't mess with the SDWB block */
if (address < 0x4000) address += 0x4000;
}
/* Align the access */
......
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