Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-airoha-add-qdisc-offload-support'

Lorenzo Bianconi says:

====================
net: airoha: Add Qdisc offload support

Introduce support for ETS and HTB Qdisc offload available on the Airoha
EN7581 ethernet controller.
====================

Link: https://patch.msgid.link/20250103-airoha-en7581-qdisc-offload-v1-0-608a23fa65d5@kernel.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+514 -4
+514 -4
drivers/net/ethernet/mediatek/airoha_eth.c
··· 15 15 #include <linux/u64_stats_sync.h> 16 16 #include <net/dsa.h> 17 17 #include <net/page_pool/helpers.h> 18 + #include <net/pkt_cls.h> 18 19 #include <uapi/linux/ppp_defs.h> 19 20 20 21 #define AIROHA_MAX_NUM_GDM_PORTS 1 ··· 24 23 #define AIROHA_MAX_NUM_XSI_RSTS 5 25 24 #define AIROHA_MAX_MTU 2000 26 25 #define AIROHA_MAX_PACKET_SIZE 2048 26 + #define AIROHA_NUM_QOS_CHANNELS 4 27 + #define AIROHA_NUM_QOS_QUEUES 8 27 28 #define AIROHA_NUM_TX_RING 32 28 29 #define AIROHA_NUM_RX_RING 32 30 + #define AIROHA_NUM_NETDEV_TX_RINGS (AIROHA_NUM_TX_RING + \ 31 + AIROHA_NUM_QOS_CHANNELS) 29 32 #define AIROHA_FE_MC_MAX_VLAN_TABLE 64 30 33 #define AIROHA_FE_MC_MAX_VLAN_PORT 16 31 34 #define AIROHA_NUM_TX_IRQ 2 ··· 44 39 45 40 #define PSE_RSV_PAGES 128 46 41 #define PSE_QUEUE_RSV_PAGES 64 42 + 43 + #define QDMA_METER_IDX(_n) ((_n) & 0xff) 44 + #define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3) 47 45 48 46 /* FE */ 49 47 #define PSE_BASE 0x0100 ··· 549 541 #define INGRESS_SLOW_TICK_RATIO_MASK GENMASK(29, 16) 550 542 #define INGRESS_FAST_TICK_MASK GENMASK(15, 0) 551 543 544 + #define REG_QUEUE_CLOSE_CFG(_n) (0x00a0 + ((_n) & 0xfc)) 545 + #define TXQ_DISABLE_CHAN_QUEUE_MASK(_n, _m) BIT((_m) + (((_n) & 0x3) << 3)) 546 + 552 547 #define REG_TXQ_DIS_CFG_BASE(_n) ((_n) ? 0x20a0 : 0x00a0) 553 548 #define REG_TXQ_DIS_CFG(_n, _m) (REG_TXQ_DIS_CFG_BASE((_n)) + (_m) << 2) 549 + 550 + #define REG_CNTR_CFG(_n) (0x0400 + ((_n) << 3)) 551 + #define CNTR_EN_MASK BIT(31) 552 + #define CNTR_ALL_CHAN_EN_MASK BIT(30) 553 + #define CNTR_ALL_QUEUE_EN_MASK BIT(29) 554 + #define CNTR_ALL_DSCP_RING_EN_MASK BIT(28) 555 + #define CNTR_SRC_MASK GENMASK(27, 24) 556 + #define CNTR_DSCP_RING_MASK GENMASK(20, 16) 557 + #define CNTR_CHAN_MASK GENMASK(7, 3) 558 + #define CNTR_QUEUE_MASK GENMASK(2, 0) 559 + 560 + #define REG_CNTR_VAL(_n) (0x0404 + ((_n) << 3)) 554 561 555 562 #define REG_LMGR_INIT_CFG 0x1000 556 563 #define LMGR_INIT_START BIT(31) ··· 588 565 #define EGRESS_SLOW_TICK_RATIO_MASK GENMASK(29, 16) 589 566 #define EGRESS_FAST_TICK_MASK GENMASK(15, 0) 590 567 568 + #define TRTCM_PARAM_RW_MASK BIT(31) 569 + #define TRTCM_PARAM_RW_DONE_MASK BIT(30) 570 + #define TRTCM_PARAM_TYPE_MASK GENMASK(29, 28) 571 + #define TRTCM_METER_GROUP_MASK GENMASK(27, 26) 572 + #define TRTCM_PARAM_INDEX_MASK GENMASK(23, 17) 573 + #define TRTCM_PARAM_RATE_TYPE_MASK BIT(16) 574 + 575 + #define REG_TRTCM_CFG_PARAM(_n) ((_n) + 0x4) 576 + #define REG_TRTCM_DATA_LOW(_n) ((_n) + 0x8) 577 + #define REG_TRTCM_DATA_HIGH(_n) ((_n) + 0xc) 578 + 591 579 #define REG_TXWRR_MODE_CFG 0x1020 592 580 #define TWRR_WEIGHT_SCALE_MASK BIT(31) 593 581 #define TWRR_WEIGHT_BASE_MASK BIT(3) 594 582 583 + #define REG_TXWRR_WEIGHT_CFG 0x1024 584 + #define TWRR_RW_CMD_MASK BIT(31) 585 + #define TWRR_RW_CMD_DONE BIT(30) 586 + #define TWRR_CHAN_IDX_MASK GENMASK(23, 19) 587 + #define TWRR_QUEUE_IDX_MASK GENMASK(18, 16) 588 + #define TWRR_VALUE_MASK GENMASK(15, 0) 589 + 595 590 #define REG_PSE_BUF_USAGE_CFG 0x1028 596 591 #define PSE_BUF_ESTIMATE_EN_MASK BIT(29) 592 + 593 + #define REG_CHAN_QOS_MODE(_n) (0x1040 + ((_n) << 2)) 594 + #define CHAN_QOS_MODE_MASK(_n) GENMASK(2 + ((_n) << 2), (_n) << 2) 597 595 598 596 #define REG_GLB_TRTCM_CFG 0x1080 599 597 #define GLB_TRTCM_EN_MASK BIT(31) ··· 764 720 FE_PSE_PORT_DROP = 0xf, 765 721 }; 766 722 723 + enum tx_sched_mode { 724 + TC_SCH_WRR8, 725 + TC_SCH_SP, 726 + TC_SCH_WRR7, 727 + TC_SCH_WRR6, 728 + TC_SCH_WRR5, 729 + TC_SCH_WRR4, 730 + TC_SCH_WRR3, 731 + TC_SCH_WRR2, 732 + }; 733 + 734 + enum trtcm_param_type { 735 + TRTCM_MISC_MODE, /* meter_en, pps_mode, tick_sel */ 736 + TRTCM_TOKEN_RATE_MODE, 737 + TRTCM_BUCKETSIZE_SHIFT_MODE, 738 + TRTCM_BUCKET_COUNTER_MODE, 739 + }; 740 + 741 + enum trtcm_mode_type { 742 + TRTCM_COMMIT_MODE, 743 + TRTCM_PEAK_MODE, 744 + }; 745 + 746 + enum trtcm_param { 747 + TRTCM_TICK_SEL = BIT(0), 748 + TRTCM_PKT_MODE = BIT(1), 749 + TRTCM_METER_MODE = BIT(2), 750 + }; 751 + 752 + #define MIN_TOKEN_SIZE 4096 753 + #define MAX_TOKEN_SIZE_OFFSET 17 754 + #define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6) 755 + #define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0) 756 + 767 757 struct airoha_queue_entry { 768 758 union { 769 759 void *buf; ··· 888 810 int id; 889 811 890 812 struct airoha_hw_stats stats; 813 + 814 + DECLARE_BITMAP(qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS); 815 + 816 + /* qos stats counters */ 817 + u64 cpu_tx_packets; 818 + u64 fwd_tx_packets; 891 819 }; 892 820 893 821 struct airoha_eth { ··· 1873 1789 WRITE_ONCE(q->desc[i].ctrl, cpu_to_le32(val)); 1874 1790 } 1875 1791 1792 + /* xmit ring drop default setting */ 1793 + airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid), 1794 + TX_RING_IRQ_BLOCKING_TX_DROP_EN_MASK); 1795 + 1876 1796 airoha_qdma_wr(qdma, REG_TX_RING_BASE(qid), dma_addr); 1877 1797 airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, 1878 1798 FIELD_PREP(TX_RING_CPU_IDX_MASK, q->head)); ··· 2043 1955 FIELD_PREP(SLA_SLOW_TICK_RATIO_MASK, 40)); 2044 1956 } 2045 1957 1958 + static void airoha_qdma_init_qos_stats(struct airoha_qdma *qdma) 1959 + { 1960 + int i; 1961 + 1962 + for (i = 0; i < AIROHA_NUM_QOS_CHANNELS; i++) { 1963 + /* Tx-cpu transferred count */ 1964 + airoha_qdma_wr(qdma, REG_CNTR_VAL(i << 1), 0); 1965 + airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1), 1966 + CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK | 1967 + CNTR_ALL_DSCP_RING_EN_MASK | 1968 + FIELD_PREP(CNTR_CHAN_MASK, i)); 1969 + /* Tx-fwd transferred count */ 1970 + airoha_qdma_wr(qdma, REG_CNTR_VAL((i << 1) + 1), 0); 1971 + airoha_qdma_wr(qdma, REG_CNTR_CFG(i << 1), 1972 + CNTR_EN_MASK | CNTR_ALL_QUEUE_EN_MASK | 1973 + CNTR_ALL_DSCP_RING_EN_MASK | 1974 + FIELD_PREP(CNTR_SRC_MASK, 1) | 1975 + FIELD_PREP(CNTR_CHAN_MASK, i)); 1976 + } 1977 + } 1978 + 2046 1979 static int airoha_qdma_hw_init(struct airoha_qdma *qdma) 2047 1980 { 2048 1981 int i; ··· 2114 2005 2115 2006 airoha_qdma_set(qdma, REG_TXQ_CNGST_CFG, 2116 2007 TXQ_CNGST_DROP_EN | TXQ_CNGST_DEI_DROP_EN); 2008 + airoha_qdma_init_qos_stats(qdma); 2117 2009 2118 2010 return 0; 2119 2011 } ··· 2535 2425 } while (u64_stats_fetch_retry(&port->stats.syncp, start)); 2536 2426 } 2537 2427 2428 + static u16 airoha_dev_select_queue(struct net_device *dev, struct sk_buff *skb, 2429 + struct net_device *sb_dev) 2430 + { 2431 + struct airoha_gdm_port *port = netdev_priv(dev); 2432 + int queue, channel; 2433 + 2434 + /* For dsa device select QoS channel according to the dsa user port 2435 + * index, rely on port id otherwise. Select QoS queue based on the 2436 + * skb priority. 2437 + */ 2438 + channel = netdev_uses_dsa(dev) ? skb_get_queue_mapping(skb) : port->id; 2439 + channel = channel % AIROHA_NUM_QOS_CHANNELS; 2440 + queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES; /* QoS queue */ 2441 + queue = channel * AIROHA_NUM_QOS_QUEUES + queue; 2442 + 2443 + return queue < dev->num_tx_queues ? queue : 0; 2444 + } 2445 + 2538 2446 static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, 2539 2447 struct net_device *dev) 2540 2448 { 2541 2449 struct skb_shared_info *sinfo = skb_shinfo(skb); 2542 2450 struct airoha_gdm_port *port = netdev_priv(dev); 2543 - u32 msg0 = 0, msg1, len = skb_headlen(skb); 2544 - int i, qid = skb_get_queue_mapping(skb); 2451 + u32 msg0, msg1, len = skb_headlen(skb); 2545 2452 struct airoha_qdma *qdma = port->qdma; 2546 2453 u32 nr_frags = 1 + sinfo->nr_frags; 2547 2454 struct netdev_queue *txq; 2548 2455 struct airoha_queue *q; 2549 2456 void *data = skb->data; 2457 + int i, qid; 2550 2458 u16 index; 2551 2459 u8 fport; 2552 2460 2461 + qid = skb_get_queue_mapping(skb) % ARRAY_SIZE(qdma->q_tx); 2462 + msg0 = FIELD_PREP(QDMA_ETH_TXMSG_CHAN_MASK, 2463 + qid / AIROHA_NUM_QOS_QUEUES) | 2464 + FIELD_PREP(QDMA_ETH_TXMSG_QUEUE_MASK, 2465 + qid % AIROHA_NUM_QOS_QUEUES); 2553 2466 if (skb->ip_summed == CHECKSUM_PARTIAL) 2554 2467 msg0 |= FIELD_PREP(QDMA_ETH_TXMSG_TCO_MASK, 1) | 2555 2468 FIELD_PREP(QDMA_ETH_TXMSG_UCO_MASK, 1) | ··· 2742 2609 } while (u64_stats_fetch_retry(&port->stats.syncp, start)); 2743 2610 } 2744 2611 2612 + static int airoha_qdma_set_chan_tx_sched(struct airoha_gdm_port *port, 2613 + int channel, enum tx_sched_mode mode, 2614 + const u16 *weights, u8 n_weights) 2615 + { 2616 + int i; 2617 + 2618 + for (i = 0; i < AIROHA_NUM_TX_RING; i++) 2619 + airoha_qdma_clear(port->qdma, REG_QUEUE_CLOSE_CFG(channel), 2620 + TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)); 2621 + 2622 + for (i = 0; i < n_weights; i++) { 2623 + u32 status; 2624 + int err; 2625 + 2626 + airoha_qdma_wr(port->qdma, REG_TXWRR_WEIGHT_CFG, 2627 + TWRR_RW_CMD_MASK | 2628 + FIELD_PREP(TWRR_CHAN_IDX_MASK, channel) | 2629 + FIELD_PREP(TWRR_QUEUE_IDX_MASK, i) | 2630 + FIELD_PREP(TWRR_VALUE_MASK, weights[i])); 2631 + err = read_poll_timeout(airoha_qdma_rr, status, 2632 + status & TWRR_RW_CMD_DONE, 2633 + USEC_PER_MSEC, 10 * USEC_PER_MSEC, 2634 + true, port->qdma, 2635 + REG_TXWRR_WEIGHT_CFG); 2636 + if (err) 2637 + return err; 2638 + } 2639 + 2640 + airoha_qdma_rmw(port->qdma, REG_CHAN_QOS_MODE(channel >> 3), 2641 + CHAN_QOS_MODE_MASK(channel), 2642 + mode << __ffs(CHAN_QOS_MODE_MASK(channel))); 2643 + 2644 + return 0; 2645 + } 2646 + 2647 + static int airoha_qdma_set_tx_prio_sched(struct airoha_gdm_port *port, 2648 + int channel) 2649 + { 2650 + static const u16 w[AIROHA_NUM_QOS_QUEUES] = {}; 2651 + 2652 + return airoha_qdma_set_chan_tx_sched(port, channel, TC_SCH_SP, w, 2653 + ARRAY_SIZE(w)); 2654 + } 2655 + 2656 + static int airoha_qdma_set_tx_ets_sched(struct airoha_gdm_port *port, 2657 + int channel, 2658 + struct tc_ets_qopt_offload *opt) 2659 + { 2660 + struct tc_ets_qopt_offload_replace_params *p = &opt->replace_params; 2661 + enum tx_sched_mode mode = TC_SCH_SP; 2662 + u16 w[AIROHA_NUM_QOS_QUEUES] = {}; 2663 + int i, nstrict = 0; 2664 + 2665 + if (p->bands > AIROHA_NUM_QOS_QUEUES) 2666 + return -EINVAL; 2667 + 2668 + for (i = 0; i < p->bands; i++) { 2669 + if (!p->quanta[i]) 2670 + nstrict++; 2671 + } 2672 + 2673 + /* this configuration is not supported by the hw */ 2674 + if (nstrict == AIROHA_NUM_QOS_QUEUES - 1) 2675 + return -EINVAL; 2676 + 2677 + for (i = 0; i < p->bands - nstrict; i++) 2678 + w[i] = p->weights[nstrict + i]; 2679 + 2680 + if (!nstrict) 2681 + mode = TC_SCH_WRR8; 2682 + else if (nstrict < AIROHA_NUM_QOS_QUEUES - 1) 2683 + mode = nstrict + 1; 2684 + 2685 + return airoha_qdma_set_chan_tx_sched(port, channel, mode, w, 2686 + ARRAY_SIZE(w)); 2687 + } 2688 + 2689 + static int airoha_qdma_get_tx_ets_stats(struct airoha_gdm_port *port, 2690 + int channel, 2691 + struct tc_ets_qopt_offload *opt) 2692 + { 2693 + u64 cpu_tx_packets = airoha_qdma_rr(port->qdma, 2694 + REG_CNTR_VAL(channel << 1)); 2695 + u64 fwd_tx_packets = airoha_qdma_rr(port->qdma, 2696 + REG_CNTR_VAL((channel << 1) + 1)); 2697 + u64 tx_packets = (cpu_tx_packets - port->cpu_tx_packets) + 2698 + (fwd_tx_packets - port->fwd_tx_packets); 2699 + _bstats_update(opt->stats.bstats, 0, tx_packets); 2700 + 2701 + port->cpu_tx_packets = cpu_tx_packets; 2702 + port->fwd_tx_packets = fwd_tx_packets; 2703 + 2704 + return 0; 2705 + } 2706 + 2707 + static int airoha_tc_setup_qdisc_ets(struct airoha_gdm_port *port, 2708 + struct tc_ets_qopt_offload *opt) 2709 + { 2710 + int channel = TC_H_MAJ(opt->handle) >> 16; 2711 + 2712 + if (opt->parent == TC_H_ROOT) 2713 + return -EINVAL; 2714 + 2715 + switch (opt->command) { 2716 + case TC_ETS_REPLACE: 2717 + return airoha_qdma_set_tx_ets_sched(port, channel, opt); 2718 + case TC_ETS_DESTROY: 2719 + /* PRIO is default qdisc scheduler */ 2720 + return airoha_qdma_set_tx_prio_sched(port, channel); 2721 + case TC_ETS_STATS: 2722 + return airoha_qdma_get_tx_ets_stats(port, channel, opt); 2723 + default: 2724 + return -EOPNOTSUPP; 2725 + } 2726 + } 2727 + 2728 + static int airoha_qdma_get_trtcm_param(struct airoha_qdma *qdma, int channel, 2729 + u32 addr, enum trtcm_param_type param, 2730 + enum trtcm_mode_type mode, 2731 + u32 *val_low, u32 *val_high) 2732 + { 2733 + u32 idx = QDMA_METER_IDX(channel), group = QDMA_METER_GROUP(channel); 2734 + u32 val, config = FIELD_PREP(TRTCM_PARAM_TYPE_MASK, param) | 2735 + FIELD_PREP(TRTCM_METER_GROUP_MASK, group) | 2736 + FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) | 2737 + FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode); 2738 + 2739 + airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config); 2740 + if (read_poll_timeout(airoha_qdma_rr, val, 2741 + val & TRTCM_PARAM_RW_DONE_MASK, 2742 + USEC_PER_MSEC, 10 * USEC_PER_MSEC, true, 2743 + qdma, REG_TRTCM_CFG_PARAM(addr))) 2744 + return -ETIMEDOUT; 2745 + 2746 + *val_low = airoha_qdma_rr(qdma, REG_TRTCM_DATA_LOW(addr)); 2747 + if (val_high) 2748 + *val_high = airoha_qdma_rr(qdma, REG_TRTCM_DATA_HIGH(addr)); 2749 + 2750 + return 0; 2751 + } 2752 + 2753 + static int airoha_qdma_set_trtcm_param(struct airoha_qdma *qdma, int channel, 2754 + u32 addr, enum trtcm_param_type param, 2755 + enum trtcm_mode_type mode, u32 val) 2756 + { 2757 + u32 idx = QDMA_METER_IDX(channel), group = QDMA_METER_GROUP(channel); 2758 + u32 config = TRTCM_PARAM_RW_MASK | 2759 + FIELD_PREP(TRTCM_PARAM_TYPE_MASK, param) | 2760 + FIELD_PREP(TRTCM_METER_GROUP_MASK, group) | 2761 + FIELD_PREP(TRTCM_PARAM_INDEX_MASK, idx) | 2762 + FIELD_PREP(TRTCM_PARAM_RATE_TYPE_MASK, mode); 2763 + 2764 + airoha_qdma_wr(qdma, REG_TRTCM_DATA_LOW(addr), val); 2765 + airoha_qdma_wr(qdma, REG_TRTCM_CFG_PARAM(addr), config); 2766 + 2767 + return read_poll_timeout(airoha_qdma_rr, val, 2768 + val & TRTCM_PARAM_RW_DONE_MASK, 2769 + USEC_PER_MSEC, 10 * USEC_PER_MSEC, true, 2770 + qdma, REG_TRTCM_CFG_PARAM(addr)); 2771 + } 2772 + 2773 + static int airoha_qdma_set_trtcm_config(struct airoha_qdma *qdma, int channel, 2774 + u32 addr, enum trtcm_mode_type mode, 2775 + bool enable, u32 enable_mask) 2776 + { 2777 + u32 val; 2778 + 2779 + if (airoha_qdma_get_trtcm_param(qdma, channel, addr, TRTCM_MISC_MODE, 2780 + mode, &val, NULL)) 2781 + return -EINVAL; 2782 + 2783 + val = enable ? val | enable_mask : val & ~enable_mask; 2784 + 2785 + return airoha_qdma_set_trtcm_param(qdma, channel, addr, TRTCM_MISC_MODE, 2786 + mode, val); 2787 + } 2788 + 2789 + static int airoha_qdma_set_trtcm_token_bucket(struct airoha_qdma *qdma, 2790 + int channel, u32 addr, 2791 + enum trtcm_mode_type mode, 2792 + u32 rate_val, u32 bucket_size) 2793 + { 2794 + u32 val, config, tick, unit, rate, rate_frac; 2795 + int err; 2796 + 2797 + if (airoha_qdma_get_trtcm_param(qdma, channel, addr, TRTCM_MISC_MODE, 2798 + mode, &config, NULL)) 2799 + return -EINVAL; 2800 + 2801 + val = airoha_qdma_rr(qdma, addr); 2802 + tick = FIELD_GET(INGRESS_FAST_TICK_MASK, val); 2803 + if (config & TRTCM_TICK_SEL) 2804 + tick *= FIELD_GET(INGRESS_SLOW_TICK_RATIO_MASK, val); 2805 + if (!tick) 2806 + return -EINVAL; 2807 + 2808 + unit = (config & TRTCM_PKT_MODE) ? 1000000 / tick : 8000 / tick; 2809 + if (!unit) 2810 + return -EINVAL; 2811 + 2812 + rate = rate_val / unit; 2813 + rate_frac = rate_val % unit; 2814 + rate_frac = FIELD_PREP(TRTCM_TOKEN_RATE_MASK, rate_frac) / unit; 2815 + rate = FIELD_PREP(TRTCM_TOKEN_RATE_MASK, rate) | 2816 + FIELD_PREP(TRTCM_TOKEN_RATE_FRACTION_MASK, rate_frac); 2817 + 2818 + err = airoha_qdma_set_trtcm_param(qdma, channel, addr, 2819 + TRTCM_TOKEN_RATE_MODE, mode, rate); 2820 + if (err) 2821 + return err; 2822 + 2823 + val = max_t(u32, bucket_size, MIN_TOKEN_SIZE); 2824 + val = min_t(u32, __fls(val), MAX_TOKEN_SIZE_OFFSET); 2825 + 2826 + return airoha_qdma_set_trtcm_param(qdma, channel, addr, 2827 + TRTCM_BUCKETSIZE_SHIFT_MODE, 2828 + mode, val); 2829 + } 2830 + 2831 + static int airoha_qdma_set_tx_rate_limit(struct airoha_gdm_port *port, 2832 + int channel, u32 rate, 2833 + u32 bucket_size) 2834 + { 2835 + int i, err; 2836 + 2837 + for (i = 0; i <= TRTCM_PEAK_MODE; i++) { 2838 + err = airoha_qdma_set_trtcm_config(port->qdma, channel, 2839 + REG_EGRESS_TRTCM_CFG, i, 2840 + !!rate, TRTCM_METER_MODE); 2841 + if (err) 2842 + return err; 2843 + 2844 + err = airoha_qdma_set_trtcm_token_bucket(port->qdma, channel, 2845 + REG_EGRESS_TRTCM_CFG, 2846 + i, rate, bucket_size); 2847 + if (err) 2848 + return err; 2849 + } 2850 + 2851 + return 0; 2852 + } 2853 + 2854 + static int airoha_tc_htb_alloc_leaf_queue(struct airoha_gdm_port *port, 2855 + struct tc_htb_qopt_offload *opt) 2856 + { 2857 + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; 2858 + u32 rate = div_u64(opt->rate, 1000) << 3; /* kbps */ 2859 + struct net_device *dev = port->dev; 2860 + int num_tx_queues = dev->real_num_tx_queues; 2861 + int err; 2862 + 2863 + if (opt->parent_classid != TC_HTB_CLASSID_ROOT) { 2864 + NL_SET_ERR_MSG_MOD(opt->extack, "invalid parent classid"); 2865 + return -EINVAL; 2866 + } 2867 + 2868 + err = airoha_qdma_set_tx_rate_limit(port, channel, rate, opt->quantum); 2869 + if (err) { 2870 + NL_SET_ERR_MSG_MOD(opt->extack, 2871 + "failed configuring htb offload"); 2872 + return err; 2873 + } 2874 + 2875 + if (opt->command == TC_HTB_NODE_MODIFY) 2876 + return 0; 2877 + 2878 + err = netif_set_real_num_tx_queues(dev, num_tx_queues + 1); 2879 + if (err) { 2880 + airoha_qdma_set_tx_rate_limit(port, channel, 0, opt->quantum); 2881 + NL_SET_ERR_MSG_MOD(opt->extack, 2882 + "failed setting real_num_tx_queues"); 2883 + return err; 2884 + } 2885 + 2886 + set_bit(channel, port->qos_sq_bmap); 2887 + opt->qid = AIROHA_NUM_TX_RING + channel; 2888 + 2889 + return 0; 2890 + } 2891 + 2892 + static void airoha_tc_remove_htb_queue(struct airoha_gdm_port *port, int queue) 2893 + { 2894 + struct net_device *dev = port->dev; 2895 + 2896 + netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1); 2897 + airoha_qdma_set_tx_rate_limit(port, queue + 1, 0, 0); 2898 + clear_bit(queue, port->qos_sq_bmap); 2899 + } 2900 + 2901 + static int airoha_tc_htb_delete_leaf_queue(struct airoha_gdm_port *port, 2902 + struct tc_htb_qopt_offload *opt) 2903 + { 2904 + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; 2905 + 2906 + if (!test_bit(channel, port->qos_sq_bmap)) { 2907 + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); 2908 + return -EINVAL; 2909 + } 2910 + 2911 + airoha_tc_remove_htb_queue(port, channel); 2912 + 2913 + return 0; 2914 + } 2915 + 2916 + static int airoha_tc_htb_destroy(struct airoha_gdm_port *port) 2917 + { 2918 + int q; 2919 + 2920 + for_each_set_bit(q, port->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS) 2921 + airoha_tc_remove_htb_queue(port, q); 2922 + 2923 + return 0; 2924 + } 2925 + 2926 + static int airoha_tc_get_htb_get_leaf_queue(struct airoha_gdm_port *port, 2927 + struct tc_htb_qopt_offload *opt) 2928 + { 2929 + u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; 2930 + 2931 + if (!test_bit(channel, port->qos_sq_bmap)) { 2932 + NL_SET_ERR_MSG_MOD(opt->extack, "invalid queue id"); 2933 + return -EINVAL; 2934 + } 2935 + 2936 + opt->qid = channel; 2937 + 2938 + return 0; 2939 + } 2940 + 2941 + static int airoha_tc_setup_qdisc_htb(struct airoha_gdm_port *port, 2942 + struct tc_htb_qopt_offload *opt) 2943 + { 2944 + switch (opt->command) { 2945 + case TC_HTB_CREATE: 2946 + break; 2947 + case TC_HTB_DESTROY: 2948 + return airoha_tc_htb_destroy(port); 2949 + case TC_HTB_NODE_MODIFY: 2950 + case TC_HTB_LEAF_ALLOC_QUEUE: 2951 + return airoha_tc_htb_alloc_leaf_queue(port, opt); 2952 + case TC_HTB_LEAF_DEL: 2953 + case TC_HTB_LEAF_DEL_LAST: 2954 + case TC_HTB_LEAF_DEL_LAST_FORCE: 2955 + return airoha_tc_htb_delete_leaf_queue(port, opt); 2956 + case TC_HTB_LEAF_QUERY_QUEUE: 2957 + return airoha_tc_get_htb_get_leaf_queue(port, opt); 2958 + default: 2959 + return -EOPNOTSUPP; 2960 + } 2961 + 2962 + return 0; 2963 + } 2964 + 2965 + static int airoha_dev_tc_setup(struct net_device *dev, enum tc_setup_type type, 2966 + void *type_data) 2967 + { 2968 + struct airoha_gdm_port *port = netdev_priv(dev); 2969 + 2970 + switch (type) { 2971 + case TC_SETUP_QDISC_ETS: 2972 + return airoha_tc_setup_qdisc_ets(port, type_data); 2973 + case TC_SETUP_QDISC_HTB: 2974 + return airoha_tc_setup_qdisc_htb(port, type_data); 2975 + default: 2976 + return -EOPNOTSUPP; 2977 + } 2978 + } 2979 + 2745 2980 static const struct net_device_ops airoha_netdev_ops = { 2746 2981 .ndo_init = airoha_dev_init, 2747 2982 .ndo_open = airoha_dev_open, 2748 2983 .ndo_stop = airoha_dev_stop, 2984 + .ndo_select_queue = airoha_dev_select_queue, 2749 2985 .ndo_start_xmit = airoha_dev_xmit, 2750 2986 .ndo_get_stats64 = airoha_dev_get_stats64, 2751 2987 .ndo_set_mac_address = airoha_dev_set_macaddr, 2988 + .ndo_setup_tc = airoha_dev_tc_setup, 2752 2989 }; 2753 2990 2754 2991 static const struct ethtool_ops airoha_ethtool_ops = { ··· 3155 2652 } 3156 2653 3157 2654 dev = devm_alloc_etherdev_mqs(eth->dev, sizeof(*port), 3158 - AIROHA_NUM_TX_RING, AIROHA_NUM_RX_RING); 2655 + AIROHA_NUM_NETDEV_TX_RINGS, 2656 + AIROHA_NUM_RX_RING); 3159 2657 if (!dev) { 3160 2658 dev_err(eth->dev, "alloc_etherdev failed\n"); 3161 2659 return -ENOMEM; ··· 3169 2665 dev->watchdog_timeo = 5 * HZ; 3170 2666 dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM | 3171 2667 NETIF_F_TSO6 | NETIF_F_IPV6_CSUM | 3172 - NETIF_F_SG | NETIF_F_TSO; 2668 + NETIF_F_SG | NETIF_F_TSO | 2669 + NETIF_F_HW_TC; 3173 2670 dev->features |= dev->hw_features; 3174 2671 dev->dev.of_node = np; 3175 2672 dev->irq = qdma->irq; 3176 2673 SET_NETDEV_DEV(dev, eth->dev); 2674 + 2675 + /* reserve hw queues for HTB offloading */ 2676 + err = netif_set_real_num_tx_queues(dev, AIROHA_NUM_TX_RING); 2677 + if (err) 2678 + return err; 3177 2679 3178 2680 err = of_get_ethdev_address(np, dev); 3179 2681 if (err) {