Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • atlas-tdaq-felix/felix-versal-tools/flxnet-drivers
1 result
Show changes
Commits on Source (2)
......@@ -5,7 +5,7 @@ These modules creates a network device on Versal card and host PC. Each FLX-182
## Instructions
- Instantiate the versal_network_device from https://gitlab.cern.ch/atlas-tdaq-felix/firmware/-/tree/phase2/FLX-1886_FLX182_virtual_network/sources/ip_cores/BNL182/ip_repo/versal_network_device_1.0?ref_type=heads
- Instantiate the versal_network_device from <https://gitlab.cern.ch/atlas-tdaq-felix/firmware/-/tree/phase2/FLX-1886_FLX182_virtual_network/sources/ip_cores/BNL182/ip_repo/versal_network_device_1.0?ref_type=heads>
- Connect the AXI bus to the Versal processing system
- Connect the FIFO ports to the the corresponding ports of Wupper
......@@ -40,7 +40,7 @@ These modules creates a network device on Versal card and host PC. Each FLX-182
ethtool -s flxnet0 msglvl 8191 # display all debug messages and packet data
```
- The exact message level may be different for different Linux versions
- This msglvl tool is mostly used by the original author of this driver, newly added debug messages don't use this yet
- For detailed explanation debug message levels see: <https://www.kernel.org/doc/Documentation/networking/netif-msg.txt>
## The modules
......@@ -61,3 +61,4 @@ Biggest changes:
- The driver is written so that multiple flxnet network devices can be created and communicate with one host
- DHCP server on host automatically gives out an IP address to the Versal card instead of having to configure the IP addresses manually
- Added flxnet driver to the build_rpm.sh script from <https://gitlab.cern.ch/atlas-tdaq-felix/felix-tdaq-drivers/-/tree/main?ref_type=heads>, so that the modules on the host PC automatically insert on host server startup
- Added carrier function that gives a signal when the link goes up or down
\ No newline at end of file
......@@ -16,9 +16,7 @@ struct flxnet_peer {
unsigned int reg_recv;
unsigned int reg_status;
unsigned char mac_addr[ETH_ALEN];
bool reserved;
unsigned int role;
struct module *owner;
struct net_device *flxnet;
struct tx_queue tx_queue;
};
......
......@@ -31,12 +31,9 @@
#define DRV_NAME "flxnet_dev"
/*
TODO:
- add watchdogs in firmware for "link detect" emulation
- disable tx and rx on the peers without "link" present
- it's possible to make TX queue circular buffer lockless
- user interrupts instead of timer; use NAPI
*/
......@@ -45,7 +42,7 @@ u32 message_level;
typedef u32 t_fifo_word;
#define MAX_PACKET_LEN 400 // MAX_PACKET_LEN is measured in FIFO words
#define MAX_PACKET_LEN 400 // measured in FIFO words
#define BYTES_IN_WORD 4
#define MAX_DATA_LEN MAX_PACKET_LEN * BYTES_IN_WORD
#define MAX_RETRY_ATTEMPTS 5
......@@ -87,7 +84,7 @@ struct task_struct *recv_task;
#define TX_BUSY 2
#define TX_ERROR 3
/* Read/Write access to the MMAPped registers */
// Read/Write access to the MMAPped registers
#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
# define register_read(offset) readl(offset)
# define register_write(offset, val) writel(val, offset)
......@@ -105,7 +102,6 @@ static inline bool check_flag(void* __iomem reg, int bit_id) {
static inline void set_flag(void* __iomem reg, int bit_id) {
uint32_t temp_reg = register_read(reg);
temp_reg |= (1 << bit_id);
//pr_info("flxnet_dev: temp_reg is %u\n", temp_reg);
register_write(reg, temp_reg);
//pr_info("flxnet_dev: flag set\n");
}
......@@ -113,7 +109,6 @@ static inline void set_flag(void* __iomem reg, int bit_id) {
static inline void clear_flag(void* __iomem reg, int bit_id) {
uint32_t temp_reg = register_read(reg);
temp_reg &= ((1 << bit_id)^0xFFFFFFFF);
//pr_info("flxnet_dev: temp_reg is %u\n", temp_reg);
register_write(reg, temp_reg);
//pr_info("flxnet_dev: flag cleared\n");
}
......@@ -163,16 +158,18 @@ static inline t_fifo_word recv_word(struct flxnet_peer* peer) {
static inline void set_carrier(struct flxnet_peer *peer, bool value) {
if (value) {
set_flag(peer->regs + peer->reg_status, SET_CARRIER);
if (message_level & NETIF_MSG_IFUP)
pr_info("flxnet_dev: setting carrier to %d\n", value);
}
else {
clear_flag(peer->regs + peer->reg_status, SET_CARRIER);
if (message_level & NETIF_MSG_IFDOWN)
pr_info("flxnet_dev: setting carrier to %d\n", value);
}
pr_info("flxnet_dev: setting carrier to %d\n", value);
}
static inline bool status_carrier(struct flxnet_peer *peer) {
bool value = check_flag(peer->regs + peer->reg_status, STATUS_CARRIER);
//pr_info("flxnet_dev: status carrier is %d\n", value);
return value;
}
......@@ -180,9 +177,8 @@ static inline bool status_carrier(struct flxnet_peer *peer) {
static inline void send_eop(struct flxnet_peer *peer) {
set_flag(peer->regs + peer->reg_status, SEND_IS_EOP);
send_word(peer, FLXNET_EOP);
if (message_level & NETIF_MSG_TX_DONE) {
if (message_level & NETIF_MSG_TX_DONE)
pr_info("flxnet_dev: end of packet sent\n");
}
clear_flag(peer->regs + peer->reg_status, SEND_IS_EOP);
}
......@@ -202,7 +198,8 @@ struct flxnet_peer *find_peer_for_netdev(struct net_device *dev) {
struct flxnet_peer *tmp;
struct flxnet_peer *return_peer = NULL;
//pr_info("flxnet_dev: finding peer for net device\n");
if (message_level & NETIF_MSG_LINK)
pr_info("flxnet_dev: finding peer for net device\n");
list_for_each_entry_safe(peer, tmp, &peers, list_head) {
if (peer->flxnet == dev) {
......@@ -234,67 +231,50 @@ void flxnet_remove_peer(struct flxnet_peer *peer) {
atomic_set(&peer_count, 0);
}
if (peer->reserved) module_put(peer->owner);
list_del(&peer->list_head);
kfree(peer);
}
// removes all peers from the network
void remove_all_peers(void) {
struct flxnet_peer *peer;
struct flxnet_peer *tmp;
if (message_level & NETIF_MSG_LINK)
pr_info("flxnet_dev: removing all peers from the network\n");
mutex_lock(&peer_mutex);
list_for_each_entry_safe(peer, tmp, &peers, list_head) {
flxnet_remove_peer(peer);
}
mutex_unlock(&peer_mutex);
}
// mark as not reserved so that peer modules can be removed
void flxnet_release_all_peers(void) {
struct flxnet_peer *peer;
struct flxnet_peer *tmp;
mutex_lock(&peer_mutex);
list_for_each_entry_safe(peer, tmp, &peers, list_head) {
if (peer->reserved) {
module_put(peer->owner);
peer->reserved = false;
} else {
if (message_level & NETIF_MSG_DRV)
pr_info("flxnet_dev: trying to release peer %p, which is not reserved, skipping\n", peer);
}
}
mutex_unlock(&peer_mutex);
}
//void flxnet_release_all_peers(void) {
// struct flxnet_peer *peer;
// struct flxnet_peer *tmp;
//
// mutex_lock(&peer_mutex);
// list_for_each_entry_safe(peer, tmp, &peers, list_head) {
// if (peer->reserved) {
// module_put(peer->owner);
// peer->reserved = false;
// } else {
// if (message_level & NETIF_MSG_DRV)
// pr_info("flxnet_dev: trying to release peer %p, which is not reserved, skipping\n", peer);
// }
// }
// mutex_unlock(&peer_mutex);
//}
// mark as reserved so that peer modules cannot be removed and iomem stay there
void flxnet_reserve_all_peers(void) {
struct flxnet_peer *peer;
struct flxnet_peer *tmp;
mutex_lock(&peer_mutex);
list_for_each_entry_safe(peer, tmp, &peers, list_head) {
if (!peer->reserved) {
peer->reserved = try_module_get(peer->owner);
if (!peer->reserved) {
pr_err("flxnet_dev: failed to reserve peer %p, owner module is missing\n", peer);
flxnet_remove_peer(peer);
}
} else {
if (message_level & NETIF_MSG_DRV)
pr_info("flxnet_dev: trying to reserve peer %p, which is already reserved, skipping\n", peer);
}
}
mutex_unlock(&peer_mutex);
}
//void flxnet_reserve_all_peers(void) {
// struct flxnet_peer *peer;
// struct flxnet_peer *tmp;
//
// mutex_lock(&peer_mutex);
// list_for_each_entry_safe(peer, tmp, &peers, list_head) {
// if (!peer->reserved) {
// peer->reserved = try_module_get(peer->owner);
// if (!peer->reserved) {
// pr_err("flxnet_dev: failed to reserve peer %p, owner module is missing\n", peer);
// flxnet_remove_peer(peer);
// }
// } else {
// if (message_level & NETIF_MSG_DRV)
// pr_info("flxnet_dev: trying to reserve peer %p, which is already reserved, skipping\n", peer);
// }
// }
// mutex_unlock(&peer_mutex);
//}
static bool tx_queue_is_full(struct flxnet_peer *peer) {
......@@ -593,21 +573,20 @@ packet_rx_done:
static inline void check_carrier(struct flxnet_peer *peer) {
bool carrier = 0;
//pr_info("flxnet_dev: status_carrier %d\n", status_carrier(peer));
carrier = status_carrier(peer);
//pr_info("flxnet_dev: carrier is %d\n", carrier);
if (carrier) {
if (!netif_carrier_ok(peer->flxnet)) {
pr_info("flxnet_dev: status carrier changed to %d\n", carrier);
if (message_level & NETIF_MSG_IFUP)
pr_info("flxnet_dev: status carrier changed to %d\n", carrier);
netif_start_queue(peer->flxnet);
netif_carrier_on(peer->flxnet);
}
}
else {
if (netif_carrier_ok(peer->flxnet)) {
pr_info("flxnet_dev: status carrier changed to %d\n", carrier);
if (message_level & NETIF_MSG_IFDOWN)
pr_info("flxnet_dev: status carrier changed to %d\n", carrier);
netif_stop_queue(peer->flxnet);
netif_carrier_off(peer->flxnet);
}
......@@ -625,7 +604,6 @@ void recv_timer_function(struct timer_list *timer_list) {
// returns true if the packet can be received by at least one peer
bool can_transmit_packets(struct flxnet_peer *peer) {
if (!peer->reserved) return false;
if (is_magic_correct(peer) && can_accept_block(peer)) {
mutex_unlock(&peer_mutex);
return true;
......@@ -634,18 +612,11 @@ bool can_transmit_packets(struct flxnet_peer *peer) {
}
/*
Iterate over all peers, retrieve all packets under the assumption that
CPU can receive them faster than FIFO fills up
*/
// iterate over all peers, retrieve all packets under the assumption that CPU can receive them faster than FIFO fills up
void rx_all_packets(struct flxnet_peer *peer) {
int length_words, rv;
t_fifo_word sop;
if (!peer->reserved) {
return;
}
if (!is_magic_correct(peer)) {
pr_err("flxnet_dev: invalid magic in %s, removing peer %p from the network\n",
__FUNCTION__, peer);
......@@ -682,11 +653,8 @@ void rx_all_packets(struct flxnet_peer *peer) {
}
/*
Background task for polling the FIFOs and reading out packets
I don't want these in NAPI poll because this can be slow and
hence potentially interfere with other network devices
*/
// background task for polling the FIFOs and reading out packets
int send_recv_thread(void *data) {
struct flxnet_peer *peer, *tmp;
static int carrier_timer = 0;
......@@ -707,15 +675,15 @@ int send_recv_thread(void *data) {
}
if (!list_empty(&peers)) {
// check carrier every 1000ms
if (carrier_timer++ == 1000) {
//pr_info("flxnet_dev: carrier timer is 0\n");
check_carrier(peer);
carrier_timer = 0;
}
}
// if (message_level & NETIF_MSG_INTR)
// pr_info("flxnet: wake up worker thread %s\n", __FUNCTION__);
if (message_level & NETIF_MSG_INTR)
pr_info("flxnet: wake up worker thread %s\n", __FUNCTION__);
tx_all_packets(peer);
......@@ -742,10 +710,11 @@ int send_recv_thread(void *data) {
}
int open(struct net_device *dev) {
mutex_lock(&flxnet_mutex);
flxnet_reserve_all_peers(); // reserve the modules that supplied the peers
tx_queue_reset(dev); // clear TX queue
//flxnet_reserve_all_peers(); // reserve the modules that supplied the peers
tx_queue_reset(dev); // clear TX queue
// enable RX side
if (message_level & NETIF_MSG_IFUP)
......@@ -786,8 +755,8 @@ int stop(struct net_device *dev) {
netif_stop_queue(dev);
netif_carrier_off(dev);
tx_queue_reset(dev); // clear TX queue
flxnet_release_all_peers(); // free the modules that supplied the peers
tx_queue_reset(dev); // clear TX queue
//flxnet_release_all_peers(); // free the modules that supplied the peers
mutex_unlock(&flxnet_mutex);
......@@ -841,13 +810,8 @@ int transmit_packet(struct flxnet_peer *peer, struct tx_packet *packet) {
int send_broadcast(struct tx_packet *packet, struct flxnet_peer *peer) {
int rv;
rv = TX_BUSY;
if (!peer->reserved) {
return -1;
}
if (transmit_packet(peer, packet) != TX_BUSY)
rv = TX_SUCCESS;
......@@ -877,11 +841,6 @@ int send_packet(struct tx_packet *packet, struct flxnet_peer *peer) {
if (is_multicast_ether_addr(packet->dest_mac))
return send_broadcast(packet, peer);
if (!peer->reserved) {
return -1;
}
if (memcmp(peer->mac_addr, packet->dest_mac, ETH_ALEN) == 0) {
// matching peer is found in the table
rv = transmit_packet(peer, packet);
......@@ -1006,10 +965,6 @@ static void __iomem *dst;
// register the network device
int register_network(struct flxnet_peer *peer) {
int rv;
mutex_init(&peer_mutex);
mutex_init(&flxnet_mutex);
atomic_set(&peer_count, 0);
message_level = 0;
// allocate ring buffer for outgoing packets
......@@ -1037,9 +992,6 @@ int register_network(struct flxnet_peer *peer) {
peer->flxnet->tx_queue_len = 100;
peer->flxnet->features = NETIF_F_HW_CSUM;
init_waitqueue_head(&recv_queue);
timer_setup(&recv_timer, recv_timer_function, 0);
#ifdef IS_ROLE_TARGET
// get versal device_id and parse address
dst = ioremap(0xF1250000, 4096);
......@@ -1060,11 +1012,13 @@ int register_network(struct flxnet_peer *peer) {
zynq_data.hw_addr[0] &= 0xfe; // clear multicast bit
zynq_data.hw_addr[0] |= 0x02; // set local assignment bit (IEEE802)
eth_hw_addr_set(peer->flxnet, zynq_data.hw_addr);
pr_info("flxnet_dev: versal ethernet adress set\n");
if (message_level & NETIF_MSG_PROBE)
pr_info("flxnet_dev: versal ethernet adress set\n");
#else
eth_random_addr(peer->flxnet->dev_addr);
pr_info("flxnet_dev: random ethernet adress set\n");
if (message_level & NETIF_MSG_PROBE)
pr_info("flxnet_dev: random ethernet adress set\n");
#endif
rv = register_netdev(peer->flxnet);
......@@ -1089,7 +1043,7 @@ err_alloc_tx_queue:
// add a felix device to the network
struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *owner) {
struct flxnet_peer * flxnet_add_peer(void* __iomem base_address) {
struct flxnet_peer *peer;
pr_info("flxnet_dev: flxnet_add_peer %lX\n", (long unsigned int)base_address);
peer = kzalloc(sizeof(struct flxnet_peer), GFP_KERNEL);
......@@ -1101,8 +1055,6 @@ struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *
register_network(peer);
peer->regs = base_address;
peer->owner = owner;
peer->reserved = false;
INIT_LIST_HEAD(&peer->list_head);
#ifdef IS_ROLE_HOST
......@@ -1116,14 +1068,9 @@ struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *
#endif
set_carrier(peer, true);
pr_info("flxnet_dev: status_carrier %d\n", status_carrier(peer));
if (message_level & NETIF_MSG_IFUP)
pr_info("flxnet_dev: status_carrier %d\n", status_carrier(peer));
mutex_lock(&peer_mutex);
peer->reserved = try_module_get(owner);
if (!peer->reserved) {
mutex_unlock(&peer_mutex);
goto err_module_get;
}
list_add(&peers, &peer->list_head);
atomic_inc(&peer_count);
mutex_unlock(&peer_mutex);
......@@ -1132,14 +1079,15 @@ struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *
pr_info("flxnet_dev: added peer %p to the network\n", peer);
return peer;
err_module_get:
kfree(peer);
return NULL;
}
int __init flxnet_dev_init(void) {
pr_info("flxnet_dev: initializing module\n");
pr_info("flxnet_dev: initializing %s driver\n", DRV_NAME);
mutex_init(&peer_mutex);
mutex_init(&flxnet_mutex);
atomic_set(&peer_count, 0);
init_waitqueue_head(&recv_queue);
timer_setup(&recv_timer, recv_timer_function, 0);
return 0;
}
......@@ -1157,17 +1105,17 @@ void __exit flxnet_dev_exit(void) {
free_netdev(peer->flxnet);
kfree(peer->tx_queue.packets);
}
mutex_unlock(&peer_mutex);
remove_all_peers();
pr_info("flxnet_dev: unregistred network device, removing module\n");
}
else {
pr_info("flxnet_dev: no more networks to unregister, removing module\n");
pr_info("flxnet_dev: unregistred network device\n");
}
pr_info("flxnet_dev: removing %s driver\n", DRV_NAME);
mutex_unlock(&peer_mutex);
mutex_destroy(&peer_mutex);
mutex_destroy(&flxnet_mutex);
}
MODULE_AUTHOR("Elena Zhivun <elena.zhivun@cern.ch>");
MODULE_DESCRIPTION("Driver both on host PC and Versal card for establishing virtual network over PCIe");
MODULE_AUTHOR("Laura Rientsma <l.rientsma@nikhef.nl>");
MODULE_DESCRIPTION("Driver on both host PC and Versal card for establishing virtual network over PCIe");
module_init(flxnet_dev_init);
module_exit(flxnet_dev_exit);
......
......@@ -24,7 +24,7 @@
#include "flxnet/flxnet.h"
extern struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *owner);
extern struct flxnet_peer * flxnet_add_peer(void* __iomem base_address);
extern void flxnet_remove_peer(struct flxnet_peer *peer);
#define DRV_MODULE_NAME "flxnet_pcie"
......@@ -154,8 +154,7 @@ static int configure_pcie_device(struct pci_dev *pdev) {
// add this device to the network
pr_info("flxnet_pcie: inserting peer into flxnet\n");
fdev->peer = flxnet_add_peer(fdev->bar + dev_base_addr,
THIS_MODULE);
fdev->peer = flxnet_add_peer(fdev->bar + dev_base_addr);
if (IS_ERR(fdev->peer)) {
pr_err("flxnet_pcie: error inserting peer into flxnet\n");
......@@ -272,5 +271,6 @@ module_param(dev_base_addr, uint, S_IRUSR);
MODULE_PARM_DESC(dev_base_addr, "Base offset of the FIFO AXI device");
MODULE_AUTHOR("Elena Zhivun <elena.zhivun@cern.ch>");
MODULE_AUTHOR("Laura Rientsma <l.rientsma@nikhef.nl>");
MODULE_DESCRIPTION("Driver on host PC for establishing virtual network over PCIe, registers with flxnet_dev");
MODULE_LICENSE("GPL");
......@@ -37,7 +37,7 @@
#define DRV_MODULE_NAME "flxnet_target"
extern struct flxnet_peer * flxnet_add_peer(void* __iomem base_address, struct module *owner);
extern struct flxnet_peer * flxnet_add_peer(void* __iomem base_address);
extern void flxnet_remove_peer(struct flxnet_peer *peer);
struct flxnet_peer *peer;
......@@ -63,7 +63,7 @@ static int flx_net_probe(struct platform_device *pdev) {
// add this device to the network
dev_info(&pdev->dev, "flxnet_target: registering a peer with flxnet_dev\n");
peer = flxnet_add_peer(base, THIS_MODULE);
peer = flxnet_add_peer(base);
if (IS_ERR(peer)) {
dev_err(&pdev->dev, "flxnet_target: failed to insert flxnet peer\n");
return -ENODEV;
......@@ -97,13 +97,13 @@ static struct platform_driver flx_net_driver = {
};
static int __init flxnet_target_init(void) {
pr_info("flxnet_target: init driver\n");
pr_info("flxnet_target: initializing %s module\n", DRV_MODULE_NAME);
return platform_driver_register(&flx_net_driver);
}
static void __exit flxnet_target_exit(void) {
pr_info("flxnet_target: exit driver, removing peers\n");
pr_info("flxnet_target: removing %s module\n", DRV_MODULE_NAME);
platform_driver_unregister(&flx_net_driver);
}
......@@ -111,6 +111,7 @@ module_init(flxnet_target_init);
module_exit(flxnet_target_exit);
MODULE_AUTHOR("Elena Zhivun <elena.zhivun@cern.ch>");
MODULE_AUTHOR("Laura Rientsma <l.rientsma@nikhef.nl>");
MODULE_DESCRIPTION("Driver on Versal card for establishing virtual network over PCIe, registers with flxnet_dev");
MODULE_LICENSE("GPL");