[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 22/36] cadence_gem: Add support for screening
From: |
Peter Maydell |
Subject: |
[Qemu-devel] [PULL 22/36] cadence_gem: Add support for screening |
Date: |
Thu, 22 Sep 2016 18:22:01 +0100 |
From: Alistair Francis <address@hidden>
The Cadence GEM hardware allows incoming data to be 'screened' based on some
register values. Add support for these screens.
We also need to increase the max regs to avoid compilation failures. These new
registers are implemented in the next patch.
Signed-off-by: Alistair Francis <address@hidden>
Reviewed-by: Peter Maydell <address@hidden>
Message-id: address@hidden
Signed-off-by: Peter Maydell <address@hidden>
---
hw/net/cadence_gem.c | 171 ++++++++++++++++++++++++++++++++++++++++++-
include/hw/net/cadence_gem.h | 6 +-
2 files changed, 174 insertions(+), 3 deletions(-)
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
index 08b3747..49a63a7 100644
--- a/hw/net/cadence_gem.c
+++ b/hw/net/cadence_gem.c
@@ -27,6 +27,7 @@
#include "hw/net/cadence_gem.h"
#include "qapi/error.h"
+#include "qemu/log.h"
#include "net/checksum.h"
#ifdef CADENCE_GEM_ERR_DEBUG
@@ -142,6 +143,37 @@
#define GEM_DESCONF6 (0x00000294/4)
#define GEM_DESCONF7 (0x00000298/4)
+#define GEM_SCREENING_TYPE1_REGISTER_0 (0x00000500 / 4)
+
+#define GEM_ST1R_UDP_PORT_MATCH_ENABLE (1 << 29)
+#define GEM_ST1R_DSTC_ENABLE (1 << 28)
+#define GEM_ST1R_UDP_PORT_MATCH_SHIFT (12)
+#define GEM_ST1R_UDP_PORT_MATCH_WIDTH (27 - GEM_ST1R_UDP_PORT_MATCH_SHIFT +
1)
+#define GEM_ST1R_DSTC_MATCH_SHIFT (4)
+#define GEM_ST1R_DSTC_MATCH_WIDTH (11 - GEM_ST1R_DSTC_MATCH_SHIFT + 1)
+#define GEM_ST1R_QUEUE_SHIFT (0)
+#define GEM_ST1R_QUEUE_WIDTH (3 - GEM_ST1R_QUEUE_SHIFT + 1)
+
+#define GEM_SCREENING_TYPE2_REGISTER_0 (0x00000540 / 4)
+
+#define GEM_ST2R_COMPARE_A_ENABLE (1 << 18)
+#define GEM_ST2R_COMPARE_A_SHIFT (13)
+#define GEM_ST2R_COMPARE_WIDTH (17 - GEM_ST2R_COMPARE_A_SHIFT + 1)
+#define GEM_ST2R_ETHERTYPE_ENABLE (1 << 12)
+#define GEM_ST2R_ETHERTYPE_INDEX_SHIFT (9)
+#define GEM_ST2R_ETHERTYPE_INDEX_WIDTH (11 - GEM_ST2R_ETHERTYPE_INDEX_SHIFT \
+ + 1)
+#define GEM_ST2R_QUEUE_SHIFT (0)
+#define GEM_ST2R_QUEUE_WIDTH (3 - GEM_ST2R_QUEUE_SHIFT + 1)
+
+#define GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 (0x000006e0 / 4)
+#define GEM_TYPE2_COMPARE_0_WORD_0 (0x00000700 / 4)
+
+#define GEM_T2CW1_COMPARE_OFFSET_SHIFT (7)
+#define GEM_T2CW1_COMPARE_OFFSET_WIDTH (8 - GEM_T2CW1_COMPARE_OFFSET_SHIFT +
1)
+#define GEM_T2CW1_OFFSET_VALUE_SHIFT (0)
+#define GEM_T2CW1_OFFSET_VALUE_WIDTH (6 - GEM_T2CW1_OFFSET_VALUE_SHIFT + 1)
+
/*****************************************/
#define GEM_NWCTRL_TXSTART 0x00000200 /* Transmit Enable */
#define GEM_NWCTRL_TXENA 0x00000008 /* Transmit Enable */
@@ -602,6 +634,126 @@ static int gem_mac_address_filter(CadenceGEMState *s,
const uint8_t *packet)
return GEM_RX_REJECT;
}
+/* Figure out which queue the received data should be sent to */
+static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
+ unsigned rxbufsize)
+{
+ uint32_t reg;
+ bool matched, mismatched;
+ int i, j;
+
+ for (i = 0; i < s->num_type1_screeners; i++) {
+ reg = s->regs[GEM_SCREENING_TYPE1_REGISTER_0 + i];
+ matched = false;
+ mismatched = false;
+
+ /* Screening is based on UDP Port */
+ if (reg & GEM_ST1R_UDP_PORT_MATCH_ENABLE) {
+ uint16_t udp_port = rxbuf_ptr[14 + 22] << 8 | rxbuf_ptr[14 + 23];
+ if (udp_port == extract32(reg, GEM_ST1R_UDP_PORT_MATCH_SHIFT,
+ GEM_ST1R_UDP_PORT_MATCH_WIDTH)) {
+ matched = true;
+ } else {
+ mismatched = true;
+ }
+ }
+
+ /* Screening is based on DS/TC */
+ if (reg & GEM_ST1R_DSTC_ENABLE) {
+ uint8_t dscp = rxbuf_ptr[14 + 1];
+ if (dscp == extract32(reg, GEM_ST1R_DSTC_MATCH_SHIFT,
+ GEM_ST1R_DSTC_MATCH_WIDTH)) {
+ matched = true;
+ } else {
+ mismatched = true;
+ }
+ }
+
+ if (matched && !mismatched) {
+ return extract32(reg, GEM_ST1R_QUEUE_SHIFT, GEM_ST1R_QUEUE_WIDTH);
+ }
+ }
+
+ for (i = 0; i < s->num_type2_screeners; i++) {
+ reg = s->regs[GEM_SCREENING_TYPE2_REGISTER_0 + i];
+ matched = false;
+ mismatched = false;
+
+ if (reg & GEM_ST2R_ETHERTYPE_ENABLE) {
+ uint16_t type = rxbuf_ptr[12] << 8 | rxbuf_ptr[13];
+ int et_idx = extract32(reg, GEM_ST2R_ETHERTYPE_INDEX_SHIFT,
+ GEM_ST2R_ETHERTYPE_INDEX_WIDTH);
+
+ if (et_idx > s->num_type2_screeners) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Out of range ethertype "
+ "register index: %d\n", et_idx);
+ }
+ if (type == s->regs[GEM_SCREENING_TYPE2_ETHERTYPE_REG_0 +
+ et_idx]) {
+ matched = true;
+ } else {
+ mismatched = true;
+ }
+ }
+
+ /* Compare A, B, C */
+ for (j = 0; j < 3; j++) {
+ uint32_t cr0, cr1, mask;
+ uint16_t rx_cmp;
+ int offset;
+ int cr_idx = extract32(reg, GEM_ST2R_COMPARE_A_SHIFT + j * 6,
+ GEM_ST2R_COMPARE_WIDTH);
+
+ if (!(reg & (GEM_ST2R_COMPARE_A_ENABLE << (j * 6)))) {
+ continue;
+ }
+ if (cr_idx > s->num_type2_screeners) {
+ qemu_log_mask(LOG_GUEST_ERROR, "Out of range compare "
+ "register index: %d\n", cr_idx);
+ }
+
+ cr0 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2];
+ cr1 = s->regs[GEM_TYPE2_COMPARE_0_WORD_0 + cr_idx * 2 + 1];
+ offset = extract32(cr1, GEM_T2CW1_OFFSET_VALUE_SHIFT,
+ GEM_T2CW1_OFFSET_VALUE_WIDTH);
+
+ switch (extract32(cr1, GEM_T2CW1_COMPARE_OFFSET_SHIFT,
+ GEM_T2CW1_COMPARE_OFFSET_WIDTH)) {
+ case 3: /* Skip UDP header */
+ qemu_log_mask(LOG_UNIMP, "TCP compare offsets"
+ "unimplemented - assuming UDP\n");
+ offset += 8;
+ /* Fallthrough */
+ case 2: /* skip the IP header */
+ offset += 20;
+ /* Fallthrough */
+ case 1: /* Count from after the ethertype */
+ offset += 14;
+ break;
+ case 0:
+ /* Offset from start of frame */
+ break;
+ }
+
+ rx_cmp = rxbuf_ptr[offset] << 8 | rxbuf_ptr[offset];
+ mask = extract32(cr0, 0, 16);
+
+ if ((rx_cmp & mask) == (extract32(cr0, 16, 16) & mask)) {
+ matched = true;
+ } else {
+ mismatched = true;
+ }
+ }
+
+ if (matched && !mismatched) {
+ return extract32(reg, GEM_ST2R_QUEUE_SHIFT, GEM_ST2R_QUEUE_WIDTH);
+ }
+ }
+
+ /* We made it here, assume it's queue 0 */
+ return 0;
+}
+
static void gem_get_rx_desc(CadenceGEMState *s)
{
DB_PRINT("read descriptor 0x%x\n", (unsigned)s->rx_desc_addr[0]);
@@ -712,6 +864,9 @@ static ssize_t gem_receive(NetClientState *nc, const
uint8_t *buf, size_t size)
DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
+ /* Find which queue we are targetting */
+ q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
+
while (bytes_to_copy) {
/* Do nothing if receive is not enabled. */
if (!gem_can_receive(nc)) {
@@ -1228,6 +1383,14 @@ static void gem_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Invalid num-priority-queues value: %" PRIx8,
s->num_priority_queues);
return;
+ } else if (s->num_type1_screeners > MAX_TYPE1_SCREENERS) {
+ error_setg(errp, "Invalid num-type1-screeners value: %" PRIx8,
+ s->num_type1_screeners);
+ return;
+ } else if (s->num_type2_screeners > MAX_TYPE2_SCREENERS) {
+ error_setg(errp, "Invalid num-type2-screeners value: %" PRIx8,
+ s->num_type2_screeners);
+ return;
}
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
@@ -1254,8 +1417,8 @@ static void gem_init(Object *obj)
static const VMStateDescription vmstate_cadence_gem = {
.name = "cadence_gem",
- .version_id = 3,
- .minimum_version_id = 3,
+ .version_id = 4,
+ .minimum_version_id = 4,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, CadenceGEMState, CADENCE_GEM_MAXREG),
VMSTATE_UINT16_ARRAY(phy_regs, CadenceGEMState, 32),
@@ -1273,6 +1436,10 @@ static Property gem_properties[] = {
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
num_priority_queues, 1),
+ DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState,
+ num_type1_screeners, 4),
+ DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState,
+ num_type2_screeners, 4),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h
index 77e0582..c469ffe 100644
--- a/include/hw/net/cadence_gem.h
+++ b/include/hw/net/cadence_gem.h
@@ -30,9 +30,11 @@
#include "net/net.h"
#include "hw/sysbus.h"
-#define CADENCE_GEM_MAXREG (0x00000640/4) /* Last valid GEM address */
+#define CADENCE_GEM_MAXREG (0x00000800 / 4) /* Last valid GEM address */
#define MAX_PRIORITY_QUEUES 8
+#define MAX_TYPE1_SCREENERS 16
+#define MAX_TYPE2_SCREENERS 16
typedef struct CadenceGEMState {
/*< private >*/
@@ -46,6 +48,8 @@ typedef struct CadenceGEMState {
/* Static properties */
uint8_t num_priority_queues;
+ uint8_t num_type1_screeners;
+ uint8_t num_type2_screeners;
/* GEM registers backing store */
uint32_t regs[CADENCE_GEM_MAXREG];
--
2.7.4
- [Qemu-devel] [PULL 13/36] aspeed: use error_report instead of LOG_GUEST_ERROR, (continued)
- [Qemu-devel] [PULL 13/36] aspeed: use error_report instead of LOG_GUEST_ERROR, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 10/36] arm: add support for an ast2500 evaluation board, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 12/36] aspeed: calculate the RAM size bits at realize time, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 16/36] hw/ptimer: Actually stop the timer in case of error, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 07/36] palmetto-bmc: add board specific configuration, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 08/36] hw/misc: use macros to define hw-strap1 register on the AST2400 Aspeed SoC, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 18/36] hw/ptimer: Suppress error messages under qtest, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 03/36] ast2400: replace ast2400 with aspeed_soc, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 15/36] aspeed: allocate RAM after the memory controller has checked the size, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 09/36] aspeed: add a ast2500 SoC and support to the SCU and SDMC controllers, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 22/36] cadence_gem: Add support for screening,
Peter Maydell <=
- [Qemu-devel] [PULL 25/36] xlnx-zynqmp: Set the number of priority queues, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 11/36] palmetto-bmc: remove extra no_sdcard assignement, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 14/36] aspeed: add a ram_size property to the memory controller, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 21/36] cadence_gem: Add the num-priority-queues property, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 27/36] loader: Use the specified MemoryRegion, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 02/36] ast2400: rename the Aspeed SoC files to aspeed_soc, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 20/36] cadence_gem: QOMify Cadence GEM, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 29/36] loader: Add AddressSpace loading support to ELFs, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 30/36] loader: Add AddressSpace loading support to uImages, Peter Maydell, 2016/09/22
- [Qemu-devel] [PULL 01/36] arm: add Cortex A7 CPU parameters, Peter Maydell, 2016/09/22