diff options
| -rw-r--r-- | Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_eth.c | 254 | ||||
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_eth.h | 65 | ||||
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_ppe.c | 259 | ||||
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_ppe_debugfs.c | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/airoha/airoha_regs.h | 6 |
6 files changed, 439 insertions, 183 deletions
diff --git a/Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml b/Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml index 6d22131ac2f9..fbe2ddcdd909 100644 --- a/Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml +++ b/Documentation/devicetree/bindings/net/airoha,en7581-eth.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - airoha,en7581-eth + - airoha,an7583-eth reg: items: @@ -44,6 +45,7 @@ properties: - description: PDMA irq resets: + minItems: 7 maxItems: 8 reset-names: @@ -54,8 +56,9 @@ properties: - const: xsi-mac - const: hsi0-mac - const: hsi1-mac - - const: hsi-mac + - enum: [ hsi-mac, xfp-mac ] - const: xfp-mac + minItems: 7 memory-region: items: @@ -81,6 +84,36 @@ properties: interface to implement hardware flow offloading programming Packet Processor Engine (PPE) flow table. +allOf: + - $ref: ethernet-controller.yaml# + - if: + properties: + compatible: + contains: + enum: + - airoha,en7581-eth + then: + properties: + resets: + minItems: 8 + + reset-names: + minItems: 8 + + - if: + properties: + compatible: + contains: + enum: + - airoha,an7583-eth + then: + properties: + resets: + maxItems: 7 + + reset-names: + maxItems: 7 + patternProperties: "^ethernet@[1-4]$": type: object diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 5825f6f29a92..8483ea02603e 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -297,8 +297,11 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) int q; all_rsv = airoha_fe_get_pse_all_rsv(eth); - /* hw misses PPE2 oq rsv */ - all_rsv += PSE_RSV_PAGES * pse_port_num_queues[FE_PSE_PORT_PPE2]; + if (airoha_ppe_is_enabled(eth, 1)) { + /* hw misses PPE2 oq rsv */ + all_rsv += PSE_RSV_PAGES * + pse_port_num_queues[FE_PSE_PORT_PPE2]; + } airoha_fe_set(eth, REG_FE_PSE_BUF_SET, all_rsv); /* CMD1 */ @@ -335,13 +338,17 @@ static void airoha_fe_pse_ports_init(struct airoha_eth *eth) for (q = 4; q < pse_port_num_queues[FE_PSE_PORT_CDM4]; q++) airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_CDM4, q, PSE_QUEUE_RSV_PAGES); - /* PPE2 */ - for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE2]; q++) { - if (q < pse_port_num_queues[FE_PSE_PORT_PPE2] / 2) - airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, q, - PSE_QUEUE_RSV_PAGES); - else - airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, q, 0); + if (airoha_ppe_is_enabled(eth, 1)) { + /* PPE2 */ + for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_PPE2]; q++) { + if (q < pse_port_num_queues[FE_PSE_PORT_PPE2] / 2) + airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, + q, + PSE_QUEUE_RSV_PAGES); + else + airoha_fe_set_pse_oq_rsv(eth, FE_PSE_PORT_PPE2, + q, 0); + } } /* GMD4 */ for (q = 0; q < pse_port_num_queues[FE_PSE_PORT_GDM4]; q++) @@ -524,25 +531,6 @@ static int airoha_fe_init(struct airoha_eth *eth) /* disable IFC by default */ airoha_fe_clear(eth, REG_FE_CSR_IFC_CFG, FE_IFC_EN_MASK); - airoha_fe_wr(eth, REG_PPE_DFT_CPORT0(0), - FIELD_PREP(DFT_CPORT_MASK(7), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(6), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(5), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(4), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(3), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(2), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(1), FE_PSE_PORT_CDM1) | - FIELD_PREP(DFT_CPORT_MASK(0), FE_PSE_PORT_CDM1)); - airoha_fe_wr(eth, REG_PPE_DFT_CPORT0(1), - FIELD_PREP(DFT_CPORT_MASK(7), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(6), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(5), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(4), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(3), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(2), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(1), FE_PSE_PORT_CDM2) | - FIELD_PREP(DFT_CPORT_MASK(0), FE_PSE_PORT_CDM2)); - /* enable 1:N vlan action, init vlan table */ airoha_fe_set(eth, REG_MC_VLAN_EN, MC_VLAN_EN_MASK); @@ -1387,8 +1375,7 @@ static int airoha_hw_init(struct platform_device *pdev, int err, i; /* disable xsi */ - err = reset_control_bulk_assert(ARRAY_SIZE(eth->xsi_rsts), - eth->xsi_rsts); + err = reset_control_bulk_assert(eth->soc->num_xsi_rsts, eth->xsi_rsts); if (err) return err; @@ -1695,19 +1682,23 @@ static int airoha_dev_set_macaddr(struct net_device *dev, void *p) return 0; } -static void airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) +static int airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) { - u32 pse_port = port->id == 3 ? FE_PSE_PORT_GDM3 : FE_PSE_PORT_GDM4; struct airoha_eth *eth = port->qdma->eth; - u32 chan = port->id == 3 ? 4 : 0; + u32 val, pse_port, chan, nbq; + int src_port; /* Forward the traffic to the proper GDM port */ + pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 + : FE_PSE_PORT_GDM4; airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(2), pse_port); airoha_fe_clear(eth, REG_GDM_FWD_CFG(2), GDM_STRIP_CRC); /* Enable GDM2 loopback */ airoha_fe_wr(eth, REG_GDM_TXCHN_EN(2), 0xffffffff); airoha_fe_wr(eth, REG_GDM_RXCHN_EN(2), 0xffff); + + chan = port->id == AIROHA_GDM3_IDX ? airoha_is_7581(eth) ? 4 : 3 : 0; airoha_fe_rmw(eth, REG_GDM_LPBK_CFG(2), LPBK_CHAN_MASK | LPBK_MODE_MASK | LPBK_EN_MASK, FIELD_PREP(LPBK_CHAN_MASK, chan) | @@ -1722,36 +1713,36 @@ static void airhoha_set_gdm2_loopback(struct airoha_gdm_port *port) airoha_fe_clear(eth, REG_FE_VIP_PORT_EN, BIT(2)); airoha_fe_clear(eth, REG_FE_IFC_PORT_EN, BIT(2)); - if (port->id == 3) { - /* FIXME: handle XSI_PCE1_PORT */ - airoha_fe_rmw(eth, REG_FE_WAN_PORT, - WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, - FIELD_PREP(WAN0_MASK, HSGMII_LAN_PCIE0_SRCPORT)); - airoha_fe_rmw(eth, - REG_SP_DFT_CPORT(HSGMII_LAN_PCIE0_SRCPORT >> 3), - SP_CPORT_PCIE0_MASK, - FIELD_PREP(SP_CPORT_PCIE0_MASK, - FE_PSE_PORT_CDM2)); - } else { - /* FIXME: handle XSI_USB_PORT */ + /* XXX: handle XSI_USB_PORT and XSI_PCE1_PORT */ + nbq = port->id == AIROHA_GDM3_IDX && airoha_is_7581(eth) ? 4 : 0; + src_port = eth->soc->ops.get_src_port_id(port, nbq); + if (src_port < 0) + return src_port; + + airoha_fe_rmw(eth, REG_FE_WAN_PORT, + WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, + FIELD_PREP(WAN0_MASK, src_port)); + val = src_port & SP_CPORT_DFT_MASK; + airoha_fe_rmw(eth, + REG_SP_DFT_CPORT(src_port >> fls(SP_CPORT_DFT_MASK)), + SP_CPORT_MASK(val), + FE_PSE_PORT_CDM2 << __ffs(SP_CPORT_MASK(val))); + + if (port->id != AIROHA_GDM3_IDX && airoha_is_7581(eth)) airoha_fe_rmw(eth, REG_SRC_PORT_FC_MAP6, FC_ID_OF_SRC_PORT24_MASK, FIELD_PREP(FC_ID_OF_SRC_PORT24_MASK, 2)); - airoha_fe_rmw(eth, REG_FE_WAN_PORT, - WAN1_EN_MASK | WAN1_MASK | WAN0_MASK, - FIELD_PREP(WAN0_MASK, HSGMII_LAN_ETH_SRCPORT)); - airoha_fe_rmw(eth, - REG_SP_DFT_CPORT(HSGMII_LAN_ETH_SRCPORT >> 3), - SP_CPORT_ETH_MASK, - FIELD_PREP(SP_CPORT_ETH_MASK, FE_PSE_PORT_CDM2)); - } + + return 0; } static int airoha_dev_init(struct net_device *dev) { struct airoha_gdm_port *port = netdev_priv(dev); - struct airoha_eth *eth = port->qdma->eth; - u32 pse_port; + struct airoha_qdma *qdma = port->qdma; + struct airoha_eth *eth = qdma->eth; + u32 pse_port, fe_cpu_port; + u8 ppe_id; airoha_set_macaddr(port, dev->dev_addr); @@ -1759,18 +1750,37 @@ static int airoha_dev_init(struct net_device *dev) case 3: case 4: /* If GDM2 is active we can't enable loopback */ - if (!eth->ports[1]) - airhoha_set_gdm2_loopback(port); + if (!eth->ports[1]) { + int err; + + err = airhoha_set_gdm2_loopback(port); + if (err) + return err; + } fallthrough; case 2: - pse_port = FE_PSE_PORT_PPE2; - break; - default: + if (airoha_ppe_is_enabled(eth, 1)) { + /* For PPE2 always use secondary cpu port. */ + fe_cpu_port = FE_PSE_PORT_CDM2; + pse_port = FE_PSE_PORT_PPE2; + break; + } + fallthrough; + default: { + u8 qdma_id = qdma - ð->qdma[0]; + + /* For PPE1 select cpu port according to the running QDMA. */ + fe_cpu_port = qdma_id ? FE_PSE_PORT_CDM2 : FE_PSE_PORT_CDM1; pse_port = FE_PSE_PORT_PPE1; break; } + } airoha_set_gdm_port_fwd_cfg(eth, REG_GDM_FWD_CFG(port->id), pse_port); + ppe_id = pse_port == FE_PSE_PORT_PPE2 ? 1 : 0; + airoha_fe_rmw(eth, REG_PPE_DFT_CPORT0(ppe_id), + DFT_CPORT_MASK(port->id), + fe_cpu_port << __ffs(DFT_CPORT_MASK(port->id))); return 0; } @@ -1887,6 +1897,22 @@ static bool airoha_dev_tx_queue_busy(struct airoha_queue *q, u32 nr_frags) return index >= tail; } +static int airoha_get_fe_port(struct airoha_gdm_port *port) +{ + struct airoha_qdma *qdma = port->qdma; + struct airoha_eth *eth = qdma->eth; + + switch (eth->soc->version) { + case 0x7583: + return port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 + : port->id; + case 0x7581: + default: + return port->id == AIROHA_GDM4_IDX ? FE_PSE_PORT_GDM4 + : port->id; + } +} + static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -1927,7 +1953,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, } } - fport = port->id == 4 ? FE_PSE_PORT_GDM4 : port->id; + fport = airoha_get_fe_port(port); msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) | FIELD_PREP(QDMA_ETH_TXMSG_METER_MASK, 0x7f); @@ -2922,6 +2948,7 @@ free_metadata_dst: static int airoha_probe(struct platform_device *pdev) { + struct reset_control_bulk_data *xsi_rsts; struct device_node *np; struct airoha_eth *eth; int i, err; @@ -2930,6 +2957,10 @@ static int airoha_probe(struct platform_device *pdev) if (!eth) return -ENOMEM; + eth->soc = of_device_get_match_data(&pdev->dev); + if (!eth->soc) + return -EINVAL; + eth->dev = &pdev->dev; err = dma_set_mask_and_coherent(eth->dev, DMA_BIT_MASK(32)); @@ -2954,13 +2985,18 @@ static int airoha_probe(struct platform_device *pdev) return err; } - eth->xsi_rsts[0].id = "xsi-mac"; - eth->xsi_rsts[1].id = "hsi0-mac"; - eth->xsi_rsts[2].id = "hsi1-mac"; - eth->xsi_rsts[3].id = "hsi-mac"; - eth->xsi_rsts[4].id = "xfp-mac"; + xsi_rsts = devm_kzalloc(eth->dev, + eth->soc->num_xsi_rsts * sizeof(*xsi_rsts), + GFP_KERNEL); + if (err) + return err; + + eth->xsi_rsts = xsi_rsts; + for (i = 0; i < eth->soc->num_xsi_rsts; i++) + eth->xsi_rsts[i].id = eth->soc->xsi_rsts_names[i]; + err = devm_reset_control_bulk_get_exclusive(eth->dev, - ARRAY_SIZE(eth->xsi_rsts), + eth->soc->num_xsi_rsts, eth->xsi_rsts); if (err) { dev_err(eth->dev, "failed to get bulk xsi reset lines\n"); @@ -3048,8 +3084,90 @@ static void airoha_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); } +static const char * const en7581_xsi_rsts_names[] = { + "xsi-mac", + "hsi0-mac", + "hsi1-mac", + "hsi-mac", + "xfp-mac", +}; + +static int airoha_en7581_get_src_port_id(struct airoha_gdm_port *port, int nbq) +{ + switch (port->id) { + case 3: + /* 7581 SoC supports PCIe serdes on GDM3 port */ + if (nbq == 4) + return HSGMII_LAN_7581_PCIE0_SRCPORT; + if (nbq == 5) + return HSGMII_LAN_7581_PCIE1_SRCPORT; + break; + case 4: + /* 7581 SoC supports eth and usb serdes on GDM4 port */ + if (!nbq) + return HSGMII_LAN_7581_ETH_SRCPORT; + if (nbq == 1) + return HSGMII_LAN_7581_USB_SRCPORT; + break; + default: + break; + } + + return -EINVAL; +} + +static const char * const an7583_xsi_rsts_names[] = { + "xsi-mac", + "hsi0-mac", + "hsi1-mac", + "xfp-mac", +}; + +static int airoha_an7583_get_src_port_id(struct airoha_gdm_port *port, int nbq) +{ + switch (port->id) { + case 3: + /* 7583 SoC supports eth serdes on GDM3 port */ + if (!nbq) + return HSGMII_LAN_7583_ETH_SRCPORT; + break; + case 4: + /* 7583 SoC supports PCIe and USB serdes on GDM4 port */ + if (!nbq) + return HSGMII_LAN_7583_PCIE_SRCPORT; + if (nbq == 1) + return HSGMII_LAN_7583_USB_SRCPORT; + break; + default: + break; + } + + return -EINVAL; +} + +static const struct airoha_eth_soc_data en7581_soc_data = { + .version = 0x7581, + .xsi_rsts_names = en7581_xsi_rsts_names, + .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names), + .num_ppe = 2, + .ops = { + .get_src_port_id = airoha_en7581_get_src_port_id, + }, +}; + +static const struct airoha_eth_soc_data an7583_soc_data = { + .version = 0x7583, + .xsi_rsts_names = an7583_xsi_rsts_names, + .num_xsi_rsts = ARRAY_SIZE(an7583_xsi_rsts_names), + .num_ppe = 1, + .ops = { + .get_src_port_id = airoha_an7583_get_src_port_id, + }, +}; + static const struct of_device_id of_airoha_match[] = { - { .compatible = "airoha,en7581-eth" }, + { .compatible = "airoha,en7581-eth", .data = &en7581_soc_data }, + { .compatible = "airoha,an7583-eth", .data = &an7583_soc_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_airoha_match); diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h index cd13c1c1224f..eb27a4ff5198 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -21,7 +21,6 @@ #define AIROHA_MAX_NUM_IRQ_BANKS 4 #define AIROHA_MAX_DSA_PORTS 7 #define AIROHA_MAX_NUM_RSTS 3 -#define AIROHA_MAX_NUM_XSI_RSTS 5 #define AIROHA_MAX_MTU 9216 #define AIROHA_MAX_PACKET_SIZE 2048 #define AIROHA_NUM_QOS_CHANNELS 4 @@ -48,20 +47,9 @@ #define QDMA_METER_IDX(_n) ((_n) & 0xff) #define QDMA_METER_GROUP(_n) (((_n) >> 8) & 0x3) -#define PPE_NUM 2 -#define PPE1_SRAM_NUM_ENTRIES (8 * 1024) -#define PPE_SRAM_NUM_ENTRIES (2 * PPE1_SRAM_NUM_ENTRIES) -#ifdef CONFIG_NET_AIROHA_FLOW_STATS -#define PPE1_STATS_NUM_ENTRIES (4 * 1024) -#else -#define PPE1_STATS_NUM_ENTRIES 0 -#endif /* CONFIG_NET_AIROHA_FLOW_STATS */ -#define PPE_STATS_NUM_ENTRIES (2 * PPE1_STATS_NUM_ENTRIES) -#define PPE1_SRAM_NUM_DATA_ENTRIES (PPE1_SRAM_NUM_ENTRIES - PPE1_STATS_NUM_ENTRIES) -#define PPE_SRAM_NUM_DATA_ENTRIES (2 * PPE1_SRAM_NUM_DATA_ENTRIES) +#define PPE_SRAM_NUM_ENTRIES (8 * 1024) +#define PPE_STATS_NUM_ENTRIES (4 * 1024) #define PPE_DRAM_NUM_ENTRIES (16 * 1024) -#define PPE_NUM_ENTRIES (PPE_SRAM_NUM_ENTRIES + PPE_DRAM_NUM_ENTRIES) -#define PPE_HASH_MASK (PPE_NUM_ENTRIES - 1) #define PPE_ENTRY_SIZE 80 #define PPE_RAM_NUM_ENTRIES_SHIFT(_n) (__ffs((_n) >> 10)) @@ -79,10 +67,16 @@ enum { }; enum { - HSGMII_LAN_PCIE0_SRCPORT = 0x16, - HSGMII_LAN_PCIE1_SRCPORT, - HSGMII_LAN_ETH_SRCPORT, - HSGMII_LAN_USB_SRCPORT, + HSGMII_LAN_7581_PCIE0_SRCPORT = 0x16, + HSGMII_LAN_7581_PCIE1_SRCPORT, + HSGMII_LAN_7581_ETH_SRCPORT, + HSGMII_LAN_7581_USB_SRCPORT, +}; + +enum { + HSGMII_LAN_7583_ETH_SRCPORT = 0x16, + HSGMII_LAN_7583_PCIE_SRCPORT = 0x18, + HSGMII_LAN_7583_USB_SRCPORT, }; enum { @@ -111,6 +105,13 @@ enum { CRSN_25 = 0x19, }; +enum airoha_gdm_index { + AIROHA_GDM1_IDX = 1, + AIROHA_GDM2_IDX = 2, + AIROHA_GDM3_IDX = 3, + AIROHA_GDM4_IDX = 4, +}; + enum { FE_PSE_PORT_CDM1, FE_PSE_PORT_GDM1, @@ -554,7 +555,7 @@ struct airoha_ppe { struct rhashtable l2_flows; struct hlist_head *foe_flow; - u16 foe_check_time[PPE_NUM_ENTRIES]; + u16 *foe_check_time; struct airoha_foe_stats *foe_stats; dma_addr_t foe_stats_dma; @@ -562,9 +563,21 @@ struct airoha_ppe { struct dentry *debugfs_dir; }; +struct airoha_eth_soc_data { + u16 version; + const char * const *xsi_rsts_names; + int num_xsi_rsts; + int num_ppe; + struct { + int (*get_src_port_id)(struct airoha_gdm_port *port, int nbq); + } ops; +}; + struct airoha_eth { struct device *dev; + const struct airoha_eth_soc_data *soc; + unsigned long state; void __iomem *fe_regs; @@ -574,7 +587,7 @@ struct airoha_eth { struct rhashtable flow_table; struct reset_control_bulk_data rsts[AIROHA_MAX_NUM_RSTS]; - struct reset_control_bulk_data xsi_rsts[AIROHA_MAX_NUM_XSI_RSTS]; + struct reset_control_bulk_data *xsi_rsts; struct net_device *napi_dev; @@ -617,15 +630,27 @@ static inline bool airhoa_is_lan_gdm_port(struct airoha_gdm_port *port) return port->id == 1; } +static inline bool airoha_is_7581(struct airoha_eth *eth) +{ + return eth->soc->version == 0x7581; +} + +static inline bool airoha_is_7583(struct airoha_eth *eth) +{ + return eth->soc->version == 0x7583; +} + bool airoha_is_valid_gdm_port(struct airoha_eth *eth, struct airoha_gdm_port *port); +bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, u16 hash, bool rx_wlan); int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data); int airoha_ppe_init(struct airoha_eth *eth); void airoha_ppe_deinit(struct airoha_eth *eth); void airoha_ppe_init_upd_mem(struct airoha_gdm_port *port); +u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe); struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe, u32 hash); void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash, diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 691361b25407..c373f21d95f5 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -32,9 +32,50 @@ static const struct rhashtable_params airoha_l2_flow_table_params = { .automatic_shrinking = true, }; -static bool airoha_ppe2_is_enabled(struct airoha_eth *eth) +static int airoha_ppe_get_num_stats_entries(struct airoha_ppe *ppe) { - return airoha_fe_rr(eth, REG_PPE_GLO_CFG(1)) & PPE_GLO_CFG_EN_MASK; + if (!IS_ENABLED(CONFIG_NET_AIROHA_FLOW_STATS)) + return -EOPNOTSUPP; + + if (airoha_is_7583(ppe->eth)) + return -EOPNOTSUPP; + + return PPE_STATS_NUM_ENTRIES; +} + +static int airoha_ppe_get_total_num_stats_entries(struct airoha_ppe *ppe) +{ + int num_stats = airoha_ppe_get_num_stats_entries(ppe); + + if (num_stats > 0) { + struct airoha_eth *eth = ppe->eth; + + num_stats = num_stats * eth->soc->num_ppe; + } + + return num_stats; +} + +static u32 airoha_ppe_get_total_sram_num_entries(struct airoha_ppe *ppe) +{ + struct airoha_eth *eth = ppe->eth; + + return PPE_SRAM_NUM_ENTRIES * eth->soc->num_ppe; +} + +u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe) +{ + u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); + + return sram_num_entries + PPE_DRAM_NUM_ENTRIES; +} + +bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index) +{ + if (index >= eth->soc->num_ppe) + return false; + + return airoha_fe_rr(eth, REG_PPE_GLO_CFG(index)) & PPE_GLO_CFG_EN_MASK; } static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe) @@ -46,14 +87,22 @@ static u32 airoha_ppe_get_timestamp(struct airoha_ppe *ppe) static void airoha_ppe_hw_init(struct airoha_ppe *ppe) { - u32 sram_tb_size, sram_num_entries, dram_num_entries; + u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries; + u32 sram_tb_size, dram_num_entries; struct airoha_eth *eth = ppe->eth; - int i; + int i, sram_num_stats_entries; - sram_tb_size = PPE_SRAM_NUM_ENTRIES * sizeof(struct airoha_foe_entry); + sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); + sram_tb_size = sram_num_entries * sizeof(struct airoha_foe_entry); dram_num_entries = PPE_RAM_NUM_ENTRIES_SHIFT(PPE_DRAM_NUM_ENTRIES); - for (i = 0; i < PPE_NUM; i++) { + sram_num_stats_entries = airoha_ppe_get_num_stats_entries(ppe); + if (sram_num_stats_entries > 0) + sram_ppe_num_data_entries -= sram_num_stats_entries; + sram_ppe_num_data_entries = + PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries); + + for (i = 0; i < eth->soc->num_ppe; i++) { int p; airoha_fe_wr(eth, REG_PPE_TB_BASE(i), @@ -85,10 +134,16 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) airoha_fe_rmw(eth, REG_PPE_TB_CFG(i), PPE_TB_CFG_SEARCH_MISS_MASK | + PPE_SRAM_TB_NUM_ENTRY_MASK | + PPE_DRAM_TB_NUM_ENTRY_MASK | PPE_TB_CFG_KEEPALIVE_MASK | PPE_TB_ENTRY_SIZE_MASK, FIELD_PREP(PPE_TB_CFG_SEARCH_MISS_MASK, 3) | - FIELD_PREP(PPE_TB_ENTRY_SIZE_MASK, 0)); + FIELD_PREP(PPE_TB_ENTRY_SIZE_MASK, 0) | + FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, + sram_ppe_num_data_entries) | + FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, + dram_num_entries)); airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED); @@ -101,35 +156,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) FIELD_PREP(FP1_EGRESS_MTU_MASK, AIROHA_MAX_MTU)); } - - if (airoha_ppe2_is_enabled(eth)) { - sram_num_entries = - PPE_RAM_NUM_ENTRIES_SHIFT(PPE1_SRAM_NUM_DATA_ENTRIES); - airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), - PPE_SRAM_TB_NUM_ENTRY_MASK | - PPE_DRAM_TB_NUM_ENTRY_MASK, - FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, - sram_num_entries) | - FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, - dram_num_entries)); - airoha_fe_rmw(eth, REG_PPE_TB_CFG(1), - PPE_SRAM_TB_NUM_ENTRY_MASK | - PPE_DRAM_TB_NUM_ENTRY_MASK, - FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, - sram_num_entries) | - FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, - dram_num_entries)); - } else { - sram_num_entries = - PPE_RAM_NUM_ENTRIES_SHIFT(PPE_SRAM_NUM_DATA_ENTRIES); - airoha_fe_rmw(eth, REG_PPE_TB_CFG(0), - PPE_SRAM_TB_NUM_ENTRY_MASK | - PPE_DRAM_TB_NUM_ENTRY_MASK, - FIELD_PREP(PPE_SRAM_TB_NUM_ENTRY_MASK, - sram_num_entries) | - FIELD_PREP(PPE_DRAM_TB_NUM_ENTRY_MASK, - dram_num_entries)); - } } static void airoha_ppe_flow_mangle_eth(const struct flow_action_entry *act, void *eth) @@ -428,9 +454,11 @@ static int airoha_ppe_foe_entry_set_ipv6_tuple(struct airoha_foe_entry *hwe, return 0; } -static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe) +static u32 airoha_ppe_foe_get_entry_hash(struct airoha_ppe *ppe, + struct airoha_foe_entry *hwe) { int type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1); + u32 ppe_hash_mask = airoha_ppe_get_total_num_entries(ppe) - 1; u32 hash, hv1, hv2, hv3; switch (type) { @@ -468,25 +496,31 @@ static u32 airoha_ppe_foe_get_entry_hash(struct airoha_foe_entry *hwe) case PPE_PKT_TYPE_IPV6_6RD: default: WARN_ON_ONCE(1); - return PPE_HASH_MASK; + return ppe_hash_mask; } hash = (hv1 & hv2) | ((~hv1) & hv3); hash = (hash >> 24) | ((hash & 0xffffff) << 8); hash ^= hv1 ^ hv2 ^ hv3; hash ^= hash >> 16; - hash &= PPE_NUM_ENTRIES - 1; + hash &= ppe_hash_mask; return hash; } -static u32 airoha_ppe_foe_get_flow_stats_index(struct airoha_ppe *ppe, u32 hash) +static int airoha_ppe_foe_get_flow_stats_index(struct airoha_ppe *ppe, + u32 hash, u32 *index) { - if (!airoha_ppe2_is_enabled(ppe->eth)) - return hash; + int ppe_num_stats_entries; + + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries < 0) + return ppe_num_stats_entries; - return hash >= PPE_STATS_NUM_ENTRIES ? hash - PPE1_STATS_NUM_ENTRIES - : hash; + *index = hash >= ppe_num_stats_entries ? hash - PPE_STATS_NUM_ENTRIES + : hash; + + return 0; } static void airoha_ppe_foe_flow_stat_entry_reset(struct airoha_ppe *ppe, @@ -500,9 +534,13 @@ static void airoha_ppe_foe_flow_stat_entry_reset(struct airoha_ppe *ppe, static void airoha_ppe_foe_flow_stats_reset(struct airoha_ppe *ppe, struct airoha_npu *npu) { - int i; + int i, ppe_num_stats_entries; - for (i = 0; i < PPE_STATS_NUM_ENTRIES; i++) + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries < 0) + return; + + for (i = 0; i < ppe_num_stats_entries; i++) airoha_ppe_foe_flow_stat_entry_reset(ppe, npu, i); } @@ -513,10 +551,17 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, { int type = FIELD_GET(AIROHA_FOE_IB1_BIND_PACKET_TYPE, hwe->ib1); u32 index, pse_port, val, *data, *ib2, *meter; + int ppe_num_stats_entries; u8 nbq; - index = airoha_ppe_foe_get_flow_stats_index(ppe, hash); - if (index >= PPE_STATS_NUM_ENTRIES) + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries < 0) + return; + + if (airoha_ppe_foe_get_flow_stats_index(ppe, hash, &index)) + return; + + if (index >= ppe_num_stats_entries) return; if (type == PPE_PKT_TYPE_BRIDGE) { @@ -557,17 +602,17 @@ static void airoha_ppe_foe_flow_stats_update(struct airoha_ppe *ppe, static struct airoha_foe_entry * airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash) { + u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); + lockdep_assert_held(&ppe_lock); - if (hash < PPE_SRAM_NUM_ENTRIES) { + if (hash < sram_num_entries) { u32 *hwe = ppe->foe + hash * sizeof(struct airoha_foe_entry); + bool ppe2 = hash >= PPE_SRAM_NUM_ENTRIES; struct airoha_eth *eth = ppe->eth; - bool ppe2; u32 val; int i; - ppe2 = airoha_ppe2_is_enabled(ppe->eth) && - hash >= PPE1_SRAM_NUM_ENTRIES; airoha_fe_wr(ppe->eth, REG_PPE_RAM_CTRL(ppe2), FIELD_PREP(PPE_SRAM_CTRL_ENTRY_MASK, hash) | PPE_SRAM_CTRL_REQ_MASK); @@ -577,7 +622,8 @@ airoha_ppe_foe_get_entry_locked(struct airoha_ppe *ppe, u32 hash) REG_PPE_RAM_CTRL(ppe2))) return NULL; - for (i = 0; i < sizeof(struct airoha_foe_entry) / 4; i++) + for (i = 0; i < sizeof(struct airoha_foe_entry) / sizeof(*hwe); + i++) hwe[i] = airoha_fe_rr(eth, REG_PPE_RAM_ENTRY(ppe2, i)); } @@ -614,10 +660,32 @@ static bool airoha_ppe_foe_compare_entry(struct airoha_flow_table_entry *e, return !memcmp(&e->data.d, &hwe->d, len - sizeof(hwe->ib1)); } +static int airoha_ppe_foe_commit_sram_entry(struct airoha_ppe *ppe, u32 hash) +{ + struct airoha_foe_entry *hwe = ppe->foe + hash * sizeof(*hwe); + bool ppe2 = hash >= PPE_SRAM_NUM_ENTRIES; + u32 *ptr = (u32 *)hwe, val; + int i; + + for (i = 0; i < sizeof(*hwe) / sizeof(*ptr); i++) + airoha_fe_wr(ppe->eth, REG_PPE_RAM_ENTRY(ppe2, i), ptr[i]); + + wmb(); + airoha_fe_wr(ppe->eth, REG_PPE_RAM_CTRL(ppe2), + FIELD_PREP(PPE_SRAM_CTRL_ENTRY_MASK, hash) | + PPE_SRAM_CTRL_WR_MASK | PPE_SRAM_CTRL_REQ_MASK); + + return read_poll_timeout_atomic(airoha_fe_rr, val, + val & PPE_SRAM_CTRL_ACK_MASK, + 10, 100, false, ppe->eth, + REG_PPE_RAM_CTRL(ppe2)); +} + static int airoha_ppe_foe_commit_entry(struct airoha_ppe *ppe, struct airoha_foe_entry *e, u32 hash, bool rx_wlan) { + u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); struct airoha_foe_entry *hwe = ppe->foe + hash * sizeof(*hwe); u32 ts = airoha_ppe_get_timestamp(ppe); struct airoha_eth *eth = ppe->eth; @@ -642,14 +710,8 @@ static int airoha_ppe_foe_commit_entry(struct airoha_ppe *ppe, if (!rx_wlan) airoha_ppe_foe_flow_stats_update(ppe, npu, hwe, hash); - if (hash < PPE_SRAM_NUM_ENTRIES) { - dma_addr_t addr = ppe->foe_dma + hash * sizeof(*hwe); - bool ppe2 = airoha_ppe2_is_enabled(eth) && - hash >= PPE1_SRAM_NUM_ENTRIES; - - err = npu->ops.ppe_foe_commit_entry(npu, addr, sizeof(*hwe), - hash, ppe2); - } + if (hash < sram_num_entries) + err = airoha_ppe_foe_commit_sram_entry(ppe, hash); unlock: rcu_read_unlock(); @@ -772,7 +834,7 @@ static void airoha_ppe_foe_insert_entry(struct airoha_ppe *ppe, if (state == AIROHA_FOE_STATE_BIND) goto unlock; - index = airoha_ppe_foe_get_entry_hash(hwe); + index = airoha_ppe_foe_get_entry_hash(ppe, hwe); hlist_for_each_entry_safe(e, n, &ppe->foe_flow[index], list) { if (e->type == FLOW_TYPE_L2_SUBFLOW) { state = FIELD_GET(AIROHA_FOE_IB1_BIND_STATE, hwe->ib1); @@ -832,7 +894,7 @@ static int airoha_ppe_foe_flow_commit_entry(struct airoha_ppe *ppe, if (type == PPE_PKT_TYPE_BRIDGE) return airoha_ppe_foe_l2_flow_commit_entry(ppe, e); - hash = airoha_ppe_foe_get_entry_hash(&e->data); + hash = airoha_ppe_foe_get_entry_hash(ppe, &e->data); e->type = FLOW_TYPE_L4; e->hash = 0xffff; @@ -1158,11 +1220,19 @@ static int airoha_ppe_flow_offload_destroy(struct airoha_eth *eth, void airoha_ppe_foe_entry_get_stats(struct airoha_ppe *ppe, u32 hash, struct airoha_foe_stats64 *stats) { - u32 index = airoha_ppe_foe_get_flow_stats_index(ppe, hash); struct airoha_eth *eth = ppe->eth; + int ppe_num_stats_entries; struct airoha_npu *npu; + u32 index; - if (index >= PPE_STATS_NUM_ENTRIES) + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries < 0) + return; + + if (airoha_ppe_foe_get_flow_stats_index(ppe, hash, &index)) + return; + + if (index >= ppe_num_stats_entries) return; rcu_read_lock(); @@ -1225,20 +1295,22 @@ static int airoha_ppe_flow_offload_cmd(struct airoha_eth *eth, return -EOPNOTSUPP; } -static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe, - struct airoha_npu *npu) +static int airoha_ppe_flush_sram_entries(struct airoha_ppe *ppe) { - int i, sram_num_entries = PPE_SRAM_NUM_ENTRIES; + u32 sram_num_entries = airoha_ppe_get_total_sram_num_entries(ppe); struct airoha_foe_entry *hwe = ppe->foe; + int i, err = 0; - if (airoha_ppe2_is_enabled(ppe->eth)) - sram_num_entries = sram_num_entries / 2; + for (i = 0; i < sram_num_entries; i++) { + int err; - for (i = 0; i < sram_num_entries; i++) memset(&hwe[i], 0, sizeof(*hwe)); + err = airoha_ppe_foe_commit_sram_entry(ppe, i); + if (err) + break; + } - return npu->ops.ppe_flush_sram_entries(npu, ppe->foe_dma, - PPE_SRAM_NUM_ENTRIES); + return err; } static struct airoha_npu *airoha_ppe_npu_get(struct airoha_eth *eth) @@ -1257,7 +1329,7 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) { struct airoha_npu *npu = airoha_ppe_npu_get(eth); struct airoha_ppe *ppe = eth->ppe; - int err; + int err, ppe_num_stats_entries; if (IS_ERR(npu)) return PTR_ERR(npu); @@ -1266,18 +1338,15 @@ static int airoha_ppe_offload_setup(struct airoha_eth *eth) if (err) goto error_npu_put; - if (PPE_STATS_NUM_ENTRIES) { + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries > 0) { err = npu->ops.ppe_init_stats(npu, ppe->foe_stats_dma, - PPE_STATS_NUM_ENTRIES); + ppe_num_stats_entries); if (err) goto error_npu_put; } airoha_ppe_hw_init(ppe); - err = airoha_ppe_flush_sram_entries(ppe, npu); - if (err) - goto error_npu_put; - airoha_ppe_foe_flow_stats_reset(ppe, npu); rcu_assign_pointer(eth->npu, npu); @@ -1313,9 +1382,10 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, u16 hash, bool rx_wlan) { struct airoha_ppe *ppe = dev->priv; + u32 ppe_hash_mask = airoha_ppe_get_total_num_entries(ppe) - 1; u16 now, diff; - if (hash > PPE_HASH_MASK) + if (hash > ppe_hash_mask) return; now = (u16)jiffies; @@ -1405,8 +1475,9 @@ EXPORT_SYMBOL_GPL(airoha_ppe_put_dev); int airoha_ppe_init(struct airoha_eth *eth) { + int foe_size, err, ppe_num_stats_entries; + u32 ppe_num_entries; struct airoha_ppe *ppe; - int foe_size, err; ppe = devm_kzalloc(eth->dev, sizeof(*ppe), GFP_KERNEL); if (!ppe) @@ -1415,24 +1486,25 @@ int airoha_ppe_init(struct airoha_eth *eth) ppe->dev.ops.setup_tc_block_cb = airoha_ppe_setup_tc_block_cb; ppe->dev.ops.check_skb = airoha_ppe_check_skb; ppe->dev.priv = ppe; + ppe->eth = eth; + eth->ppe = ppe; - foe_size = PPE_NUM_ENTRIES * sizeof(struct airoha_foe_entry); + ppe_num_entries = airoha_ppe_get_total_num_entries(ppe); + foe_size = ppe_num_entries * sizeof(struct airoha_foe_entry); ppe->foe = dmam_alloc_coherent(eth->dev, foe_size, &ppe->foe_dma, GFP_KERNEL); if (!ppe->foe) return -ENOMEM; - ppe->eth = eth; - eth->ppe = ppe; - ppe->foe_flow = devm_kzalloc(eth->dev, - PPE_NUM_ENTRIES * sizeof(*ppe->foe_flow), + ppe_num_entries * sizeof(*ppe->foe_flow), GFP_KERNEL); if (!ppe->foe_flow) return -ENOMEM; - foe_size = PPE_STATS_NUM_ENTRIES * sizeof(*ppe->foe_stats); - if (foe_size) { + ppe_num_stats_entries = airoha_ppe_get_total_num_stats_entries(ppe); + if (ppe_num_stats_entries > 0) { + foe_size = ppe_num_stats_entries * sizeof(*ppe->foe_stats); ppe->foe_stats = dmam_alloc_coherent(eth->dev, foe_size, &ppe->foe_stats_dma, GFP_KERNEL); @@ -1440,6 +1512,15 @@ int airoha_ppe_init(struct airoha_eth *eth) return -ENOMEM; } + ppe->foe_check_time = devm_kzalloc(eth->dev, ppe_num_entries, + GFP_KERNEL); + if (!ppe->foe_check_time) + return -ENOMEM; + + err = airoha_ppe_flush_sram_entries(ppe); + if (err) + return err; + err = rhashtable_init(ð->flow_table, &airoha_flow_table_params); if (err) return err; diff --git a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c index 05a756233f6a..0112c41150bb 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c +++ b/drivers/net/ethernet/airoha/airoha_ppe_debugfs.c @@ -53,9 +53,10 @@ static int airoha_ppe_debugfs_foe_show(struct seq_file *m, void *private, [AIROHA_FOE_STATE_FIN] = "FIN", }; struct airoha_ppe *ppe = m->private; + u32 ppe_num_entries = airoha_ppe_get_total_num_entries(ppe); int i; - for (i = 0; i < PPE_NUM_ENTRIES; i++) { + for (i = 0; i < ppe_num_entries; i++) { const char *state_str, *type_str = "UNKNOWN"; void *src_addr = NULL, *dest_addr = NULL; u16 *src_port = NULL, *dest_port = NULL; diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h index 69c5a143db8c..ebcce00d9bc6 100644 --- a/drivers/net/ethernet/airoha/airoha_regs.h +++ b/drivers/net/ethernet/airoha/airoha_regs.h @@ -383,10 +383,8 @@ #define REG_MC_VLAN_DATA 0x2108 #define REG_SP_DFT_CPORT(_n) (0x20e0 + ((_n) << 2)) -#define SP_CPORT_PCIE1_MASK GENMASK(31, 28) -#define SP_CPORT_PCIE0_MASK GENMASK(27, 24) -#define SP_CPORT_USB_MASK GENMASK(7, 4) -#define SP_CPORT_ETH_MASK GENMASK(7, 4) +#define SP_CPORT_DFT_MASK GENMASK(2, 0) +#define SP_CPORT_MASK(_n) GENMASK(3 + ((_n) << 2), ((_n) << 2)) #define REG_SRC_PORT_FC_MAP6 0x2298 #define FC_ID_OF_SRC_PORT27_MASK GENMASK(28, 24) |
