#define NOTIFY_EVENTS 10
#define NOTIFY_BLOCKS 10
+
#define RX_TRUNCATE_EN_93XX BIT(6)
#define RX_TRUNCATE_EN_83XX BIT(4)
#define TX_PAD_EN_838X BIT(5)
#define SKB_MTU 1600
+/* Ethernet header, two stacked VLAN tags (802.1ad QinQ) and FCS */
+#define RTETH_FRAME_OVERHEAD (ETH_HLEN + 2 * VLAN_HLEN + ETH_FCS_LEN)
/* TODO: change this to 1568 after fragment handling has been tested in the wild */
#define SKB_FRAG_SIZE 400
#define SKB_PAD MAX(32, L1_CACHE_BYTES)
offsetof(struct rteth_tx_data, ring));
}
+/*
+ * Three limits bound the frames exchanged with the CPU port, and each family spreads them
+ * over registers of its own, whose length fields are named after the block holding them:
+ * what the driver receives is transmitted by the switch, but received by the NIC.
+ *
+ * - the DMA truncation length cuts a frame short. It still reaches the CPU, carrying only
+ * as many bytes as the field allows, so switch it off and leave the length to the others.
+ * - the largest frame the switch hands to the CPU, which drops the longer ones. Both
+ * measured on an RTL9303 by lowering one at a time while frames of growing size were
+ * sent into a user port.
+ * - the largest frame the switch takes from the CPU. Longan keeps it in the port register
+ * of the CPU port, Maple in a register of its own, the others in a second field of the
+ * register above.
+ */
+static void rteth_838x_set_max_packet_length(struct rteth_ctrl *ctrl, int len)
+{
+ regmap_update_bits(ctrl->map, RTETH_838X_DMA_IF_PKT_RX_FLTR_CTRL, GENMASK(13, 0), len);
+ regmap_update_bits(ctrl->map, RTETH_838X_DMA_IF_PKT_TX_FLTR_CTRL, GENMASK(13, 0), len);
+ regmap_clear_bits(ctrl->map, ctrl->r->dma_if_ctrl, RX_TRUNCATE_EN_83XX);
+}
+
+static void rteth_839x_set_max_packet_length(struct rteth_ctrl *ctrl, int len)
+{
+ regmap_update_bits(ctrl->map, RTETH_839X_DMA_IF_PKT_FLTR_CTRL,
+ GENMASK(27, 14) | GENMASK(13, 0),
+ FIELD_PREP(GENMASK(27, 14), len) | FIELD_PREP(GENMASK(13, 0), len));
+ regmap_clear_bits(ctrl->map, ctrl->r->dma_if_ctrl, RX_TRUNCATE_EN_83XX);
+}
+
+static void rteth_930x_set_max_packet_length(struct rteth_ctrl *ctrl, int len)
+{
+ regmap_update_bits(ctrl->map, RTETH_930X_MAC_L2_CPU_MAX_LEN_CTRL, GENMASK(13, 0), len);
+ regmap_update_bits(ctrl->map, RTETH_930X_MAC_L2_PORT_MAX_LEN_CTRL,
+ GENMASK(27, 14) | GENMASK(13, 0),
+ FIELD_PREP(GENMASK(27, 14), len) | FIELD_PREP(GENMASK(13, 0), len));
+ regmap_clear_bits(ctrl->map, ctrl->r->dma_if_ctrl, RX_TRUNCATE_EN_93XX);
+}
+
+static void rteth_931x_set_max_packet_length(struct rteth_ctrl *ctrl, int len)
+{
+ regmap_update_bits(ctrl->map, RTETH_931X_MAC_L2_CPU_MAX_LEN_CTRL,
+ GENMASK(27, 14) | GENMASK(13, 0),
+ FIELD_PREP(GENMASK(27, 14), len) | FIELD_PREP(GENMASK(13, 0), len));
+ regmap_clear_bits(ctrl->map, ctrl->r->dma_if_ctrl, RX_TRUNCATE_EN_93XX);
+}
+
+static void rteth_set_max_packet_length(struct rteth_ctrl *ctrl)
+{
+ ctrl->r->set_max_packet_length(ctrl, ctrl->dev->mtu + RTETH_FRAME_OVERHEAD);
+}
+
static void rteth_838x_hw_en_rxtx(struct rteth_ctrl *ctrl)
{
- /* Truncate RX buffer to SKB_MTU bytes, pad TX */
- regmap_write(ctrl->map, ctrl->r->dma_if_ctrl,
- (SKB_MTU << 16) | RX_TRUNCATE_EN_83XX | TX_PAD_EN_838X);
+ /* Pad TX */
+ regmap_write(ctrl->map, ctrl->r->dma_if_ctrl, TX_PAD_EN_838X);
+
+ rteth_set_max_packet_length(ctrl);
rteth_enable_all_rx_irqs(ctrl);
static void rteth_839x_hw_en_rxtx(struct rteth_ctrl *ctrl)
{
- /* Setup CPU-Port: RX Buffer */
- regmap_write(ctrl->map, ctrl->r->dma_if_ctrl, (SKB_MTU << 5) | RX_TRUNCATE_EN_83XX);
+ rteth_set_max_packet_length(ctrl);
rteth_enable_all_rx_irqs(ctrl);
static void rteth_930x_hw_en_rxtx(struct rteth_ctrl *ctrl)
{
- /* Setup CPU-Port: RX Buffer truncated at SKB_MTU Bytes */
- regmap_write(ctrl->map, ctrl->r->dma_if_ctrl, (SKB_MTU << 16) | RX_TRUNCATE_EN_93XX);
+ rteth_set_max_packet_length(ctrl);
rteth_enable_all_rx_irqs(ctrl);
static void rteth_931x_hw_en_rxtx(struct rteth_ctrl *ctrl)
{
- /* Setup CPU-Port: RX Buffer truncated at SKB_MTU Bytes */
- regmap_write(ctrl->map, ctrl->r->dma_if_ctrl, (SKB_MTU << 16) | RX_TRUNCATE_EN_93XX);
+ rteth_set_max_packet_length(ctrl);
rteth_enable_all_rx_irqs(ctrl);
.hw_stop = &rteth_838x_hw_stop,
.hw_reset = &rteth_838x_hw_reset,
.init_mac = &rteth_838x_init_mac,
+ .set_max_packet_length = rteth_838x_set_max_packet_length,
.netdev_ops = &rteth_838x_netdev_ops,
};
.hw_stop = &rteth_839x_hw_stop,
.hw_reset = &rteth_839x_hw_reset,
.init_mac = &rteth_839x_init_mac,
+ .set_max_packet_length = rteth_839x_set_max_packet_length,
.setup_notify_ring_buffer = &rteth_839x_setup_notify_ring_buffer,
.netdev_ops = &rteth_839x_netdev_ops,
};
.hw_stop = &rteth_930x_hw_stop,
.hw_reset = &rteth_93xx_hw_reset,
.init_mac = &rteth_930x_init_mac,
+ .set_max_packet_length = rteth_930x_set_max_packet_length,
.netdev_ops = &rteth_930x_netdev_ops,
};
.hw_stop = &rteth_931x_hw_stop,
.hw_reset = &rteth_93xx_hw_reset,
.init_mac = &rteth_931x_init_mac,
+ .set_max_packet_length = rteth_931x_set_max_packet_length,
.netdev_ops = &rteth_931x_netdev_ops,
};
#define RTETH_838X_DMA_IF_CTRL (0x9f58)
#define RTETH_838X_DMA_IF_INTR_MSK (0x9f50)
#define RTETH_838X_DMA_IF_INTR_STS (0x9f54)
+#define RTETH_838X_DMA_IF_PKT_RX_FLTR_CTRL (0x6b10)
+#define RTETH_838X_DMA_IF_PKT_TX_FLTR_CTRL (0xaa6c)
#define RTETH_838X_DMA_IF_RX_RING_CNTR (0xb7e8)
#define RTETH_838X_DMA_IF_RX_RING_SIZE (0xb7e4)
#define RTETH_838X_DMA_RX_BASE (0x9f00)
#define RTETH_839X_DMA_IF_CTRL (0x786c)
#define RTETH_839X_DMA_IF_INTR_MSK (0x7864)
#define RTETH_839X_DMA_IF_INTR_STS (0x7868)
+#define RTETH_839X_DMA_IF_PKT_FLTR_CTRL (0x1000)
#define RTETH_839X_DMA_IF_RX_RING_CNTR (0x603c)
#define RTETH_839X_DMA_IF_RX_RING_SIZE (0x6038)
#define RTETH_839X_DMA_RX_BASE (0x780c)
#define RTETH_930X_DMA_TX_BASE (0xe000)
#define RTETH_930X_MAC_FORCE_MODE_CTRL (0xca1c + RTETH_930X_CPU_PORT * 4)
#define RTETH_930X_MAC_L2_ADDR_CTRL (0xc714)
+#define RTETH_930X_MAC_L2_CPU_MAX_LEN_CTRL (0xa3a0)
#define RTETH_930X_MAC_L2_PORT_CTRL (0x3268 + RTETH_930X_CPU_PORT * 64)
+#define RTETH_930X_MAC_L2_PORT_MAX_LEN_CTRL (0x326c + RTETH_930X_CPU_PORT * 64)
#define RTETH_930X_QM_RSN2CPUQID_CTRL_0 (0xa344)
#define RTETH_930X_QM_RSN2CPUQID_CTRL_CNT 11
#define RTETH_930X_RMA_CTRL_0 (0x9e60)
#define RTETH_931X_DMA_TX_BASE (0x0900)
#define RTETH_931X_MAC_FORCE_MODE_CTRL (0x0dcc + RTETH_931X_CPU_PORT * 4)
#define RTETH_931X_MAC_L2_ADDR_CTRL (0x135c)
+#define RTETH_931X_MAC_L2_CPU_MAX_LEN_CTRL (0x1368)
#define RTETH_931X_MAC_L2_PORT_CTRL (0x6000 + RTETH_931X_CPU_PORT * 128)
#define RTETH_931X_QM_RSN2CPUQID_CTRL_0 (0xa9f4)
#define RTETH_931X_QM_RSN2CPUQID_CTRL_CNT 14
void (*hw_stop)(struct rteth_ctrl *ctrl);
void (*hw_reset)(struct rteth_ctrl *ctrl);
int (*init_mac)(struct rteth_ctrl *ctrl);
+ void (*set_max_packet_length)(struct rteth_ctrl *ctrl, int len);
void (*setup_notify_ring_buffer)(struct rteth_ctrl *ctrl);
void (*update_counter)(struct rteth_ctrl *ctrl, int ring, int released);
const struct net_device_ops *netdev_ops;