2016-06-14 01:19:17 +02:00
|
|
|
/** AXI Stream interconnect related helper functions
|
|
|
|
*
|
|
|
|
* These functions present a simpler interface to Xilinx' AXI Stream switch driver (XAxis_Switch_*)
|
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2017-03-03 20:20:13 -04:00
|
|
|
* @copyright 2017, Steffen Vogel
|
2016-06-14 01:19:17 +02:00
|
|
|
**********************************************************************************/
|
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
#include "list.h"
|
|
|
|
#include "log.h"
|
2017-04-26 11:52:22 +02:00
|
|
|
#include "log_config.h"
|
2017-02-12 14:35:05 -03:00
|
|
|
#include "plugin.h"
|
|
|
|
|
2016-06-19 19:23:19 +02:00
|
|
|
#include "fpga/ip.h"
|
2017-02-18 10:43:58 -05:00
|
|
|
#include "fpga/card.h"
|
|
|
|
#include "fpga/ips/switch.h"
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2017-03-25 21:13:07 +01:00
|
|
|
int switch_start(struct fpga_ip *c)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
struct fpga_card *f = c->card;
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-06-26 15:22:25 +02:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
XAxis_Switch *xsw = &sw->inst;
|
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
if (c != f->sw)
|
|
|
|
error("There can be only one AXI4-Stream interconnect per FPGA");
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
/* Setup AXI-stream switch */
|
|
|
|
XAxis_Switch_Config sw_cfg = {
|
2017-02-18 10:43:58 -05:00
|
|
|
.BaseAddress = (uintptr_t) f->map + c->baseaddr,
|
2016-06-26 15:22:25 +02:00
|
|
|
.MaxNumMI = sw->num_ports,
|
|
|
|
.MaxNumSI = sw->num_ports
|
2016-06-14 01:19:17 +02:00
|
|
|
};
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
ret = XAxisScr_CfgInitialize(xsw, &sw_cfg, (uintptr_t) c->card->map + c->baseaddr);
|
2016-06-14 01:19:17 +02:00
|
|
|
if (ret != XST_SUCCESS)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Disable all masters */
|
2016-06-26 15:22:25 +02:00
|
|
|
XAxisScr_RegUpdateDisable(xsw);
|
|
|
|
XAxisScr_MiPortDisableAll(xsw);
|
|
|
|
XAxisScr_RegUpdateEnable(xsw);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
switch_init_paths(c);
|
2016-07-08 13:01:40 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
int switch_init_paths(struct fpga_ip *c)
|
2016-07-08 13:01:40 +02:00
|
|
|
{
|
|
|
|
int ret;
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-07-08 13:01:40 +02:00
|
|
|
|
|
|
|
XAxis_Switch *xsw = &sw->inst;
|
|
|
|
|
|
|
|
XAxisScr_RegUpdateDisable(xsw);
|
|
|
|
XAxisScr_MiPortDisableAll(xsw);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-03-25 21:13:45 +01:00
|
|
|
for (size_t i = 0; i < list_length(&sw->paths); i++) {
|
|
|
|
struct sw_path *p = list_at(&sw->paths, i);
|
2017-02-18 10:43:58 -05:00
|
|
|
struct fpga_ip *mi, *si;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
mi = list_lookup(&c->card->ips, p->out);
|
|
|
|
si = list_lookup(&c->card->ips, p->in);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
if (!mi || !si || mi->port == -1 || si->port == -1)
|
|
|
|
error("Invalid path configuration for FPGA");
|
|
|
|
|
|
|
|
ret = switch_connect(c, mi, si);
|
|
|
|
if (ret)
|
|
|
|
error("Failed to configure switch");
|
|
|
|
}
|
2016-06-14 01:19:17 +02:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
XAxisScr_RegUpdateEnable(xsw);
|
|
|
|
|
2016-06-14 01:19:17 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
int switch_destroy(struct fpga_ip *c)
|
2016-06-26 15:22:25 +02:00
|
|
|
{
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-06-26 15:22:25 +02:00
|
|
|
|
|
|
|
list_destroy(&sw->paths, NULL, true);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
return 0;
|
2016-06-26 15:22:25 +02:00
|
|
|
}
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
int switch_parse(struct fpga_ip *c)
|
2016-06-26 15:22:25 +02:00
|
|
|
{
|
2017-02-18 10:43:58 -05:00
|
|
|
struct fpga_card *f = c->card;
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-07-08 13:01:40 +02:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
list_init(&sw->paths);
|
|
|
|
|
|
|
|
config_setting_t *cfg_sw, *cfg_path;
|
2016-07-08 13:01:40 +02:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports))
|
|
|
|
cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name);
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
cfg_sw = config_setting_get_member(f->cfg, "paths");
|
2016-06-26 15:22:25 +02:00
|
|
|
if (!cfg_sw)
|
|
|
|
return 0; /* no switch config available */
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
for (int i = 0; i < config_setting_length(cfg_sw); i++) {
|
|
|
|
cfg_path = config_setting_get_elem(cfg_sw, i);
|
|
|
|
|
|
|
|
struct sw_path path;
|
2016-07-08 13:01:40 +02:00
|
|
|
int reverse;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
if (!config_setting_lookup_bool(cfg_path, "reverse", &reverse))
|
|
|
|
reverse = 0;
|
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
if (!config_setting_lookup_string(cfg_path, "in", &path.in) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "from", &path.in) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "src", &path.in) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "source", &path.in))
|
|
|
|
cerror(cfg_path, "Path is missing 'in' setting");
|
|
|
|
|
|
|
|
if (!config_setting_lookup_string(cfg_path, "out", &path.out) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "to", &path.out) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "dst", &path.out) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "dest", &path.out) &&
|
|
|
|
!config_setting_lookup_string(cfg_path, "sink", &path.out))
|
|
|
|
cerror(cfg_path, "Path is missing 'out' setting");
|
|
|
|
|
|
|
|
list_push(&sw->paths, memdup(&path, sizeof(path)));
|
2016-07-08 13:01:40 +02:00
|
|
|
|
|
|
|
if (reverse) {
|
|
|
|
const char *tmp = path.in;
|
|
|
|
path.in = path.out;
|
|
|
|
path.out = tmp;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
list_push(&sw->paths, memdup(&path, sizeof(path)));
|
|
|
|
}
|
2016-06-26 15:22:25 +02:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
|
2016-06-14 01:19:17 +02:00
|
|
|
{
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-06-26 15:22:25 +02:00
|
|
|
XAxis_Switch *xsw = &sw->inst;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
uint32_t mux, port;
|
|
|
|
|
|
|
|
/* Check if theres already something connected */
|
|
|
|
for (int i = 0; i < sw->num_ports; i++) {
|
|
|
|
mux = XAxisScr_ReadReg(xsw->Config.BaseAddress, XAXIS_SCR_MI_MUX_START_OFFSET + i * 4);
|
|
|
|
if (!(mux & XAXIS_SCR_MI_X_DISABLE_MASK)) {
|
|
|
|
port = mux & ~XAXIS_SCR_MI_X_DISABLE_MASK;
|
|
|
|
|
|
|
|
if (port == si->port) {
|
|
|
|
warn("Switch: Slave port %s (%u) has been connected already to port %u. Disconnecting...", si->name, si->port, i);
|
|
|
|
XAxisScr_RegUpdateDisable(xsw);
|
|
|
|
XAxisScr_MiPortDisable(xsw, i);
|
|
|
|
XAxisScr_RegUpdateEnable(xsw);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reconfigure switch */
|
2016-06-26 15:22:25 +02:00
|
|
|
XAxisScr_RegUpdateDisable(xsw);
|
|
|
|
XAxisScr_MiPortEnable(xsw, mi->port, si->port);
|
|
|
|
XAxisScr_RegUpdateEnable(xsw);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-07-08 13:01:40 +02:00
|
|
|
/* Reset IPs */
|
|
|
|
/*ip_reset(mi);
|
|
|
|
ip_reset(si);*/
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
debug(8, "FPGA: Switch connected %s (%u) to %s (%u)", mi->name, mi->port, si->name, si->port);
|
2016-06-19 19:23:19 +02:00
|
|
|
|
2016-06-26 15:22:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-18 10:43:58 -05:00
|
|
|
int switch_disconnect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si)
|
2016-06-26 15:22:25 +02:00
|
|
|
{
|
2017-03-27 12:58:40 +02:00
|
|
|
struct sw *sw = c->_vd;
|
2016-06-26 15:22:25 +02:00
|
|
|
XAxis_Switch *xsw = &sw->inst;
|
|
|
|
|
|
|
|
if (!XAxisScr_IsMiPortEnabled(xsw, mi->port, si->port))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
XAxisScr_MiPortDisable(xsw, mi->port);
|
2016-06-14 01:19:17 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2016-06-26 15:22:25 +02:00
|
|
|
|
2017-02-12 14:35:05 -03:00
|
|
|
static struct plugin p = {
|
|
|
|
.name = "Xilinx's AXI4-Stream switch",
|
|
|
|
.description = "",
|
|
|
|
.type = PLUGIN_TYPE_FPGA_IP,
|
|
|
|
.ip = {
|
2017-02-18 10:43:58 -05:00
|
|
|
.vlnv = { "xilinx.com", "ip", "axis_interconnect", NULL },
|
|
|
|
.type = FPGA_IP_TYPE_MISC,
|
2017-03-25 21:13:07 +01:00
|
|
|
.start = switch_start,
|
2017-02-12 14:35:05 -03:00
|
|
|
.destroy = switch_destroy,
|
2017-03-25 21:10:25 +01:00
|
|
|
.parse = switch_parse,
|
|
|
|
.size = sizeof(struct sw)
|
2017-02-12 14:35:05 -03:00
|
|
|
}
|
2016-06-26 15:22:25 +02:00
|
|
|
};
|
|
|
|
|
2017-04-26 11:52:22 +02:00
|
|
|
REGISTER_PLUGIN(&p)
|