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 'pru-icssm-ethernet-driver'

Parvathi Pudi says:

====================
PRU-ICSSM Ethernet Driver

The Programmable Real-Time Unit Industrial Communication Sub-system (PRU-ICSS)
is available on the TI SOCs in two flavors: Gigabit ICSS (ICSSG) and the older
Megabit ICSS (ICSSM).

Support for ICSSG Dual-EMAC mode has already been mainlined [1] and the
fundamental components/drivers such as PRUSS driver, Remoteproc driver,
PRU-ICSS INTC, and PRU-ICSS IEP drivers are already available in the mainline
Linux kernel. The current set of patch series builds on top of these components
and introduces changes to support the Dual-EMAC using ICSSM on the TI AM57xx,
AM437x and AM335x devices.

AM335x, AM437x and AM57xx devices may have either one or two PRU-ICSS instances
with two 32-bit RISC PRU cores. Each PRU core has (a) dedicated Ethernet interface
(MII, MDIO), timers, capture modules, and serial communication interfaces, and
(b) dedicated data and instruction RAM as well as shared RAM for inter PRU
communication within the PRU-ICSS.

These patches add support for basic RX and TX functionality over PRU Ethernet
ports in Dual-EMAC mode.

Further, note that these are the initial set of patches for a single instance of
PRU-ICSS Ethernet. Additional features such as Ethtool support, VLAN Filtering,
Multicast Filtering, Promiscuous mode, Storm prevention, Interrupt coalescing,
Linux PTP (ptp4l) Ordinary clock and Switch mode support for AM335x, AM437x
and AM57x along with support for a second instance of PRU-ICSS on AM57x
will be posted subsequently.

The patches presented in this series have gone through the patch verification
tools and no warnings or errors are reported. Sample test logs obtained from AM33x,
AM43x and AM57x verifying the functionality on Linux next kernel are available here:

[Interface up Testing](https://gist.github.com/ParvathiPudi/59ca0087dc7bed0f83a3b0e6db27d39c)

[Ping Testing](https://gist.github.com/ParvathiPudi/bcd39aa7006f6176d8c5b71a23d0928b)

[Iperf Testing](https://gist.github.com/ParvathiPudi/9bb4fa42410fbc757a93f65ecb45e4f3)

[1] https://lore.kernel.org/all/20230106121046.886863-1-danishanwar@ti.com/
[2] https://lore.kernel.org/all/20250108125937.10604-1-basharath@couthit.com/
====================

Link: https://patch.msgid.link/20250912104741.528721-1-parvathi@couthit.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+2761 -3
+7 -3
Documentation/devicetree/bindings/net/ti,icss-iep.yaml
··· 8 8 9 9 maintainers: 10 10 - Md Danish Anwar <danishanwar@ti.com> 11 + - Parvathi Pudi <parvathi@couthit.com> 12 + - Basharath Hussain Khaja <basharath@couthit.com> 11 13 12 14 properties: 13 15 compatible: ··· 19 17 - ti,am642-icss-iep 20 18 - ti,j721e-icss-iep 21 19 - const: ti,am654-icss-iep 22 - 23 - - const: ti,am654-icss-iep 24 - 20 + - enum: 21 + - ti,am654-icss-iep 22 + - ti,am5728-icss-iep 23 + - ti,am4376-icss-iep 24 + - ti,am3356-icss-iep 25 25 26 26 reg: 27 27 maxItems: 1
+233
Documentation/devicetree/bindings/net/ti,icssm-prueth.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/ti,icssm-prueth.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Texas Instruments ICSSM PRUSS Ethernet 8 + 9 + maintainers: 10 + - Roger Quadros <rogerq@ti.com> 11 + - Andrew F. Davis <afd@ti.com> 12 + - Parvathi Pudi <parvathi@couthit.com> 13 + - Basharath Hussain Khaja <basharath@couthit.com> 14 + 15 + description: 16 + Ethernet based on the Programmable Real-Time Unit and Industrial 17 + Communication Subsystem. 18 + 19 + properties: 20 + compatible: 21 + enum: 22 + - ti,am57-prueth # for AM57x SoC family 23 + - ti,am4376-prueth # for AM43x SoC family 24 + - ti,am3359-prueth # for AM33x SoC family 25 + 26 + sram: 27 + $ref: /schemas/types.yaml#/definitions/phandle 28 + description: 29 + phandle to OCMC SRAM node 30 + 31 + ti,mii-rt: 32 + $ref: /schemas/types.yaml#/definitions/phandle 33 + description: 34 + phandle to the MII_RT peripheral for ICSS 35 + 36 + ti,iep: 37 + $ref: /schemas/types.yaml#/definitions/phandle 38 + description: 39 + phandle to IEP (Industrial Ethernet Peripheral) for ICSS 40 + 41 + ti,ecap: 42 + $ref: /schemas/types.yaml#/definitions/phandle 43 + description: 44 + phandle to Enhanced Capture (eCAP) event for ICSS 45 + 46 + interrupts: 47 + items: 48 + - description: High priority Rx Interrupt specifier. 49 + - description: Low priority Rx Interrupt specifier. 50 + 51 + interrupt-names: 52 + items: 53 + - const: rx_hp 54 + - const: rx_lp 55 + 56 + ethernet-ports: 57 + type: object 58 + additionalProperties: false 59 + 60 + properties: 61 + '#address-cells': 62 + const: 1 63 + '#size-cells': 64 + const: 0 65 + 66 + patternProperties: 67 + ^ethernet-port@[0-1]$: 68 + type: object 69 + description: ICSSM PRUETH external ports 70 + $ref: ethernet-controller.yaml# 71 + unevaluatedProperties: false 72 + 73 + properties: 74 + reg: 75 + items: 76 + - enum: [0, 1] 77 + description: ICSSM PRUETH port number 78 + 79 + interrupts: 80 + maxItems: 3 81 + 82 + interrupt-names: 83 + items: 84 + - const: rx 85 + - const: emac_ptp_tx 86 + - const: hsr_ptp_tx 87 + 88 + required: 89 + - reg 90 + 91 + anyOf: 92 + - required: 93 + - ethernet-port@0 94 + - required: 95 + - ethernet-port@1 96 + 97 + required: 98 + - compatible 99 + - sram 100 + - ti,mii-rt 101 + - ti,iep 102 + - ti,ecap 103 + - ethernet-ports 104 + - interrupts 105 + - interrupt-names 106 + 107 + allOf: 108 + - $ref: /schemas/remoteproc/ti,pru-consumer.yaml# 109 + 110 + unevaluatedProperties: false 111 + 112 + examples: 113 + - | 114 + /* Dual-MAC Ethernet application node on PRU-ICSS2 */ 115 + pruss2_eth: pruss2-eth { 116 + compatible = "ti,am57-prueth"; 117 + ti,prus = <&pru2_0>, <&pru2_1>; 118 + sram = <&ocmcram1>; 119 + ti,mii-rt = <&pruss2_mii_rt>; 120 + ti,iep = <&pruss2_iep>; 121 + ti,ecap = <&pruss2_ecap>; 122 + interrupts = <20 2 2>, <21 3 3>; 123 + interrupt-names = "rx_hp", "rx_lp"; 124 + interrupt-parent = <&pruss2_intc>; 125 + 126 + ethernet-ports { 127 + #address-cells = <1>; 128 + #size-cells = <0>; 129 + pruss2_emac0: ethernet-port@0 { 130 + reg = <0>; 131 + phy-handle = <&pruss2_eth0_phy>; 132 + phy-mode = "mii"; 133 + interrupts = <20 2 2>, <26 6 6>, <23 6 6>; 134 + interrupt-names = "rx", "emac_ptp_tx", "hsr_ptp_tx"; 135 + /* Filled in by bootloader */ 136 + local-mac-address = [00 00 00 00 00 00]; 137 + }; 138 + 139 + pruss2_emac1: ethernet-port@1 { 140 + reg = <1>; 141 + phy-handle = <&pruss2_eth1_phy>; 142 + phy-mode = "mii"; 143 + interrupts = <21 3 3>, <27 9 7>, <24 9 7>; 144 + interrupt-names = "rx", "emac_ptp_tx", "hsr_ptp_tx"; 145 + /* Filled in by bootloader */ 146 + local-mac-address = [00 00 00 00 00 00]; 147 + }; 148 + }; 149 + }; 150 + - | 151 + /* Dual-MAC Ethernet application node on PRU-ICSS1 */ 152 + pruss1_eth: pruss1-eth { 153 + compatible = "ti,am4376-prueth"; 154 + ti,prus = <&pru1_0>, <&pru1_1>; 155 + sram = <&ocmcram>; 156 + ti,mii-rt = <&pruss1_mii_rt>; 157 + ti,iep = <&pruss1_iep>; 158 + ti,ecap = <&pruss1_ecap>; 159 + interrupts = <20 2 2>, <21 3 3>; 160 + interrupt-names = "rx_hp", "rx_lp"; 161 + interrupt-parent = <&pruss1_intc>; 162 + 163 + pinctrl-0 = <&pruss1_eth_default>; 164 + pinctrl-names = "default"; 165 + 166 + ethernet-ports { 167 + #address-cells = <1>; 168 + #size-cells = <0>; 169 + pruss1_emac0: ethernet-port@0 { 170 + reg = <0>; 171 + phy-handle = <&pruss1_eth0_phy>; 172 + phy-mode = "mii"; 173 + interrupts = <20 2 2>, <26 6 6>, <23 6 6>; 174 + interrupt-names = "rx", "emac_ptp_tx", 175 + "hsr_ptp_tx"; 176 + /* Filled in by bootloader */ 177 + local-mac-address = [00 00 00 00 00 00]; 178 + }; 179 + 180 + pruss1_emac1: ethernet-port@1 { 181 + reg = <1>; 182 + phy-handle = <&pruss1_eth1_phy>; 183 + phy-mode = "mii"; 184 + interrupts = <21 3 3>, <27 9 7>, <24 9 7>; 185 + interrupt-names = "rx", "emac_ptp_tx", 186 + "hsr_ptp_tx"; 187 + /* Filled in by bootloader */ 188 + local-mac-address = [00 00 00 00 00 00]; 189 + }; 190 + }; 191 + }; 192 + - | 193 + /* Dual-MAC Ethernet application node on PRU-ICSS */ 194 + pruss_eth: pruss-eth { 195 + compatible = "ti,am3359-prueth"; 196 + ti,prus = <&pru0>, <&pru1>; 197 + sram = <&ocmcram>; 198 + ti,mii-rt = <&pruss_mii_rt>; 199 + ti,iep = <&pruss_iep>; 200 + ti,ecap = <&pruss_ecap>; 201 + interrupts = <20 2 2>, <21 3 3>; 202 + interrupt-names = "rx_hp", "rx_lp"; 203 + interrupt-parent = <&pruss_intc>; 204 + 205 + pinctrl-0 = <&pruss_eth_default>; 206 + pinctrl-names = "default"; 207 + 208 + ethernet-ports { 209 + #address-cells = <1>; 210 + #size-cells = <0>; 211 + pruss_emac0: ethernet-port@0 { 212 + reg = <0>; 213 + phy-handle = <&pruss_eth0_phy>; 214 + phy-mode = "mii"; 215 + interrupts = <20 2 2>, <26 6 6>, <23 6 6>; 216 + interrupt-names = "rx", "emac_ptp_tx", 217 + "hsr_ptp_tx"; 218 + /* Filled in by bootloader */ 219 + local-mac-address = [00 00 00 00 00 00]; 220 + }; 221 + 222 + pruss_emac1: ethernet-port@1 { 223 + reg = <1>; 224 + phy-handle = <&pruss_eth1_phy>; 225 + phy-mode = "mii"; 226 + interrupts = <21 3 3>, <27 9 7>, <24 9 7>; 227 + interrupt-names = "rx", "emac_ptp_tx", 228 + "hsr_ptp_tx"; 229 + /* Filled in by bootloader */ 230 + local-mac-address = [00 00 00 00 00 00]; 231 + }; 232 + }; 233 + };
+32
Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/ti,pruss-ecap.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Texas Instruments PRU-ICSS Enhanced Capture (eCAP) event module 8 + 9 + maintainers: 10 + - Murali Karicheri <m-karicheri2@ti.com> 11 + - Parvathi Pudi <parvathi@couthit.com> 12 + - Basharath Hussain Khaja <basharath@couthit.com> 13 + 14 + properties: 15 + compatible: 16 + const: ti,pruss-ecap 17 + 18 + reg: 19 + maxItems: 1 20 + 21 + required: 22 + - compatible 23 + - reg 24 + 25 + additionalProperties: false 26 + 27 + examples: 28 + - | 29 + pruss2_ecap: ecap@30000 { 30 + compatible = "ti,pruss-ecap"; 31 + reg = <0x30000 0x60>; 32 + };
+9
Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
··· 251 251 252 252 type: object 253 253 254 + ecap@[a-f0-9]+$: 255 + description: 256 + PRU-ICSS has a Enhanced Capture (eCAP) event module which can generate 257 + and capture periodic timer based events which will be used for features 258 + like RX Pacing to rise interrupt when the timer event has occurred. 259 + Each PRU-ICSS instance has one eCAP module irrespective of SOCs. 260 + $ref: /schemas/net/ti,pruss-ecap.yaml# 261 + type: object 262 + 254 263 mii-rt@[a-f0-9]+$: 255 264 description: | 256 265 Real-Time Ethernet to support multiple industrial communication protocols.
+12
MAINTAINERS
··· 25319 25319 F: Documentation/devicetree/bindings/net/ti,icss*.yaml 25320 25320 F: drivers/net/ethernet/ti/icssg/* 25321 25321 25322 + TI ICSSM ETHERNET DRIVER (ICSSM) 25323 + M: MD Danish Anwar <danishanwar@ti.com> 25324 + M: Parvathi Pudi <parvathi@couthit.com> 25325 + R: Roger Quadros <rogerq@kernel.org> 25326 + R: Mohan Reddy Putluru <pmohan@couthit.com> 25327 + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) 25328 + L: netdev@vger.kernel.org 25329 + S: Maintained 25330 + F: Documentation/devicetree/bindings/net/ti,icssm*.yaml 25331 + F: Documentation/devicetree/bindings/net/ti,pruss-ecap.yaml 25332 + F: drivers/net/ethernet/ti/icssm/* 25333 + 25322 25334 TI J721E CSI2RX DRIVER 25323 25335 M: Jai Luthra <jai.luthra@linux.dev> 25324 25336 L: linux-media@vger.kernel.org
+12
drivers/net/ethernet/ti/Kconfig
··· 229 229 To compile this driver as a module, choose M here. The module 230 230 will be called icss_iep. 231 231 232 + config TI_PRUETH 233 + tristate "TI PRU Ethernet EMAC driver" 234 + depends on PRU_REMOTEPROC 235 + depends on NET_SWITCHDEV 236 + select TI_ICSS_IEP 237 + imply PTP_1588_CLOCK 238 + help 239 + Some TI SoCs has Programmable Realtime Unit (PRU) cores which can 240 + support Single or Dual Ethernet ports with the help of firmware code 241 + running on PRU cores. This driver supports remoteproc based 242 + communication to PRU firmware to expose Ethernet interface to Linux. 243 + 232 244 endif # NET_VENDOR_TI
+3
drivers/net/ethernet/ti/Makefile
··· 3 3 # Makefile for the TI network device drivers. 4 4 # 5 5 6 + obj-$(CONFIG_TI_PRUETH) += icssm-prueth.o 7 + icssm-prueth-y := icssm/icssm_prueth.o 8 + 6 9 obj-$(CONFIG_TI_CPSW) += cpsw-common.o 7 10 obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o 8 11 obj-$(CONFIG_TI_CPSW_SWITCHDEV) += cpsw-common.o
+101
drivers/net/ethernet/ti/icssg/icss_iep.c
··· 982 982 .config = &am654_icss_iep_regmap_config, 983 983 }; 984 984 985 + static const struct icss_iep_plat_data am57xx_icss_iep_plat_data = { 986 + .flags = ICSS_IEP_64BIT_COUNTER_SUPPORT | 987 + ICSS_IEP_SLOW_COMPEN_REG_SUPPORT, 988 + .reg_offs = { 989 + [ICSS_IEP_GLOBAL_CFG_REG] = 0x00, 990 + [ICSS_IEP_COMPEN_REG] = 0x08, 991 + [ICSS_IEP_SLOW_COMPEN_REG] = 0x0c, 992 + [ICSS_IEP_COUNT_REG0] = 0x10, 993 + [ICSS_IEP_COUNT_REG1] = 0x14, 994 + [ICSS_IEP_CAPTURE_CFG_REG] = 0x18, 995 + [ICSS_IEP_CAPTURE_STAT_REG] = 0x1c, 996 + 997 + [ICSS_IEP_CAP6_RISE_REG0] = 0x50, 998 + [ICSS_IEP_CAP6_RISE_REG1] = 0x54, 999 + 1000 + [ICSS_IEP_CAP7_RISE_REG0] = 0x60, 1001 + [ICSS_IEP_CAP7_RISE_REG1] = 0x64, 1002 + 1003 + [ICSS_IEP_CMP_CFG_REG] = 0x70, 1004 + [ICSS_IEP_CMP_STAT_REG] = 0x74, 1005 + [ICSS_IEP_CMP0_REG0] = 0x78, 1006 + [ICSS_IEP_CMP0_REG1] = 0x7c, 1007 + [ICSS_IEP_CMP1_REG0] = 0x80, 1008 + [ICSS_IEP_CMP1_REG1] = 0x84, 1009 + 1010 + [ICSS_IEP_CMP8_REG0] = 0xc0, 1011 + [ICSS_IEP_CMP8_REG1] = 0xc4, 1012 + [ICSS_IEP_SYNC_CTRL_REG] = 0x180, 1013 + [ICSS_IEP_SYNC0_STAT_REG] = 0x188, 1014 + [ICSS_IEP_SYNC1_STAT_REG] = 0x18c, 1015 + [ICSS_IEP_SYNC_PWIDTH_REG] = 0x190, 1016 + [ICSS_IEP_SYNC0_PERIOD_REG] = 0x194, 1017 + [ICSS_IEP_SYNC1_DELAY_REG] = 0x198, 1018 + [ICSS_IEP_SYNC_START_REG] = 0x19c, 1019 + }, 1020 + .config = &am654_icss_iep_regmap_config, 1021 + }; 1022 + 1023 + static bool am335x_icss_iep_valid_reg(struct device *dev, unsigned int reg) 1024 + { 1025 + switch (reg) { 1026 + case ICSS_IEP_GLOBAL_CFG_REG ... ICSS_IEP_CAPTURE_STAT_REG: 1027 + case ICSS_IEP_CAP6_RISE_REG0: 1028 + case ICSS_IEP_CMP_CFG_REG ... ICSS_IEP_CMP0_REG0: 1029 + case ICSS_IEP_CMP8_REG0 ... ICSS_IEP_SYNC_START_REG: 1030 + return true; 1031 + default: 1032 + return false; 1033 + } 1034 + } 1035 + 1036 + static const struct regmap_config am335x_icss_iep_regmap_config = { 1037 + .name = "icss iep", 1038 + .reg_stride = 1, 1039 + .reg_write = icss_iep_regmap_write, 1040 + .reg_read = icss_iep_regmap_read, 1041 + .writeable_reg = am335x_icss_iep_valid_reg, 1042 + .readable_reg = am335x_icss_iep_valid_reg, 1043 + }; 1044 + 1045 + static const struct icss_iep_plat_data am335x_icss_iep_plat_data = { 1046 + .flags = 0, 1047 + .reg_offs = { 1048 + [ICSS_IEP_GLOBAL_CFG_REG] = 0x00, 1049 + [ICSS_IEP_COMPEN_REG] = 0x08, 1050 + [ICSS_IEP_COUNT_REG0] = 0x0c, 1051 + [ICSS_IEP_CAPTURE_CFG_REG] = 0x10, 1052 + [ICSS_IEP_CAPTURE_STAT_REG] = 0x14, 1053 + 1054 + [ICSS_IEP_CAP6_RISE_REG0] = 0x30, 1055 + 1056 + [ICSS_IEP_CAP7_RISE_REG0] = 0x38, 1057 + 1058 + [ICSS_IEP_CMP_CFG_REG] = 0x40, 1059 + [ICSS_IEP_CMP_STAT_REG] = 0x44, 1060 + [ICSS_IEP_CMP0_REG0] = 0x48, 1061 + 1062 + [ICSS_IEP_CMP8_REG0] = 0x88, 1063 + [ICSS_IEP_SYNC_CTRL_REG] = 0x100, 1064 + [ICSS_IEP_SYNC0_STAT_REG] = 0x108, 1065 + [ICSS_IEP_SYNC1_STAT_REG] = 0x10c, 1066 + [ICSS_IEP_SYNC_PWIDTH_REG] = 0x110, 1067 + [ICSS_IEP_SYNC0_PERIOD_REG] = 0x114, 1068 + [ICSS_IEP_SYNC1_DELAY_REG] = 0x118, 1069 + [ICSS_IEP_SYNC_START_REG] = 0x11c, 1070 + }, 1071 + .config = &am335x_icss_iep_regmap_config, 1072 + }; 1073 + 985 1074 static const struct of_device_id icss_iep_of_match[] = { 986 1075 { 987 1076 .compatible = "ti,am654-icss-iep", 988 1077 .data = &am654_icss_iep_plat_data, 1078 + }, 1079 + { 1080 + .compatible = "ti,am5728-icss-iep", 1081 + .data = &am57xx_icss_iep_plat_data, 1082 + }, 1083 + { 1084 + .compatible = "ti,am4376-icss-iep", 1085 + .data = &am335x_icss_iep_plat_data, 1086 + }, 1087 + { 1088 + .compatible = "ti,am3356-icss-iep", 1089 + .data = &am335x_icss_iep_plat_data, 989 1090 }, 990 1091 {}, 991 1092 };
+1748
drivers/net/ethernet/ti/icssm/icssm_prueth.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Texas Instruments ICSSM Ethernet Driver 4 + * 5 + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ 6 + * 7 + */ 8 + 9 + #include <linux/etherdevice.h> 10 + #include <linux/genalloc.h> 11 + #include <linux/if_bridge.h> 12 + #include <linux/if_hsr.h> 13 + #include <linux/if_vlan.h> 14 + #include <linux/interrupt.h> 15 + #include <linux/kernel.h> 16 + #include <linux/mfd/syscon.h> 17 + #include <linux/module.h> 18 + #include <linux/net_tstamp.h> 19 + #include <linux/of.h> 20 + #include <linux/of_irq.h> 21 + #include <linux/of_mdio.h> 22 + #include <linux/of_net.h> 23 + #include <linux/platform_device.h> 24 + #include <linux/phy.h> 25 + #include <linux/remoteproc/pruss.h> 26 + #include <linux/ptp_classify.h> 27 + #include <linux/regmap.h> 28 + #include <linux/remoteproc.h> 29 + #include <net/pkt_cls.h> 30 + 31 + #include "icssm_prueth.h" 32 + #include "../icssg/icssg_mii_rt.h" 33 + #include "../icssg/icss_iep.h" 34 + 35 + #define OCMC_RAM_SIZE (SZ_64K) 36 + 37 + #define TX_START_DELAY 0x40 38 + #define TX_CLK_DELAY_100M 0x6 39 + #define HR_TIMER_TX_DELAY_US 100 40 + 41 + static void icssm_prueth_write_reg(struct prueth *prueth, 42 + enum prueth_mem region, 43 + unsigned int reg, u32 val) 44 + { 45 + writel_relaxed(val, prueth->mem[region].va + reg); 46 + } 47 + 48 + /* Below macro is for 1528 Byte Frame support, to Allow even with 49 + * Redundancy tag 50 + */ 51 + #define PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC (VLAN_ETH_FRAME_LEN + \ 52 + ETH_FCS_LEN + \ 53 + ICSSM_LRE_TAG_SIZE) 54 + 55 + /* ensure that order of PRUSS mem regions is same as enum prueth_mem */ 56 + static enum pruss_mem pruss_mem_ids[] = { PRUSS_MEM_DRAM0, PRUSS_MEM_DRAM1, 57 + PRUSS_MEM_SHRD_RAM2 }; 58 + 59 + static const struct prueth_queue_info queue_infos[][NUM_QUEUES] = { 60 + [PRUETH_PORT_QUEUE_HOST] = { 61 + [PRUETH_QUEUE1] = { 62 + P0_Q1_BUFFER_OFFSET, 63 + HOST_QUEUE_DESC_OFFSET, 64 + P0_Q1_BD_OFFSET, 65 + P0_Q1_BD_OFFSET + ((HOST_QUEUE_1_SIZE - 1) * BD_SIZE), 66 + }, 67 + [PRUETH_QUEUE2] = { 68 + P0_Q2_BUFFER_OFFSET, 69 + HOST_QUEUE_DESC_OFFSET + 8, 70 + P0_Q2_BD_OFFSET, 71 + P0_Q2_BD_OFFSET + ((HOST_QUEUE_2_SIZE - 1) * BD_SIZE), 72 + }, 73 + [PRUETH_QUEUE3] = { 74 + P0_Q3_BUFFER_OFFSET, 75 + HOST_QUEUE_DESC_OFFSET + 16, 76 + P0_Q3_BD_OFFSET, 77 + P0_Q3_BD_OFFSET + ((HOST_QUEUE_3_SIZE - 1) * BD_SIZE), 78 + }, 79 + [PRUETH_QUEUE4] = { 80 + P0_Q4_BUFFER_OFFSET, 81 + HOST_QUEUE_DESC_OFFSET + 24, 82 + P0_Q4_BD_OFFSET, 83 + P0_Q4_BD_OFFSET + ((HOST_QUEUE_4_SIZE - 1) * BD_SIZE), 84 + }, 85 + }, 86 + [PRUETH_PORT_QUEUE_MII0] = { 87 + [PRUETH_QUEUE1] = { 88 + P1_Q1_BUFFER_OFFSET, 89 + P1_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * 90 + ICSS_BLOCK_SIZE), 91 + P1_Q1_BD_OFFSET, 92 + P1_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), 93 + }, 94 + [PRUETH_QUEUE2] = { 95 + P1_Q2_BUFFER_OFFSET, 96 + P1_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * 97 + ICSS_BLOCK_SIZE), 98 + P1_Q2_BD_OFFSET, 99 + P1_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), 100 + }, 101 + [PRUETH_QUEUE3] = { 102 + P1_Q3_BUFFER_OFFSET, 103 + P1_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * 104 + ICSS_BLOCK_SIZE), 105 + P1_Q3_BD_OFFSET, 106 + P1_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), 107 + }, 108 + [PRUETH_QUEUE4] = { 109 + P1_Q4_BUFFER_OFFSET, 110 + P1_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * 111 + ICSS_BLOCK_SIZE), 112 + P1_Q4_BD_OFFSET, 113 + P1_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), 114 + }, 115 + }, 116 + [PRUETH_PORT_QUEUE_MII1] = { 117 + [PRUETH_QUEUE1] = { 118 + P2_Q1_BUFFER_OFFSET, 119 + P2_Q1_BUFFER_OFFSET + ((QUEUE_1_SIZE - 1) * 120 + ICSS_BLOCK_SIZE), 121 + P2_Q1_BD_OFFSET, 122 + P2_Q1_BD_OFFSET + ((QUEUE_1_SIZE - 1) * BD_SIZE), 123 + }, 124 + [PRUETH_QUEUE2] = { 125 + P2_Q2_BUFFER_OFFSET, 126 + P2_Q2_BUFFER_OFFSET + ((QUEUE_2_SIZE - 1) * 127 + ICSS_BLOCK_SIZE), 128 + P2_Q2_BD_OFFSET, 129 + P2_Q2_BD_OFFSET + ((QUEUE_2_SIZE - 1) * BD_SIZE), 130 + }, 131 + [PRUETH_QUEUE3] = { 132 + P2_Q3_BUFFER_OFFSET, 133 + P2_Q3_BUFFER_OFFSET + ((QUEUE_3_SIZE - 1) * 134 + ICSS_BLOCK_SIZE), 135 + P2_Q3_BD_OFFSET, 136 + P2_Q3_BD_OFFSET + ((QUEUE_3_SIZE - 1) * BD_SIZE), 137 + }, 138 + [PRUETH_QUEUE4] = { 139 + P2_Q4_BUFFER_OFFSET, 140 + P2_Q4_BUFFER_OFFSET + ((QUEUE_4_SIZE - 1) * 141 + ICSS_BLOCK_SIZE), 142 + P2_Q4_BD_OFFSET, 143 + P2_Q4_BD_OFFSET + ((QUEUE_4_SIZE - 1) * BD_SIZE), 144 + }, 145 + }, 146 + }; 147 + 148 + static const struct prueth_queue_desc queue_descs[][NUM_QUEUES] = { 149 + [PRUETH_PORT_QUEUE_HOST] = { 150 + { .rd_ptr = P0_Q1_BD_OFFSET, .wr_ptr = P0_Q1_BD_OFFSET, }, 151 + { .rd_ptr = P0_Q2_BD_OFFSET, .wr_ptr = P0_Q2_BD_OFFSET, }, 152 + { .rd_ptr = P0_Q3_BD_OFFSET, .wr_ptr = P0_Q3_BD_OFFSET, }, 153 + { .rd_ptr = P0_Q4_BD_OFFSET, .wr_ptr = P0_Q4_BD_OFFSET, }, 154 + }, 155 + [PRUETH_PORT_QUEUE_MII0] = { 156 + { .rd_ptr = P1_Q1_BD_OFFSET, .wr_ptr = P1_Q1_BD_OFFSET, }, 157 + { .rd_ptr = P1_Q2_BD_OFFSET, .wr_ptr = P1_Q2_BD_OFFSET, }, 158 + { .rd_ptr = P1_Q3_BD_OFFSET, .wr_ptr = P1_Q3_BD_OFFSET, }, 159 + { .rd_ptr = P1_Q4_BD_OFFSET, .wr_ptr = P1_Q4_BD_OFFSET, }, 160 + }, 161 + [PRUETH_PORT_QUEUE_MII1] = { 162 + { .rd_ptr = P2_Q1_BD_OFFSET, .wr_ptr = P2_Q1_BD_OFFSET, }, 163 + { .rd_ptr = P2_Q2_BD_OFFSET, .wr_ptr = P2_Q2_BD_OFFSET, }, 164 + { .rd_ptr = P2_Q3_BD_OFFSET, .wr_ptr = P2_Q3_BD_OFFSET, }, 165 + { .rd_ptr = P2_Q4_BD_OFFSET, .wr_ptr = P2_Q4_BD_OFFSET, }, 166 + } 167 + }; 168 + 169 + static void icssm_prueth_hostconfig(struct prueth *prueth) 170 + { 171 + void __iomem *sram_base = prueth->mem[PRUETH_MEM_SHARED_RAM].va; 172 + void __iomem *sram; 173 + 174 + /* queue size lookup table */ 175 + sram = sram_base + HOST_QUEUE_SIZE_ADDR; 176 + writew(HOST_QUEUE_1_SIZE, sram); 177 + writew(HOST_QUEUE_2_SIZE, sram + 2); 178 + writew(HOST_QUEUE_3_SIZE, sram + 4); 179 + writew(HOST_QUEUE_4_SIZE, sram + 6); 180 + 181 + /* queue information table */ 182 + sram = sram_base + HOST_Q1_RX_CONTEXT_OFFSET; 183 + memcpy_toio(sram, queue_infos[PRUETH_PORT_QUEUE_HOST], 184 + sizeof(queue_infos[PRUETH_PORT_QUEUE_HOST])); 185 + 186 + /* buffer offset table */ 187 + sram = sram_base + HOST_QUEUE_OFFSET_ADDR; 188 + writew(P0_Q1_BUFFER_OFFSET, sram); 189 + writew(P0_Q2_BUFFER_OFFSET, sram + 2); 190 + writew(P0_Q3_BUFFER_OFFSET, sram + 4); 191 + writew(P0_Q4_BUFFER_OFFSET, sram + 6); 192 + 193 + /* buffer descriptor offset table*/ 194 + sram = sram_base + HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR; 195 + writew(P0_Q1_BD_OFFSET, sram); 196 + writew(P0_Q2_BD_OFFSET, sram + 2); 197 + writew(P0_Q3_BD_OFFSET, sram + 4); 198 + writew(P0_Q4_BD_OFFSET, sram + 6); 199 + 200 + /* queue table */ 201 + sram = sram_base + HOST_QUEUE_DESC_OFFSET; 202 + memcpy_toio(sram, queue_descs[PRUETH_PORT_QUEUE_HOST], 203 + sizeof(queue_descs[PRUETH_PORT_QUEUE_HOST])); 204 + } 205 + 206 + static void icssm_prueth_mii_init(struct prueth *prueth) 207 + { 208 + struct regmap *mii_rt; 209 + u32 rxcfg_reg, rxcfg; 210 + u32 txcfg_reg, txcfg; 211 + 212 + mii_rt = prueth->mii_rt; 213 + 214 + rxcfg = PRUSS_MII_RT_RXCFG_RX_ENABLE | 215 + PRUSS_MII_RT_RXCFG_RX_DATA_RDY_MODE_DIS | 216 + PRUSS_MII_RT_RXCFG_RX_L2_EN | 217 + PRUSS_MII_RT_RXCFG_RX_CUT_PREAMBLE | 218 + PRUSS_MII_RT_RXCFG_RX_L2_EOF_SCLR_DIS; 219 + 220 + /* Configuration of Port 0 Rx */ 221 + rxcfg_reg = PRUSS_MII_RT_RXCFG0; 222 + 223 + regmap_write(mii_rt, rxcfg_reg, rxcfg); 224 + 225 + /* Configuration of Port 1 Rx */ 226 + rxcfg_reg = PRUSS_MII_RT_RXCFG1; 227 + 228 + rxcfg |= PRUSS_MII_RT_RXCFG_RX_MUX_SEL; 229 + 230 + regmap_write(mii_rt, rxcfg_reg, rxcfg); 231 + 232 + txcfg = PRUSS_MII_RT_TXCFG_TX_ENABLE | 233 + PRUSS_MII_RT_TXCFG_TX_AUTO_PREAMBLE | 234 + PRUSS_MII_RT_TXCFG_TX_32_MODE_EN | 235 + (TX_START_DELAY << PRUSS_MII_RT_TXCFG_TX_START_DELAY_SHIFT) | 236 + (TX_CLK_DELAY_100M << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT); 237 + 238 + /* Configuration of Port 0 Tx */ 239 + txcfg_reg = PRUSS_MII_RT_TXCFG0; 240 + 241 + regmap_write(mii_rt, txcfg_reg, txcfg); 242 + 243 + txcfg |= PRUSS_MII_RT_TXCFG_TX_MUX_SEL; 244 + 245 + /* Configuration of Port 1 Tx */ 246 + txcfg_reg = PRUSS_MII_RT_TXCFG1; 247 + 248 + regmap_write(mii_rt, txcfg_reg, txcfg); 249 + 250 + txcfg_reg = PRUSS_MII_RT_RX_FRMS0; 251 + 252 + /* Min frame length should be set to 64 to allow receive of standard 253 + * Ethernet frames such as PTP, LLDP that will not have the tag/rct. 254 + * Actual size written to register is size - 1 per TRM. This also 255 + * includes CRC/FCS. 256 + */ 257 + txcfg = FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MIN_FRM_MASK, 258 + (PRUSS_MII_RT_RX_FRMS_MIN_FRM - 1)); 259 + 260 + /* For EMAC, set Max frame size to 1528 i.e size with VLAN. 261 + * Actual size written to register is size - 1 as per TRM. 262 + * Since driver support run time change of protocol, driver 263 + * must overwrite the values based on Ethernet type. 264 + */ 265 + txcfg |= FIELD_PREP(PRUSS_MII_RT_RX_FRMS_MAX_FRM_MASK, 266 + (PRUSS_MII_RT_RX_FRMS_MAX_SUPPORT_EMAC - 1)); 267 + 268 + regmap_write(mii_rt, txcfg_reg, txcfg); 269 + 270 + txcfg_reg = PRUSS_MII_RT_RX_FRMS1; 271 + 272 + regmap_write(mii_rt, txcfg_reg, txcfg); 273 + } 274 + 275 + static void icssm_prueth_clearmem(struct prueth *prueth, enum prueth_mem region) 276 + { 277 + memset_io(prueth->mem[region].va, 0, prueth->mem[region].size); 278 + } 279 + 280 + static void icssm_prueth_hostinit(struct prueth *prueth) 281 + { 282 + /* Clear shared RAM */ 283 + icssm_prueth_clearmem(prueth, PRUETH_MEM_SHARED_RAM); 284 + 285 + /* Clear OCMC RAM */ 286 + icssm_prueth_clearmem(prueth, PRUETH_MEM_OCMC); 287 + 288 + /* Clear data RAMs */ 289 + if (prueth->eth_node[PRUETH_MAC0]) 290 + icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM0); 291 + if (prueth->eth_node[PRUETH_MAC1]) 292 + icssm_prueth_clearmem(prueth, PRUETH_MEM_DRAM1); 293 + 294 + /* Initialize host queues in shared RAM */ 295 + icssm_prueth_hostconfig(prueth); 296 + 297 + /* Configure MII_RT */ 298 + icssm_prueth_mii_init(prueth); 299 + } 300 + 301 + /* This function initialize the driver in EMAC mode 302 + * based on eth_type 303 + */ 304 + static void icssm_prueth_init_ethernet_mode(struct prueth *prueth) 305 + { 306 + icssm_prueth_hostinit(prueth); 307 + } 308 + 309 + static void icssm_prueth_port_enable(struct prueth_emac *emac, bool enable) 310 + { 311 + struct prueth *prueth = emac->prueth; 312 + void __iomem *port_ctrl; 313 + void __iomem *ram; 314 + 315 + ram = prueth->mem[emac->dram].va; 316 + port_ctrl = ram + PORT_CONTROL_ADDR; 317 + writeb(!!enable, port_ctrl); 318 + } 319 + 320 + static int icssm_prueth_emac_config(struct prueth_emac *emac) 321 + { 322 + struct prueth *prueth = emac->prueth; 323 + u32 sharedramaddr, ocmcaddr; 324 + void __iomem *dram_base; 325 + void __iomem *mac_addr; 326 + void __iomem *dram; 327 + void __iomem *sram; 328 + 329 + /* PRU needs local shared RAM address for C28 */ 330 + sharedramaddr = ICSS_LOCAL_SHARED_RAM; 331 + /* PRU needs real global OCMC address for C30*/ 332 + ocmcaddr = (u32)prueth->mem[PRUETH_MEM_OCMC].pa; 333 + sram = prueth->mem[PRUETH_MEM_SHARED_RAM].va; 334 + 335 + /* Clear data RAM */ 336 + icssm_prueth_clearmem(prueth, emac->dram); 337 + 338 + dram_base = prueth->mem[emac->dram].va; 339 + 340 + /* setup mac address */ 341 + mac_addr = dram_base + PORT_MAC_ADDR; 342 + memcpy_toio(mac_addr, emac->mac_addr, 6); 343 + 344 + /* queue information table */ 345 + dram = dram_base + TX_CONTEXT_Q1_OFFSET_ADDR; 346 + memcpy_toio(dram, queue_infos[emac->port_id], 347 + sizeof(queue_infos[emac->port_id])); 348 + 349 + /* queue table */ 350 + dram = dram_base + PORT_QUEUE_DESC_OFFSET; 351 + memcpy_toio(dram, queue_descs[emac->port_id], 352 + sizeof(queue_descs[emac->port_id])); 353 + 354 + emac->rx_queue_descs = sram + HOST_QUEUE_DESC_OFFSET; 355 + emac->tx_queue_descs = dram; 356 + 357 + /* Set in constant table C28 of PRU0 to ICSS Shared memory */ 358 + pru_rproc_set_ctable(emac->pru, PRU_C28, sharedramaddr); 359 + 360 + /* Set in constant table C30 of PRU0 to OCMC memory */ 361 + pru_rproc_set_ctable(emac->pru, PRU_C30, ocmcaddr); 362 + 363 + return 0; 364 + } 365 + 366 + /* called back by PHY layer if there is change in link state of hw port*/ 367 + static void icssm_emac_adjust_link(struct net_device *ndev) 368 + { 369 + struct prueth_emac *emac = netdev_priv(ndev); 370 + struct phy_device *phydev = emac->phydev; 371 + struct prueth *prueth = emac->prueth; 372 + bool new_state = false; 373 + enum prueth_mem region; 374 + unsigned long flags; 375 + u32 port_status = 0; 376 + u32 txcfg, mask; 377 + u32 delay; 378 + 379 + spin_lock_irqsave(&emac->lock, flags); 380 + 381 + if (phydev->link) { 382 + /* check the mode of operation */ 383 + if (phydev->duplex != emac->duplex) { 384 + new_state = true; 385 + emac->duplex = phydev->duplex; 386 + } 387 + if (phydev->speed != emac->speed) { 388 + new_state = true; 389 + emac->speed = phydev->speed; 390 + } 391 + if (!emac->link) { 392 + new_state = true; 393 + emac->link = 1; 394 + } 395 + } else if (emac->link) { 396 + new_state = true; 397 + emac->link = 0; 398 + } 399 + 400 + if (new_state) { 401 + phy_print_status(phydev); 402 + region = emac->dram; 403 + 404 + /* update phy/port status information based on PHY values*/ 405 + if (emac->link) { 406 + port_status |= PORT_LINK_MASK; 407 + 408 + icssm_prueth_write_reg(prueth, region, PHY_SPEED_OFFSET, 409 + emac->speed); 410 + 411 + delay = TX_CLK_DELAY_100M; 412 + delay = delay << PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_SHIFT; 413 + mask = PRUSS_MII_RT_TXCFG_TX_CLK_DELAY_MASK; 414 + 415 + if (emac->port_id) 416 + txcfg = PRUSS_MII_RT_TXCFG1; 417 + else 418 + txcfg = PRUSS_MII_RT_TXCFG0; 419 + 420 + regmap_update_bits(prueth->mii_rt, txcfg, mask, delay); 421 + } 422 + 423 + writeb(port_status, prueth->mem[region].va + 424 + PORT_STATUS_OFFSET); 425 + } 426 + 427 + if (emac->link) { 428 + /* reactivate the transmit queue if it is stopped */ 429 + if (netif_running(ndev) && netif_queue_stopped(ndev)) 430 + netif_wake_queue(ndev); 431 + } else { 432 + if (!netif_queue_stopped(ndev)) 433 + netif_stop_queue(ndev); 434 + } 435 + 436 + spin_unlock_irqrestore(&emac->lock, flags); 437 + } 438 + 439 + static unsigned int 440 + icssm_get_buff_desc_count(const struct prueth_queue_info *queue) 441 + { 442 + unsigned int buffer_desc_count; 443 + 444 + buffer_desc_count = queue->buffer_desc_end - 445 + queue->buffer_desc_offset; 446 + buffer_desc_count /= BD_SIZE; 447 + buffer_desc_count++; 448 + 449 + return buffer_desc_count; 450 + } 451 + 452 + static void icssm_get_block(struct prueth_queue_desc __iomem *queue_desc, 453 + const struct prueth_queue_info *queue, 454 + int *write_block, int *read_block) 455 + { 456 + *write_block = (readw(&queue_desc->wr_ptr) - 457 + queue->buffer_desc_offset) / BD_SIZE; 458 + *read_block = (readw(&queue_desc->rd_ptr) - 459 + queue->buffer_desc_offset) / BD_SIZE; 460 + } 461 + 462 + /** 463 + * icssm_emac_rx_irq - EMAC Rx interrupt handler 464 + * @irq: interrupt number 465 + * @dev_id: pointer to net_device 466 + * 467 + * EMAC Interrupt handler - we only schedule NAPI and not process any packets 468 + * here. 469 + * 470 + * Return: IRQ_HANDLED if the interrupt handled 471 + */ 472 + static irqreturn_t icssm_emac_rx_irq(int irq, void *dev_id) 473 + { 474 + struct net_device *ndev = (struct net_device *)dev_id; 475 + struct prueth_emac *emac = netdev_priv(ndev); 476 + 477 + if (likely(netif_running(ndev))) { 478 + /* disable Rx system event */ 479 + disable_irq_nosync(emac->rx_irq); 480 + napi_schedule(&emac->napi); 481 + } 482 + 483 + return IRQ_HANDLED; 484 + } 485 + 486 + /** 487 + * icssm_prueth_tx_enqueue - queue a packet to firmware for transmission 488 + * 489 + * @emac: EMAC data structure 490 + * @skb: packet data buffer 491 + * @queue_id: priority queue id 492 + * 493 + * Return: 0 (Success) 494 + */ 495 + static int icssm_prueth_tx_enqueue(struct prueth_emac *emac, 496 + struct sk_buff *skb, 497 + enum prueth_queue_id queue_id) 498 + { 499 + struct prueth_queue_desc __iomem *queue_desc; 500 + const struct prueth_queue_info *txqueue; 501 + struct net_device *ndev = emac->ndev; 502 + unsigned int buffer_desc_count; 503 + int free_blocks, update_block; 504 + bool buffer_wrapped = false; 505 + int write_block, read_block; 506 + void *src_addr, *dst_addr; 507 + int pkt_block_size; 508 + void __iomem *dram; 509 + int txport, pktlen; 510 + u16 update_wr_ptr; 511 + u32 wr_buf_desc; 512 + void *ocmc_ram; 513 + 514 + dram = emac->prueth->mem[emac->dram].va; 515 + if (eth_skb_pad(skb)) { 516 + if (netif_msg_tx_err(emac) && net_ratelimit()) 517 + netdev_err(ndev, "packet pad failed\n"); 518 + return -ENOMEM; 519 + } 520 + 521 + /* which port to tx: MII0 or MII1 */ 522 + txport = emac->tx_port_queue; 523 + src_addr = skb->data; 524 + pktlen = skb->len; 525 + /* Get the tx queue */ 526 + queue_desc = emac->tx_queue_descs + queue_id; 527 + txqueue = &queue_infos[txport][queue_id]; 528 + 529 + buffer_desc_count = icssm_get_buff_desc_count(txqueue); 530 + 531 + /* the PRU firmware deals mostly in pointers already 532 + * offset into ram, we would like to deal in indexes 533 + * within the queue we are working with for code 534 + * simplicity, calculate this here 535 + */ 536 + icssm_get_block(queue_desc, txqueue, &write_block, &read_block); 537 + 538 + if (write_block > read_block) { 539 + free_blocks = buffer_desc_count - write_block; 540 + free_blocks += read_block; 541 + } else if (write_block < read_block) { 542 + free_blocks = read_block - write_block; 543 + } else { /* they are all free */ 544 + free_blocks = buffer_desc_count; 545 + } 546 + 547 + pkt_block_size = DIV_ROUND_UP(pktlen, ICSS_BLOCK_SIZE); 548 + if (pkt_block_size > free_blocks) /* out of queue space */ 549 + return -ENOBUFS; 550 + 551 + /* calculate end BD address post write */ 552 + update_block = write_block + pkt_block_size; 553 + 554 + /* Check for wrap around */ 555 + if (update_block >= buffer_desc_count) { 556 + update_block %= buffer_desc_count; 557 + buffer_wrapped = true; 558 + } 559 + 560 + /* OCMC RAM is not cached and write order is not important */ 561 + ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va; 562 + dst_addr = ocmc_ram + txqueue->buffer_offset + 563 + (write_block * ICSS_BLOCK_SIZE); 564 + 565 + /* Copy the data from socket buffer(DRAM) to PRU buffers(OCMC) */ 566 + if (buffer_wrapped) { /* wrapped around buffer */ 567 + int bytes = (buffer_desc_count - write_block) * ICSS_BLOCK_SIZE; 568 + int remaining; 569 + 570 + /* bytes is integral multiple of ICSS_BLOCK_SIZE but 571 + * entire packet may have fit within the last BD 572 + * if pkt_info.length is not integral multiple of 573 + * ICSS_BLOCK_SIZE 574 + */ 575 + if (pktlen < bytes) 576 + bytes = pktlen; 577 + 578 + /* copy non-wrapped part */ 579 + memcpy(dst_addr, src_addr, bytes); 580 + 581 + /* copy wrapped part */ 582 + src_addr += bytes; 583 + remaining = pktlen - bytes; 584 + dst_addr = ocmc_ram + txqueue->buffer_offset; 585 + memcpy(dst_addr, src_addr, remaining); 586 + } else { 587 + memcpy(dst_addr, src_addr, pktlen); 588 + } 589 + 590 + /* update first buffer descriptor */ 591 + wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) & 592 + PRUETH_BD_LENGTH_MASK; 593 + writel(wr_buf_desc, dram + readw(&queue_desc->wr_ptr)); 594 + 595 + /* update the write pointer in this queue descriptor, the firmware 596 + * polls for this change so this will signal the start of transmission 597 + */ 598 + update_wr_ptr = txqueue->buffer_desc_offset + (update_block * BD_SIZE); 599 + writew(update_wr_ptr, &queue_desc->wr_ptr); 600 + 601 + return 0; 602 + } 603 + 604 + void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, 605 + struct prueth_packet_info *pkt_info) 606 + { 607 + pkt_info->shadow = !!(buffer_descriptor & PRUETH_BD_SHADOW_MASK); 608 + pkt_info->port = (buffer_descriptor & PRUETH_BD_PORT_MASK) >> 609 + PRUETH_BD_PORT_SHIFT; 610 + pkt_info->length = (buffer_descriptor & PRUETH_BD_LENGTH_MASK) >> 611 + PRUETH_BD_LENGTH_SHIFT; 612 + pkt_info->broadcast = !!(buffer_descriptor & PRUETH_BD_BROADCAST_MASK); 613 + pkt_info->error = !!(buffer_descriptor & PRUETH_BD_ERROR_MASK); 614 + pkt_info->lookup_success = !!(buffer_descriptor & 615 + PRUETH_BD_LOOKUP_SUCCESS_MASK); 616 + pkt_info->flood = !!(buffer_descriptor & PRUETH_BD_SW_FLOOD_MASK); 617 + pkt_info->timestamp = !!(buffer_descriptor & PRUETH_BD_TIMESTAMP_MASK); 618 + } 619 + 620 + /** 621 + * icssm_emac_rx_packet - EMAC Receive function 622 + * 623 + * @emac: EMAC data structure 624 + * @bd_rd_ptr: Buffer descriptor read pointer 625 + * @pkt_info: packet information structure 626 + * @rxqueue: Receive queue information structure 627 + * 628 + * Get a packet from receive queue 629 + * 630 + * Return: 0 (Success) 631 + */ 632 + int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, 633 + struct prueth_packet_info *pkt_info, 634 + const struct prueth_queue_info *rxqueue) 635 + { 636 + struct net_device *ndev = emac->ndev; 637 + unsigned int buffer_desc_count; 638 + int read_block, update_block; 639 + unsigned int actual_pkt_len; 640 + bool buffer_wrapped = false; 641 + void *src_addr, *dst_addr; 642 + struct sk_buff *skb; 643 + int pkt_block_size; 644 + void *ocmc_ram; 645 + 646 + /* the PRU firmware deals mostly in pointers already 647 + * offset into ram, we would like to deal in indexes 648 + * within the queue we are working with for code 649 + * simplicity, calculate this here 650 + */ 651 + buffer_desc_count = icssm_get_buff_desc_count(rxqueue); 652 + read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE; 653 + pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE); 654 + 655 + /* calculate end BD address post read */ 656 + update_block = read_block + pkt_block_size; 657 + 658 + /* Check for wrap around */ 659 + if (update_block >= buffer_desc_count) { 660 + update_block %= buffer_desc_count; 661 + if (update_block) 662 + buffer_wrapped = true; 663 + } 664 + 665 + /* calculate new pointer in ram */ 666 + *bd_rd_ptr = rxqueue->buffer_desc_offset + (update_block * BD_SIZE); 667 + 668 + actual_pkt_len = pkt_info->length; 669 + 670 + /* Allocate a socket buffer for this packet */ 671 + skb = netdev_alloc_skb_ip_align(ndev, actual_pkt_len); 672 + if (!skb) { 673 + if (netif_msg_rx_err(emac) && net_ratelimit()) 674 + netdev_err(ndev, "failed rx buffer alloc\n"); 675 + return -ENOMEM; 676 + } 677 + 678 + dst_addr = skb->data; 679 + 680 + /* OCMC RAM is not cached and read order is not important */ 681 + ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va; 682 + 683 + /* Get the start address of the first buffer from 684 + * the read buffer description 685 + */ 686 + src_addr = ocmc_ram + rxqueue->buffer_offset + 687 + (read_block * ICSS_BLOCK_SIZE); 688 + 689 + /* Copy the data from PRU buffers(OCMC) to socket buffer(DRAM) */ 690 + if (buffer_wrapped) { /* wrapped around buffer */ 691 + int bytes = (buffer_desc_count - read_block) * ICSS_BLOCK_SIZE; 692 + int remaining; 693 + /* bytes is integral multiple of ICSS_BLOCK_SIZE but 694 + * entire packet may have fit within the last BD 695 + * if pkt_info.length is not integral multiple of 696 + * ICSS_BLOCK_SIZE 697 + */ 698 + if (pkt_info->length < bytes) 699 + bytes = pkt_info->length; 700 + 701 + /* copy non-wrapped part */ 702 + memcpy(dst_addr, src_addr, bytes); 703 + 704 + /* copy wrapped part */ 705 + dst_addr += bytes; 706 + remaining = actual_pkt_len - bytes; 707 + 708 + src_addr = ocmc_ram + rxqueue->buffer_offset; 709 + memcpy(dst_addr, src_addr, remaining); 710 + src_addr += remaining; 711 + } else { 712 + memcpy(dst_addr, src_addr, actual_pkt_len); 713 + src_addr += actual_pkt_len; 714 + } 715 + 716 + skb_put(skb, actual_pkt_len); 717 + 718 + /* send packet up the stack */ 719 + skb->protocol = eth_type_trans(skb, ndev); 720 + netif_receive_skb(skb); 721 + 722 + /* update stats */ 723 + emac->stats.rx_bytes += actual_pkt_len; 724 + emac->stats.rx_packets++; 725 + 726 + return 0; 727 + } 728 + 729 + static int icssm_emac_rx_packets(struct prueth_emac *emac, int budget) 730 + { 731 + struct prueth_queue_desc __iomem *queue_desc; 732 + const struct prueth_queue_info *rxqueue; 733 + struct prueth *prueth = emac->prueth; 734 + struct prueth_packet_info pkt_info; 735 + int start_queue, end_queue; 736 + void __iomem *shared_ram; 737 + u16 bd_rd_ptr, bd_wr_ptr; 738 + u16 update_rd_ptr; 739 + u8 overflow_cnt; 740 + u32 rd_buf_desc; 741 + int used = 0; 742 + int i, ret; 743 + 744 + shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; 745 + 746 + start_queue = emac->rx_queue_start; 747 + end_queue = emac->rx_queue_end; 748 + 749 + /* skip Rx if budget is 0 */ 750 + if (!budget) 751 + return 0; 752 + 753 + /* search host queues for packets */ 754 + for (i = start_queue; i <= end_queue; i++) { 755 + queue_desc = emac->rx_queue_descs + i; 756 + rxqueue = &queue_infos[PRUETH_PORT_HOST][i]; 757 + 758 + overflow_cnt = readb(&queue_desc->overflow_cnt); 759 + if (overflow_cnt > 0) { 760 + emac->stats.rx_over_errors += overflow_cnt; 761 + /* reset to zero */ 762 + writeb(0, &queue_desc->overflow_cnt); 763 + } 764 + 765 + bd_rd_ptr = readw(&queue_desc->rd_ptr); 766 + bd_wr_ptr = readw(&queue_desc->wr_ptr); 767 + 768 + /* while packets are available in this queue */ 769 + while (bd_rd_ptr != bd_wr_ptr) { 770 + /* get packet info from the read buffer descriptor */ 771 + rd_buf_desc = readl(shared_ram + bd_rd_ptr); 772 + icssm_parse_packet_info(prueth, rd_buf_desc, &pkt_info); 773 + 774 + if (pkt_info.length <= 0) { 775 + /* a packet length of zero will cause us to 776 + * never move the read pointer ahead, locking 777 + * the driver, so we manually have to move it 778 + * to the write pointer, discarding all 779 + * remaining packets in this queue. This should 780 + * never happen. 781 + */ 782 + update_rd_ptr = bd_wr_ptr; 783 + emac->stats.rx_length_errors++; 784 + } else if (pkt_info.length > EMAC_MAX_FRM_SUPPORT) { 785 + /* if the packet is too large we skip it but we 786 + * still need to move the read pointer ahead 787 + * and assume something is wrong with the read 788 + * pointer as the firmware should be filtering 789 + * these packets 790 + */ 791 + update_rd_ptr = bd_wr_ptr; 792 + emac->stats.rx_length_errors++; 793 + } else { 794 + update_rd_ptr = bd_rd_ptr; 795 + ret = icssm_emac_rx_packet(emac, &update_rd_ptr, 796 + &pkt_info, rxqueue); 797 + if (ret) 798 + return used; 799 + used++; 800 + } 801 + 802 + /* after reading the buffer descriptor we clear it 803 + * to prevent improperly moved read pointer errors 804 + * from simply looking like old packets. 805 + */ 806 + writel(0, shared_ram + bd_rd_ptr); 807 + 808 + /* update read pointer in queue descriptor */ 809 + writew(update_rd_ptr, &queue_desc->rd_ptr); 810 + bd_rd_ptr = update_rd_ptr; 811 + 812 + /* all we have room for? */ 813 + if (used >= budget) 814 + return used; 815 + } 816 + } 817 + 818 + return used; 819 + } 820 + 821 + static int icssm_emac_napi_poll(struct napi_struct *napi, int budget) 822 + { 823 + struct prueth_emac *emac = container_of(napi, struct prueth_emac, napi); 824 + int num_rx; 825 + 826 + num_rx = icssm_emac_rx_packets(emac, budget); 827 + 828 + if (num_rx < budget && napi_complete_done(napi, num_rx)) 829 + enable_irq(emac->rx_irq); 830 + 831 + return num_rx; 832 + } 833 + 834 + static int icssm_emac_set_boot_pru(struct prueth_emac *emac, 835 + struct net_device *ndev) 836 + { 837 + const struct prueth_firmware *pru_firmwares; 838 + struct prueth *prueth = emac->prueth; 839 + const char *fw_name; 840 + int ret; 841 + 842 + pru_firmwares = &prueth->fw_data->fw_pru[emac->port_id - 1]; 843 + fw_name = pru_firmwares->fw_name[prueth->eth_type]; 844 + if (!fw_name) { 845 + netdev_err(ndev, "eth_type %d not supported\n", 846 + prueth->eth_type); 847 + return -ENODEV; 848 + } 849 + 850 + ret = rproc_set_firmware(emac->pru, fw_name); 851 + if (ret) { 852 + netdev_err(ndev, "failed to set %s firmware: %d\n", 853 + fw_name, ret); 854 + return ret; 855 + } 856 + 857 + ret = rproc_boot(emac->pru); 858 + if (ret) { 859 + netdev_err(ndev, "failed to boot %s firmware: %d\n", 860 + fw_name, ret); 861 + return ret; 862 + } 863 + return ret; 864 + } 865 + 866 + static int icssm_emac_request_irqs(struct prueth_emac *emac) 867 + { 868 + struct net_device *ndev = emac->ndev; 869 + int ret; 870 + 871 + ret = request_irq(emac->rx_irq, icssm_emac_rx_irq, 872 + IRQF_TRIGGER_HIGH, 873 + ndev->name, ndev); 874 + if (ret) { 875 + netdev_err(ndev, "unable to request RX IRQ\n"); 876 + return ret; 877 + } 878 + 879 + return ret; 880 + } 881 + 882 + static void icssm_ptp_dram_init(struct prueth_emac *emac) 883 + { 884 + void __iomem *sram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va; 885 + u64 temp64; 886 + 887 + writew(0, sram + MII_RX_CORRECTION_OFFSET); 888 + writew(0, sram + MII_TX_CORRECTION_OFFSET); 889 + 890 + /* Initialize RCF to 1 (Linux N/A) */ 891 + writel(1 * 1024, sram + TIMESYNC_TC_RCF_OFFSET); 892 + 893 + /* This flag will be set and cleared by firmware */ 894 + /* Write Sync0 period for sync signal generation in PTP 895 + * memory in shared RAM 896 + */ 897 + writel(200000000 / 50, sram + TIMESYNC_SYNC0_WIDTH_OFFSET); 898 + 899 + /* Write CMP1 period for sync signal generation in PTP 900 + * memory in shared RAM 901 + */ 902 + temp64 = 1000000; 903 + memcpy_toio(sram + TIMESYNC_CMP1_CMP_OFFSET, &temp64, sizeof(temp64)); 904 + 905 + /* Write Sync0 period for sync signal generation in PTP 906 + * memory in shared RAM 907 + */ 908 + writel(1000000, sram + TIMESYNC_CMP1_PERIOD_OFFSET); 909 + 910 + /* Configures domainNumber list. Firmware supports 2 domains */ 911 + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST); 912 + writeb(0, sram + TIMESYNC_DOMAIN_NUMBER_LIST + 1); 913 + 914 + /* Configure 1-step/2-step */ 915 + writeb(1, sram + DISABLE_SWITCH_SYNC_RELAY_OFFSET); 916 + 917 + /* Configures the setting to Link local frame without HSR tag */ 918 + writeb(0, sram + LINK_LOCAL_FRAME_HAS_HSR_TAG); 919 + 920 + /* Enable E2E/UDP PTP message timestamping */ 921 + writeb(1, sram + PTP_IPV4_UDP_E2E_ENABLE); 922 + } 923 + 924 + /** 925 + * icssm_emac_ndo_open - EMAC device open 926 + * @ndev: network adapter device 927 + * 928 + * Called when system wants to start the interface. 929 + * 930 + * Return: 0 for a successful open, or appropriate error code 931 + */ 932 + static int icssm_emac_ndo_open(struct net_device *ndev) 933 + { 934 + struct prueth_emac *emac = netdev_priv(ndev); 935 + struct prueth *prueth = emac->prueth; 936 + int ret; 937 + 938 + /* set h/w MAC as user might have re-configured */ 939 + ether_addr_copy(emac->mac_addr, ndev->dev_addr); 940 + 941 + if (!prueth->emac_configured) 942 + icssm_prueth_init_ethernet_mode(prueth); 943 + 944 + icssm_prueth_emac_config(emac); 945 + 946 + if (!prueth->emac_configured) { 947 + icssm_ptp_dram_init(emac); 948 + ret = icss_iep_init(prueth->iep, NULL, NULL, 0); 949 + if (ret) { 950 + netdev_err(ndev, "Failed to initialize iep: %d\n", ret); 951 + goto iep_exit; 952 + } 953 + } 954 + 955 + ret = icssm_emac_set_boot_pru(emac, ndev); 956 + if (ret) 957 + goto iep_exit; 958 + 959 + ret = icssm_emac_request_irqs(emac); 960 + if (ret) 961 + goto rproc_shutdown; 962 + 963 + napi_enable(&emac->napi); 964 + 965 + /* start PHY */ 966 + phy_start(emac->phydev); 967 + 968 + /* enable the port and vlan */ 969 + icssm_prueth_port_enable(emac, true); 970 + 971 + prueth->emac_configured |= BIT(emac->port_id); 972 + 973 + if (netif_msg_drv(emac)) 974 + dev_notice(&ndev->dev, "started\n"); 975 + 976 + return 0; 977 + 978 + rproc_shutdown: 979 + rproc_shutdown(emac->pru); 980 + 981 + iep_exit: 982 + if (!prueth->emac_configured) 983 + icss_iep_exit(prueth->iep); 984 + 985 + return ret; 986 + } 987 + 988 + /** 989 + * icssm_emac_ndo_stop - EMAC device stop 990 + * @ndev: network adapter device 991 + * 992 + * Called when system wants to stop or down the interface. 993 + * 994 + * Return: Always 0 (Success) 995 + */ 996 + static int icssm_emac_ndo_stop(struct net_device *ndev) 997 + { 998 + struct prueth_emac *emac = netdev_priv(ndev); 999 + struct prueth *prueth = emac->prueth; 1000 + 1001 + prueth->emac_configured &= ~BIT(emac->port_id); 1002 + 1003 + /* disable the mac port */ 1004 + icssm_prueth_port_enable(emac, false); 1005 + 1006 + /* stop PHY */ 1007 + phy_stop(emac->phydev); 1008 + 1009 + napi_disable(&emac->napi); 1010 + hrtimer_cancel(&emac->tx_hrtimer); 1011 + 1012 + /* stop the PRU */ 1013 + rproc_shutdown(emac->pru); 1014 + 1015 + /* free rx interrupts */ 1016 + free_irq(emac->rx_irq, ndev); 1017 + 1018 + if (netif_msg_drv(emac)) 1019 + dev_notice(&ndev->dev, "stopped\n"); 1020 + 1021 + return 0; 1022 + } 1023 + 1024 + /* VLAN-tag PCP to priority queue map for EMAC/Switch/HSR/PRP used by driver 1025 + * Index is PCP val / 2. 1026 + * low - pcp 0..3 maps to Q4 for Host 1027 + * high - pcp 4..7 maps to Q3 for Host 1028 + * low - pcp 0..3 maps to Q2 (FWD Queue) for PRU-x 1029 + * where x = 1 for PRUETH_PORT_MII0 1030 + * 0 for PRUETH_PORT_MII1 1031 + * high - pcp 4..7 maps to Q1 (FWD Queue) for PRU-x 1032 + */ 1033 + static const unsigned short emac_pcp_tx_priority_queue_map[] = { 1034 + PRUETH_QUEUE4, PRUETH_QUEUE4, 1035 + PRUETH_QUEUE3, PRUETH_QUEUE3, 1036 + PRUETH_QUEUE2, PRUETH_QUEUE2, 1037 + PRUETH_QUEUE1, PRUETH_QUEUE1, 1038 + }; 1039 + 1040 + static u16 icssm_prueth_get_tx_queue_id(struct prueth *prueth, 1041 + struct sk_buff *skb) 1042 + { 1043 + u16 vlan_tci, pcp; 1044 + int err; 1045 + 1046 + err = vlan_get_tag(skb, &vlan_tci); 1047 + if (likely(err)) 1048 + pcp = 0; 1049 + else 1050 + pcp = (vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 1051 + 1052 + /* Below code (pcp >>= 1) is made common for all 1053 + * protocols (i.e., EMAC, RSTP, HSR and PRP)* 1054 + * pcp value 0,1 will be updated to 0 mapped to QUEUE4 1055 + * pcp value 2,3 will be updated to 1 mapped to QUEUE4 1056 + * pcp value 4,5 will be updated to 2 mapped to QUEUE3 1057 + * pcp value 6,7 will be updated to 3 mapped to QUEUE3 1058 + */ 1059 + pcp >>= 1; 1060 + 1061 + return emac_pcp_tx_priority_queue_map[pcp]; 1062 + } 1063 + 1064 + /** 1065 + * icssm_emac_ndo_start_xmit - EMAC Transmit function 1066 + * @skb: SKB pointer 1067 + * @ndev: EMAC network adapter 1068 + * 1069 + * Called by the system to transmit a packet - we queue the packet in 1070 + * EMAC hardware transmit queue 1071 + * 1072 + * Return: enum netdev_tx 1073 + */ 1074 + static enum netdev_tx icssm_emac_ndo_start_xmit(struct sk_buff *skb, 1075 + struct net_device *ndev) 1076 + { 1077 + struct prueth_emac *emac = netdev_priv(ndev); 1078 + int ret; 1079 + u16 qid; 1080 + 1081 + qid = icssm_prueth_get_tx_queue_id(emac->prueth, skb); 1082 + ret = icssm_prueth_tx_enqueue(emac, skb, qid); 1083 + if (ret) { 1084 + if (ret != -ENOBUFS && netif_msg_tx_err(emac) && 1085 + net_ratelimit()) 1086 + netdev_err(ndev, "packet queue failed: %d\n", ret); 1087 + goto fail_tx; 1088 + } 1089 + 1090 + emac->stats.tx_packets++; 1091 + emac->stats.tx_bytes += skb->len; 1092 + dev_kfree_skb_any(skb); 1093 + 1094 + return NETDEV_TX_OK; 1095 + 1096 + fail_tx: 1097 + if (ret == -ENOBUFS) { 1098 + netif_stop_queue(ndev); 1099 + hrtimer_start(&emac->tx_hrtimer, 1100 + us_to_ktime(HR_TIMER_TX_DELAY_US), 1101 + HRTIMER_MODE_REL_PINNED); 1102 + ret = NETDEV_TX_BUSY; 1103 + } else { 1104 + /* error */ 1105 + emac->stats.tx_dropped++; 1106 + ret = NET_XMIT_DROP; 1107 + } 1108 + 1109 + return ret; 1110 + } 1111 + 1112 + /** 1113 + * icssm_emac_ndo_get_stats64 - EMAC get statistics function 1114 + * @ndev: The EMAC network adapter 1115 + * @stats: rtnl_link_stats structure 1116 + * 1117 + * Called when system wants to get statistics from the device. 1118 + * 1119 + */ 1120 + static void icssm_emac_ndo_get_stats64(struct net_device *ndev, 1121 + struct rtnl_link_stats64 *stats) 1122 + { 1123 + struct prueth_emac *emac = netdev_priv(ndev); 1124 + 1125 + stats->rx_packets = emac->stats.rx_packets; 1126 + stats->rx_bytes = emac->stats.rx_bytes; 1127 + stats->tx_packets = emac->stats.tx_packets; 1128 + stats->tx_bytes = emac->stats.tx_bytes; 1129 + stats->tx_dropped = emac->stats.tx_dropped; 1130 + stats->rx_over_errors = emac->stats.rx_over_errors; 1131 + stats->rx_length_errors = emac->stats.rx_length_errors; 1132 + } 1133 + 1134 + static const struct net_device_ops emac_netdev_ops = { 1135 + .ndo_open = icssm_emac_ndo_open, 1136 + .ndo_stop = icssm_emac_ndo_stop, 1137 + .ndo_start_xmit = icssm_emac_ndo_start_xmit, 1138 + .ndo_get_stats64 = icssm_emac_ndo_get_stats64, 1139 + }; 1140 + 1141 + /* get emac_port corresponding to eth_node name */ 1142 + static int icssm_prueth_node_port(struct device_node *eth_node) 1143 + { 1144 + u32 port_id; 1145 + int ret; 1146 + 1147 + ret = of_property_read_u32(eth_node, "reg", &port_id); 1148 + if (ret) 1149 + return ret; 1150 + 1151 + if (port_id == 0) 1152 + return PRUETH_PORT_MII0; 1153 + else if (port_id == 1) 1154 + return PRUETH_PORT_MII1; 1155 + else 1156 + return PRUETH_PORT_INVALID; 1157 + } 1158 + 1159 + /* get MAC instance corresponding to eth_node name */ 1160 + static int icssm_prueth_node_mac(struct device_node *eth_node) 1161 + { 1162 + u32 port_id; 1163 + int ret; 1164 + 1165 + ret = of_property_read_u32(eth_node, "reg", &port_id); 1166 + if (ret) 1167 + return ret; 1168 + 1169 + if (port_id == 0) 1170 + return PRUETH_MAC0; 1171 + else if (port_id == 1) 1172 + return PRUETH_MAC1; 1173 + else 1174 + return PRUETH_MAC_INVALID; 1175 + } 1176 + 1177 + static enum hrtimer_restart icssm_emac_tx_timer_callback(struct hrtimer *timer) 1178 + { 1179 + struct prueth_emac *emac = 1180 + container_of(timer, struct prueth_emac, tx_hrtimer); 1181 + 1182 + if (netif_queue_stopped(emac->ndev)) 1183 + netif_wake_queue(emac->ndev); 1184 + 1185 + return HRTIMER_NORESTART; 1186 + } 1187 + 1188 + static int icssm_prueth_netdev_init(struct prueth *prueth, 1189 + struct device_node *eth_node) 1190 + { 1191 + struct prueth_emac *emac; 1192 + struct net_device *ndev; 1193 + enum prueth_port port; 1194 + enum prueth_mac mac; 1195 + int ret; 1196 + 1197 + port = icssm_prueth_node_port(eth_node); 1198 + if (port == PRUETH_PORT_INVALID) 1199 + return -EINVAL; 1200 + 1201 + mac = icssm_prueth_node_mac(eth_node); 1202 + if (mac == PRUETH_MAC_INVALID) 1203 + return -EINVAL; 1204 + 1205 + ndev = devm_alloc_etherdev(prueth->dev, sizeof(*emac)); 1206 + if (!ndev) 1207 + return -ENOMEM; 1208 + 1209 + SET_NETDEV_DEV(ndev, prueth->dev); 1210 + emac = netdev_priv(ndev); 1211 + prueth->emac[mac] = emac; 1212 + emac->prueth = prueth; 1213 + emac->ndev = ndev; 1214 + emac->port_id = port; 1215 + 1216 + /* by default eth_type is EMAC */ 1217 + switch (port) { 1218 + case PRUETH_PORT_MII0: 1219 + emac->tx_port_queue = PRUETH_PORT_QUEUE_MII0; 1220 + 1221 + /* packets from MII0 are on queues 1 through 2 */ 1222 + emac->rx_queue_start = PRUETH_QUEUE1; 1223 + emac->rx_queue_end = PRUETH_QUEUE2; 1224 + 1225 + emac->dram = PRUETH_MEM_DRAM0; 1226 + emac->pru = prueth->pru0; 1227 + break; 1228 + case PRUETH_PORT_MII1: 1229 + emac->tx_port_queue = PRUETH_PORT_QUEUE_MII1; 1230 + 1231 + /* packets from MII1 are on queues 3 through 4 */ 1232 + emac->rx_queue_start = PRUETH_QUEUE3; 1233 + emac->rx_queue_end = PRUETH_QUEUE4; 1234 + 1235 + emac->dram = PRUETH_MEM_DRAM1; 1236 + emac->pru = prueth->pru1; 1237 + break; 1238 + default: 1239 + return -EINVAL; 1240 + } 1241 + 1242 + emac->rx_irq = of_irq_get_byname(eth_node, "rx"); 1243 + if (emac->rx_irq < 0) { 1244 + ret = emac->rx_irq; 1245 + if (ret != -EPROBE_DEFER) 1246 + dev_err(prueth->dev, "could not get rx irq\n"); 1247 + goto free; 1248 + } 1249 + 1250 + /* get mac address from DT and set private and netdev addr */ 1251 + ret = of_get_ethdev_address(eth_node, ndev); 1252 + if (!is_valid_ether_addr(ndev->dev_addr)) { 1253 + eth_hw_addr_random(ndev); 1254 + dev_warn(prueth->dev, "port %d: using random MAC addr: %pM\n", 1255 + port, ndev->dev_addr); 1256 + } 1257 + ether_addr_copy(emac->mac_addr, ndev->dev_addr); 1258 + 1259 + /* connect PHY */ 1260 + emac->phydev = of_phy_get_and_connect(ndev, eth_node, 1261 + icssm_emac_adjust_link); 1262 + if (!emac->phydev) { 1263 + dev_dbg(prueth->dev, "PHY connection failed\n"); 1264 + ret = -ENODEV; 1265 + goto free; 1266 + } 1267 + 1268 + /* remove unsupported modes */ 1269 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); 1270 + 1271 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); 1272 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); 1273 + 1274 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Pause_BIT); 1275 + phy_remove_link_mode(emac->phydev, ETHTOOL_LINK_MODE_Asym_Pause_BIT); 1276 + 1277 + ndev->dev.of_node = eth_node; 1278 + ndev->netdev_ops = &emac_netdev_ops; 1279 + 1280 + netif_napi_add(ndev, &emac->napi, icssm_emac_napi_poll); 1281 + 1282 + hrtimer_setup(&emac->tx_hrtimer, &icssm_emac_tx_timer_callback, 1283 + CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); 1284 + 1285 + return 0; 1286 + free: 1287 + emac->ndev = NULL; 1288 + prueth->emac[mac] = NULL; 1289 + 1290 + return ret; 1291 + } 1292 + 1293 + static void icssm_prueth_netdev_exit(struct prueth *prueth, 1294 + struct device_node *eth_node) 1295 + { 1296 + struct prueth_emac *emac; 1297 + enum prueth_mac mac; 1298 + 1299 + mac = icssm_prueth_node_mac(eth_node); 1300 + if (mac == PRUETH_MAC_INVALID) 1301 + return; 1302 + 1303 + emac = prueth->emac[mac]; 1304 + if (!emac) 1305 + return; 1306 + 1307 + phy_disconnect(emac->phydev); 1308 + 1309 + netif_napi_del(&emac->napi); 1310 + prueth->emac[mac] = NULL; 1311 + } 1312 + 1313 + static int icssm_prueth_probe(struct platform_device *pdev) 1314 + { 1315 + struct device_node *eth0_node = NULL, *eth1_node = NULL; 1316 + struct device_node *eth_node, *eth_ports_node; 1317 + enum pruss_pru_id pruss_id0, pruss_id1; 1318 + struct device *dev = &pdev->dev; 1319 + struct device_node *np; 1320 + struct prueth *prueth; 1321 + struct pruss *pruss; 1322 + int i, ret; 1323 + 1324 + np = dev->of_node; 1325 + if (!np) 1326 + return -ENODEV; /* we don't support non DT */ 1327 + 1328 + prueth = devm_kzalloc(dev, sizeof(*prueth), GFP_KERNEL); 1329 + if (!prueth) 1330 + return -ENOMEM; 1331 + 1332 + platform_set_drvdata(pdev, prueth); 1333 + prueth->dev = dev; 1334 + prueth->fw_data = device_get_match_data(dev); 1335 + 1336 + eth_ports_node = of_get_child_by_name(np, "ethernet-ports"); 1337 + if (!eth_ports_node) 1338 + return -ENOENT; 1339 + 1340 + for_each_child_of_node(eth_ports_node, eth_node) { 1341 + u32 reg; 1342 + 1343 + if (strcmp(eth_node->name, "ethernet-port")) 1344 + continue; 1345 + ret = of_property_read_u32(eth_node, "reg", &reg); 1346 + if (ret < 0) { 1347 + dev_err(dev, "%pOF error reading port_id %d\n", 1348 + eth_node, ret); 1349 + of_node_put(eth_node); 1350 + return ret; 1351 + } 1352 + 1353 + of_node_get(eth_node); 1354 + 1355 + if (reg == 0 && !eth0_node) { 1356 + eth0_node = eth_node; 1357 + if (!of_device_is_available(eth0_node)) { 1358 + of_node_put(eth0_node); 1359 + eth0_node = NULL; 1360 + } 1361 + } else if (reg == 1 && !eth1_node) { 1362 + eth1_node = eth_node; 1363 + if (!of_device_is_available(eth1_node)) { 1364 + of_node_put(eth1_node); 1365 + eth1_node = NULL; 1366 + } 1367 + } else { 1368 + if (reg == 0 || reg == 1) 1369 + dev_err(dev, "duplicate port reg value: %d\n", 1370 + reg); 1371 + else 1372 + dev_err(dev, "invalid port reg value: %d\n", 1373 + reg); 1374 + 1375 + of_node_put(eth_node); 1376 + } 1377 + } 1378 + 1379 + of_node_put(eth_ports_node); 1380 + 1381 + /* At least one node must be present and available else we fail */ 1382 + if (!eth0_node && !eth1_node) { 1383 + dev_err(dev, "neither port0 nor port1 node available\n"); 1384 + return -ENODEV; 1385 + } 1386 + 1387 + prueth->eth_node[PRUETH_MAC0] = eth0_node; 1388 + prueth->eth_node[PRUETH_MAC1] = eth1_node; 1389 + 1390 + prueth->mii_rt = syscon_regmap_lookup_by_phandle(np, "ti,mii-rt"); 1391 + if (IS_ERR(prueth->mii_rt)) { 1392 + dev_err(dev, "couldn't get mii-rt syscon regmap\n"); 1393 + return -ENODEV; 1394 + } 1395 + 1396 + if (eth0_node) { 1397 + prueth->pru0 = pru_rproc_get(np, 0, &pruss_id0); 1398 + if (IS_ERR(prueth->pru0)) { 1399 + ret = PTR_ERR(prueth->pru0); 1400 + dev_err_probe(dev, ret, "unable to get PRU0"); 1401 + goto put_pru; 1402 + } 1403 + } 1404 + 1405 + if (eth1_node) { 1406 + prueth->pru1 = pru_rproc_get(np, 1, &pruss_id1); 1407 + if (IS_ERR(prueth->pru1)) { 1408 + ret = PTR_ERR(prueth->pru1); 1409 + dev_err_probe(dev, ret, "unable to get PRU1"); 1410 + goto put_pru; 1411 + } 1412 + } 1413 + 1414 + pruss = pruss_get(prueth->pru0 ? prueth->pru0 : prueth->pru1); 1415 + if (IS_ERR(pruss)) { 1416 + ret = PTR_ERR(pruss); 1417 + dev_err(dev, "unable to get pruss handle\n"); 1418 + goto put_pru; 1419 + } 1420 + prueth->pruss = pruss; 1421 + 1422 + /* Configure PRUSS */ 1423 + if (eth0_node) 1424 + pruss_cfg_gpimode(pruss, pruss_id0, PRUSS_GPI_MODE_MII); 1425 + if (eth1_node) 1426 + pruss_cfg_gpimode(pruss, pruss_id1, PRUSS_GPI_MODE_MII); 1427 + pruss_cfg_miirt_enable(pruss, true); 1428 + pruss_cfg_xfr_enable(pruss, PRU_TYPE_PRU, true); 1429 + 1430 + /* Get PRUSS mem resources */ 1431 + /* OCMC is system resource which we get separately */ 1432 + for (i = 0; i < ARRAY_SIZE(pruss_mem_ids); i++) { 1433 + /* skip appropriate DRAM if not required */ 1434 + if (!eth0_node && i == PRUETH_MEM_DRAM0) 1435 + continue; 1436 + 1437 + if (!eth1_node && i == PRUETH_MEM_DRAM1) 1438 + continue; 1439 + 1440 + ret = pruss_request_mem_region(pruss, pruss_mem_ids[i], 1441 + &prueth->mem[i]); 1442 + if (ret) { 1443 + dev_err(dev, "unable to get PRUSS resource %d: %d\n", 1444 + i, ret); 1445 + goto put_mem; 1446 + } 1447 + } 1448 + 1449 + prueth->sram_pool = of_gen_pool_get(np, "sram", 0); 1450 + if (!prueth->sram_pool) { 1451 + dev_err(dev, "unable to get SRAM pool\n"); 1452 + ret = -ENODEV; 1453 + goto put_mem; 1454 + } 1455 + 1456 + prueth->ocmc_ram_size = OCMC_RAM_SIZE; 1457 + /* Decreased by 8KB to address the reserved region for AM33x */ 1458 + if (prueth->fw_data->driver_data == PRUSS_AM33XX) 1459 + prueth->ocmc_ram_size = (SZ_64K - SZ_8K); 1460 + 1461 + prueth->mem[PRUETH_MEM_OCMC].va = 1462 + (void __iomem *)gen_pool_alloc(prueth->sram_pool, 1463 + prueth->ocmc_ram_size); 1464 + if (!prueth->mem[PRUETH_MEM_OCMC].va) { 1465 + dev_err(dev, "unable to allocate OCMC resource\n"); 1466 + ret = -ENOMEM; 1467 + goto put_mem; 1468 + } 1469 + prueth->mem[PRUETH_MEM_OCMC].pa = gen_pool_virt_to_phys 1470 + (prueth->sram_pool, (unsigned long) 1471 + prueth->mem[PRUETH_MEM_OCMC].va); 1472 + prueth->mem[PRUETH_MEM_OCMC].size = prueth->ocmc_ram_size; 1473 + dev_dbg(dev, "ocmc: pa %pa va %p size %#zx\n", 1474 + &prueth->mem[PRUETH_MEM_OCMC].pa, 1475 + prueth->mem[PRUETH_MEM_OCMC].va, 1476 + prueth->mem[PRUETH_MEM_OCMC].size); 1477 + 1478 + /* setup netdev interfaces */ 1479 + if (eth0_node) { 1480 + ret = icssm_prueth_netdev_init(prueth, eth0_node); 1481 + if (ret) { 1482 + if (ret != -EPROBE_DEFER) { 1483 + dev_err(dev, "netdev init %s failed: %d\n", 1484 + eth0_node->name, ret); 1485 + } 1486 + goto free_pool; 1487 + } 1488 + } 1489 + 1490 + if (eth1_node) { 1491 + ret = icssm_prueth_netdev_init(prueth, eth1_node); 1492 + if (ret) { 1493 + if (ret != -EPROBE_DEFER) { 1494 + dev_err(dev, "netdev init %s failed: %d\n", 1495 + eth1_node->name, ret); 1496 + } 1497 + goto netdev_exit; 1498 + } 1499 + } 1500 + 1501 + prueth->iep = icss_iep_get(np); 1502 + if (IS_ERR(prueth->iep)) { 1503 + ret = PTR_ERR(prueth->iep); 1504 + dev_err(dev, "unable to get IEP\n"); 1505 + goto netdev_exit; 1506 + } 1507 + 1508 + /* register the network devices */ 1509 + if (eth0_node) { 1510 + ret = register_netdev(prueth->emac[PRUETH_MAC0]->ndev); 1511 + if (ret) { 1512 + dev_err(dev, "can't register netdev for port MII0"); 1513 + goto iep_put; 1514 + } 1515 + 1516 + prueth->registered_netdevs[PRUETH_MAC0] = 1517 + prueth->emac[PRUETH_MAC0]->ndev; 1518 + } 1519 + 1520 + if (eth1_node) { 1521 + ret = register_netdev(prueth->emac[PRUETH_MAC1]->ndev); 1522 + if (ret) { 1523 + dev_err(dev, "can't register netdev for port MII1"); 1524 + goto netdev_unregister; 1525 + } 1526 + 1527 + prueth->registered_netdevs[PRUETH_MAC1] = 1528 + prueth->emac[PRUETH_MAC1]->ndev; 1529 + } 1530 + 1531 + dev_info(dev, "TI PRU ethernet driver initialized: %s EMAC mode\n", 1532 + (!eth0_node || !eth1_node) ? "single" : "dual"); 1533 + 1534 + if (eth1_node) 1535 + of_node_put(eth1_node); 1536 + if (eth0_node) 1537 + of_node_put(eth0_node); 1538 + return 0; 1539 + 1540 + netdev_unregister: 1541 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1542 + if (!prueth->registered_netdevs[i]) 1543 + continue; 1544 + unregister_netdev(prueth->registered_netdevs[i]); 1545 + } 1546 + 1547 + iep_put: 1548 + icss_iep_put(prueth->iep); 1549 + prueth->iep = NULL; 1550 + 1551 + netdev_exit: 1552 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1553 + eth_node = prueth->eth_node[i]; 1554 + if (!eth_node) 1555 + continue; 1556 + 1557 + icssm_prueth_netdev_exit(prueth, eth_node); 1558 + } 1559 + 1560 + free_pool: 1561 + gen_pool_free(prueth->sram_pool, 1562 + (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, 1563 + prueth->ocmc_ram_size); 1564 + 1565 + put_mem: 1566 + for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { 1567 + if (prueth->mem[i].va) 1568 + pruss_release_mem_region(pruss, &prueth->mem[i]); 1569 + } 1570 + pruss_put(prueth->pruss); 1571 + 1572 + put_pru: 1573 + if (eth1_node) { 1574 + if (prueth->pru1) 1575 + pru_rproc_put(prueth->pru1); 1576 + of_node_put(eth1_node); 1577 + } 1578 + 1579 + if (eth0_node) { 1580 + if (prueth->pru0) 1581 + pru_rproc_put(prueth->pru0); 1582 + of_node_put(eth0_node); 1583 + } 1584 + 1585 + return ret; 1586 + } 1587 + 1588 + static void icssm_prueth_remove(struct platform_device *pdev) 1589 + { 1590 + struct prueth *prueth = platform_get_drvdata(pdev); 1591 + struct device_node *eth_node; 1592 + int i; 1593 + 1594 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1595 + if (!prueth->registered_netdevs[i]) 1596 + continue; 1597 + unregister_netdev(prueth->registered_netdevs[i]); 1598 + } 1599 + 1600 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1601 + eth_node = prueth->eth_node[i]; 1602 + if (!eth_node) 1603 + continue; 1604 + 1605 + icssm_prueth_netdev_exit(prueth, eth_node); 1606 + of_node_put(eth_node); 1607 + } 1608 + 1609 + gen_pool_free(prueth->sram_pool, 1610 + (unsigned long)prueth->mem[PRUETH_MEM_OCMC].va, 1611 + prueth->ocmc_ram_size); 1612 + 1613 + for (i = PRUETH_MEM_DRAM0; i < PRUETH_MEM_OCMC; i++) { 1614 + if (prueth->mem[i].va) 1615 + pruss_release_mem_region(prueth->pruss, 1616 + &prueth->mem[i]); 1617 + } 1618 + 1619 + icss_iep_put(prueth->iep); 1620 + prueth->iep = NULL; 1621 + 1622 + pruss_put(prueth->pruss); 1623 + 1624 + if (prueth->eth_node[PRUETH_MAC0]) 1625 + pru_rproc_put(prueth->pru0); 1626 + if (prueth->eth_node[PRUETH_MAC1]) 1627 + pru_rproc_put(prueth->pru1); 1628 + } 1629 + 1630 + #ifdef CONFIG_PM_SLEEP 1631 + static int icssm_prueth_suspend(struct device *dev) 1632 + { 1633 + struct prueth *prueth = dev_get_drvdata(dev); 1634 + struct net_device *ndev; 1635 + int i, ret; 1636 + 1637 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1638 + ndev = prueth->registered_netdevs[i]; 1639 + 1640 + if (!ndev) 1641 + continue; 1642 + 1643 + if (netif_running(ndev)) { 1644 + netif_device_detach(ndev); 1645 + ret = icssm_emac_ndo_stop(ndev); 1646 + if (ret < 0) { 1647 + netdev_err(ndev, "failed to stop: %d", ret); 1648 + return ret; 1649 + } 1650 + } 1651 + } 1652 + 1653 + return 0; 1654 + } 1655 + 1656 + static int icssm_prueth_resume(struct device *dev) 1657 + { 1658 + struct prueth *prueth = dev_get_drvdata(dev); 1659 + struct net_device *ndev; 1660 + int i, ret; 1661 + 1662 + for (i = 0; i < PRUETH_NUM_MACS; i++) { 1663 + ndev = prueth->registered_netdevs[i]; 1664 + 1665 + if (!ndev) 1666 + continue; 1667 + 1668 + if (netif_running(ndev)) { 1669 + ret = icssm_emac_ndo_open(ndev); 1670 + if (ret < 0) { 1671 + netdev_err(ndev, "failed to start: %d", ret); 1672 + return ret; 1673 + } 1674 + netif_device_attach(ndev); 1675 + } 1676 + } 1677 + 1678 + return 0; 1679 + } 1680 + 1681 + #endif /* CONFIG_PM_SLEEP */ 1682 + 1683 + static const struct dev_pm_ops prueth_dev_pm_ops = { 1684 + SET_SYSTEM_SLEEP_PM_OPS(icssm_prueth_suspend, icssm_prueth_resume) 1685 + }; 1686 + 1687 + /* AM335x SoC-specific firmware data */ 1688 + static struct prueth_private_data am335x_prueth_pdata = { 1689 + .driver_data = PRUSS_AM33XX, 1690 + .fw_pru[PRUSS_PRU0] = { 1691 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1692 + "ti-pruss/am335x-pru0-prueth-fw.elf", 1693 + }, 1694 + .fw_pru[PRUSS_PRU1] = { 1695 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1696 + "ti-pruss/am335x-pru1-prueth-fw.elf", 1697 + }, 1698 + }; 1699 + 1700 + /* AM437x SoC-specific firmware data */ 1701 + static struct prueth_private_data am437x_prueth_pdata = { 1702 + .driver_data = PRUSS_AM43XX, 1703 + .fw_pru[PRUSS_PRU0] = { 1704 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1705 + "ti-pruss/am437x-pru0-prueth-fw.elf", 1706 + }, 1707 + .fw_pru[PRUSS_PRU1] = { 1708 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1709 + "ti-pruss/am437x-pru1-prueth-fw.elf", 1710 + }, 1711 + }; 1712 + 1713 + /* AM57xx SoC-specific firmware data */ 1714 + static struct prueth_private_data am57xx_prueth_pdata = { 1715 + .driver_data = PRUSS_AM57XX, 1716 + .fw_pru[PRUSS_PRU0] = { 1717 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1718 + "ti-pruss/am57xx-pru0-prueth-fw.elf", 1719 + }, 1720 + .fw_pru[PRUSS_PRU1] = { 1721 + .fw_name[PRUSS_ETHTYPE_EMAC] = 1722 + "ti-pruss/am57xx-pru1-prueth-fw.elf", 1723 + }, 1724 + }; 1725 + 1726 + static const struct of_device_id prueth_dt_match[] = { 1727 + { .compatible = "ti,am57-prueth", .data = &am57xx_prueth_pdata, }, 1728 + { .compatible = "ti,am4376-prueth", .data = &am437x_prueth_pdata, }, 1729 + { .compatible = "ti,am3359-prueth", .data = &am335x_prueth_pdata, }, 1730 + { /* sentinel */ } 1731 + }; 1732 + MODULE_DEVICE_TABLE(of, prueth_dt_match); 1733 + 1734 + static struct platform_driver prueth_driver = { 1735 + .probe = icssm_prueth_probe, 1736 + .remove = icssm_prueth_remove, 1737 + .driver = { 1738 + .name = "prueth", 1739 + .of_match_table = prueth_dt_match, 1740 + .pm = &prueth_dev_pm_ops, 1741 + }, 1742 + }; 1743 + module_platform_driver(prueth_driver); 1744 + 1745 + MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); 1746 + MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 1747 + MODULE_DESCRIPTION("PRUSS ICSSM Ethernet Driver"); 1748 + MODULE_LICENSE("GPL");
+262
drivers/net/ethernet/ti/icssm/icssm_prueth.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Texas Instruments ICSSM Ethernet driver 3 + * 4 + * Copyright (C) 2018-2022 Texas Instruments Incorporated - https://www.ti.com/ 5 + * 6 + */ 7 + 8 + #ifndef __NET_TI_PRUETH_H 9 + #define __NET_TI_PRUETH_H 10 + 11 + #include <linux/phy.h> 12 + #include <linux/types.h> 13 + #include <linux/pruss_driver.h> 14 + #include <linux/remoteproc/pruss.h> 15 + 16 + #include "icssm_switch.h" 17 + #include "icssm_prueth_ptp.h" 18 + 19 + /* ICSSM size of redundancy tag */ 20 + #define ICSSM_LRE_TAG_SIZE 6 21 + 22 + /* PRUSS local memory map */ 23 + #define ICSS_LOCAL_SHARED_RAM 0x00010000 24 + #define EMAC_MAX_PKTLEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) 25 + /* Below macro is for 1528 Byte Frame support, to Allow even with 26 + * Redundancy tag 27 + */ 28 + #define EMAC_MAX_FRM_SUPPORT (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN + \ 29 + ICSSM_LRE_TAG_SIZE) 30 + 31 + /* PRU Ethernet Type - Ethernet functionality (protocol 32 + * implemented) provided by the PRU firmware being loaded. 33 + */ 34 + enum pruss_ethtype { 35 + PRUSS_ETHTYPE_EMAC = 0, 36 + PRUSS_ETHTYPE_HSR, 37 + PRUSS_ETHTYPE_PRP, 38 + PRUSS_ETHTYPE_SWITCH, 39 + PRUSS_ETHTYPE_MAX, 40 + }; 41 + 42 + #define PRUETH_IS_EMAC(p) ((p)->eth_type == PRUSS_ETHTYPE_EMAC) 43 + #define PRUETH_IS_SWITCH(p) ((p)->eth_type == PRUSS_ETHTYPE_SWITCH) 44 + 45 + /** 46 + * struct prueth_queue_desc - Queue descriptor 47 + * @rd_ptr: Read pointer, points to a buffer descriptor in Shared PRU RAM. 48 + * @wr_ptr: Write pointer, points to a buffer descriptor in Shared PRU RAM. 49 + * @busy_s: Slave queue busy flag, set by slave(us) to request access from 50 + * master(PRU). 51 + * @status: Bit field status register, Bits: 52 + * 0: Master queue busy flag. 53 + * 1: Packet has been placed in collision queue. 54 + * 2: Packet has been discarded due to overflow. 55 + * @max_fill_level: Maximum queue usage seen. 56 + * @overflow_cnt: Count of queue overflows. 57 + * 58 + * Each port has up to 4 queues with variable length. The queue is processed 59 + * as ring buffer with read and write pointers. Both pointers are address 60 + * pointers and increment by 4 for each buffer descriptor position. Queue has 61 + * a length defined in constants and a status. 62 + */ 63 + struct prueth_queue_desc { 64 + u16 rd_ptr; 65 + u16 wr_ptr; 66 + u8 busy_s; 67 + u8 status; 68 + u8 max_fill_level; 69 + u8 overflow_cnt; 70 + }; 71 + 72 + /** 73 + * struct prueth_queue_info - Information about a queue in memory 74 + * @buffer_offset: buffer offset in OCMC RAM 75 + * @queue_desc_offset: queue descriptor offset in Shared RAM 76 + * @buffer_desc_offset: buffer descriptors offset in Shared RAM 77 + * @buffer_desc_end: end address of buffer descriptors in Shared RAM 78 + */ 79 + struct prueth_queue_info { 80 + u16 buffer_offset; 81 + u16 queue_desc_offset; 82 + u16 buffer_desc_offset; 83 + u16 buffer_desc_end; 84 + }; 85 + 86 + /** 87 + * struct prueth_packet_info - Info about a packet in buffer 88 + * @shadow: this packet is stored in the collision queue 89 + * @port: port packet is on 90 + * @length: length of packet 91 + * @broadcast: this packet is a broadcast packet 92 + * @error: this packet has an error 93 + * @lookup_success: src mac found in FDB 94 + * @flood: packet is to be flooded 95 + * @timestamp: Specifies if timestamp is appended to the packet 96 + */ 97 + struct prueth_packet_info { 98 + bool shadow; 99 + unsigned int port; 100 + unsigned int length; 101 + bool broadcast; 102 + bool error; 103 + bool lookup_success; 104 + bool flood; 105 + bool timestamp; 106 + }; 107 + 108 + /* In switch mode there are 3 real ports i.e. 3 mac addrs. 109 + * however Linux sees only the host side port. The other 2 ports 110 + * are the switch ports. 111 + * In emac mode there are 2 real ports i.e. 2 mac addrs. 112 + * Linux sees both the ports. 113 + */ 114 + enum prueth_port { 115 + PRUETH_PORT_HOST = 0, /* host side port */ 116 + PRUETH_PORT_MII0, /* physical port MII 0 */ 117 + PRUETH_PORT_MII1, /* physical port MII 1 */ 118 + PRUETH_PORT_INVALID, /* Invalid prueth port */ 119 + }; 120 + 121 + enum prueth_mac { 122 + PRUETH_MAC0 = 0, 123 + PRUETH_MAC1, 124 + PRUETH_NUM_MACS, 125 + PRUETH_MAC_INVALID, 126 + }; 127 + 128 + /* In both switch & emac modes there are 3 port queues 129 + * EMAC mode: 130 + * RX packets for both MII0 & MII1 ports come on 131 + * QUEUE_HOST. 132 + * TX packets for MII0 go on QUEUE_MII0, TX packets 133 + * for MII1 go on QUEUE_MII1. 134 + * Switch mode: 135 + * Host port RX packets come on QUEUE_HOST 136 + * TX packets might have to go on MII0 or MII1 or both. 137 + * MII0 TX queue is QUEUE_MII0 and MII1 TX queue is 138 + * QUEUE_MII1. 139 + */ 140 + enum prueth_port_queue_id { 141 + PRUETH_PORT_QUEUE_HOST = 0, 142 + PRUETH_PORT_QUEUE_MII0, 143 + PRUETH_PORT_QUEUE_MII1, 144 + PRUETH_PORT_QUEUE_MAX, 145 + }; 146 + 147 + /* Each port queue has 4 queues and 1 collision queue */ 148 + enum prueth_queue_id { 149 + PRUETH_QUEUE1 = 0, 150 + PRUETH_QUEUE2, 151 + PRUETH_QUEUE3, 152 + PRUETH_QUEUE4, 153 + PRUETH_COLQUEUE, /* collision queue */ 154 + }; 155 + 156 + /** 157 + * struct prueth_firmware - PRU Ethernet FW data 158 + * @fw_name: firmware names of firmware to run on PRU 159 + */ 160 + struct prueth_firmware { 161 + const char *fw_name[PRUSS_ETHTYPE_MAX]; 162 + }; 163 + 164 + /* PRUeth memory range identifiers */ 165 + enum prueth_mem { 166 + PRUETH_MEM_DRAM0 = 0, 167 + PRUETH_MEM_DRAM1, 168 + PRUETH_MEM_SHARED_RAM, 169 + PRUETH_MEM_OCMC, 170 + PRUETH_MEM_MAX, 171 + }; 172 + 173 + enum pruss_device { 174 + PRUSS_AM57XX = 0, 175 + PRUSS_AM43XX, 176 + PRUSS_AM33XX, 177 + PRUSS_K2G 178 + }; 179 + 180 + /** 181 + * struct prueth_private_data - PRU Ethernet private data 182 + * @driver_data: PRU Ethernet device name 183 + * @fw_pru: firmware names to be used for PRUSS ethernet usecases 184 + */ 185 + struct prueth_private_data { 186 + enum pruss_device driver_data; 187 + const struct prueth_firmware fw_pru[PRUSS_NUM_PRUS]; 188 + }; 189 + 190 + struct prueth_emac_stats { 191 + u64 tx_packets; 192 + u64 tx_dropped; 193 + u64 tx_bytes; 194 + u64 rx_packets; 195 + u64 rx_bytes; 196 + u64 rx_length_errors; 197 + u64 rx_over_errors; 198 + }; 199 + 200 + /* data for each emac port */ 201 + struct prueth_emac { 202 + struct prueth *prueth; 203 + struct net_device *ndev; 204 + struct napi_struct napi; 205 + 206 + struct rproc *pru; 207 + struct phy_device *phydev; 208 + struct prueth_queue_desc __iomem *rx_queue_descs; 209 + struct prueth_queue_desc __iomem *tx_queue_descs; 210 + 211 + int link; 212 + int speed; 213 + int duplex; 214 + int rx_irq; 215 + 216 + enum prueth_port_queue_id tx_port_queue; 217 + enum prueth_queue_id rx_queue_start; 218 + enum prueth_queue_id rx_queue_end; 219 + enum prueth_port port_id; 220 + enum prueth_mem dram; 221 + const char *phy_id; 222 + u32 msg_enable; 223 + u8 mac_addr[6]; 224 + phy_interface_t phy_if; 225 + 226 + /* spin lock used to protect 227 + * during link configuration 228 + */ 229 + spinlock_t lock; 230 + 231 + struct hrtimer tx_hrtimer; 232 + struct prueth_emac_stats stats; 233 + }; 234 + 235 + struct prueth { 236 + struct device *dev; 237 + struct pruss *pruss; 238 + struct rproc *pru0, *pru1; 239 + struct pruss_mem_region mem[PRUETH_MEM_MAX]; 240 + struct gen_pool *sram_pool; 241 + struct regmap *mii_rt; 242 + struct icss_iep *iep; 243 + 244 + const struct prueth_private_data *fw_data; 245 + struct prueth_fw_offsets *fw_offsets; 246 + 247 + struct device_node *eth_node[PRUETH_NUM_MACS]; 248 + struct prueth_emac *emac[PRUETH_NUM_MACS]; 249 + struct net_device *registered_netdevs[PRUETH_NUM_MACS]; 250 + 251 + unsigned int eth_type; 252 + size_t ocmc_ram_size; 253 + u8 emac_configured; 254 + }; 255 + 256 + void icssm_parse_packet_info(struct prueth *prueth, u32 buffer_descriptor, 257 + struct prueth_packet_info *pkt_info); 258 + int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr, 259 + struct prueth_packet_info *pkt_info, 260 + const struct prueth_queue_info *rxqueue); 261 + 262 + #endif /* __NET_TI_PRUETH_H */
+85
drivers/net/ethernet/ti/icssm/icssm_prueth_ptp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com 4 + */ 5 + #ifndef PRUETH_PTP_H 6 + #define PRUETH_PTP_H 7 + 8 + #define RX_SYNC_TIMESTAMP_OFFSET_P1 0x8 /* 8 bytes */ 9 + #define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x14 /* 12 bytes */ 10 + 11 + #define DISABLE_PTP_FRAME_FORWARDING_CTRL_OFFSET 0x14 /* 1 byte */ 12 + 13 + #define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x20 /* 12 bytes */ 14 + #define RX_SYNC_TIMESTAMP_OFFSET_P2 0x2c /* 12 bytes */ 15 + #define RX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0x38 /* 12 bytes */ 16 + #define RX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0x44 /* 12 bytes */ 17 + #define TIMESYNC_DOMAIN_NUMBER_LIST 0x50 /* 2 bytes */ 18 + #define P1_SMA_LINE_DELAY_OFFSET 0x52 /* 4 bytes */ 19 + #define P2_SMA_LINE_DELAY_OFFSET 0x56 /* 4 bytes */ 20 + #define TIMESYNC_SECONDS_COUNT_OFFSET 0x5a /* 6 bytes */ 21 + #define TIMESYNC_TC_RCF_OFFSET 0x60 /* 4 bytes */ 22 + #define DUT_IS_MASTER_OFFSET 0x64 /* 1 byte */ 23 + #define MASTER_PORT_NUM_OFFSET 0x65 /* 1 byte */ 24 + #define SYNC_MASTER_MAC_OFFSET 0x66 /* 6 bytes */ 25 + #define TX_TS_NOTIFICATION_OFFSET_SYNC_P1 0x6c /* 1 byte */ 26 + #define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P1 0x6d /* 1 byte */ 27 + #define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P1 0x6e /* 1 byte */ 28 + #define TX_TS_NOTIFICATION_OFFSET_SYNC_P2 0x6f /* 1 byte */ 29 + #define TX_TS_NOTIFICATION_OFFSET_PDEL_REQ_P2 0x70 /* 1 byte */ 30 + #define TX_TS_NOTIFICATION_OFFSET_PDEL_RES_P2 0x71 /* 1 byte */ 31 + #define TX_SYNC_TIMESTAMP_OFFSET_P1 0x72 /* 12 bytes */ 32 + #define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P1 0x7e /* 12 bytes */ 33 + #define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P1 0x8a /* 12 bytes */ 34 + #define TX_SYNC_TIMESTAMP_OFFSET_P2 0x96 /* 12 bytes */ 35 + #define TX_PDELAY_REQ_TIMESTAMP_OFFSET_P2 0xa2 /* 12 bytes */ 36 + #define TX_PDELAY_RESP_TIMESTAMP_OFFSET_P2 0xae /* 12 bytes */ 37 + #define TIMESYNC_CTRL_VAR_OFFSET 0xba /* 1 byte */ 38 + #define DISABLE_SWITCH_SYNC_RELAY_OFFSET 0xbb /* 1 byte */ 39 + #define MII_RX_CORRECTION_OFFSET 0xbc /* 2 bytes */ 40 + #define MII_TX_CORRECTION_OFFSET 0xbe /* 2 bytes */ 41 + #define TIMESYNC_CMP1_CMP_OFFSET 0xc0 /* 8 bytes */ 42 + #define TIMESYNC_SYNC0_CMP_OFFSET 0xc8 /* 8 bytes */ 43 + #define TIMESYNC_CMP1_PERIOD_OFFSET 0xd0 /* 4 bytes */ 44 + #define TIMESYNC_SYNC0_WIDTH_OFFSET 0xd4 /* 4 bytes */ 45 + #define SINGLE_STEP_IEP_OFFSET_P1 0xd8 /* 8 bytes */ 46 + #define SINGLE_STEP_SECONDS_OFFSET_P1 0xe0 /* 8 bytes */ 47 + #define SINGLE_STEP_IEP_OFFSET_P2 0xe8 /* 8 bytes */ 48 + #define SINGLE_STEP_SECONDS_OFFSET_P2 0xf0 /* 8 bytes */ 49 + #define LINK_LOCAL_FRAME_HAS_HSR_TAG 0xf8 /* 1 bytes */ 50 + #define PTP_PREV_TX_TIMESTAMP_P1 0xf9 /* 8 bytes */ 51 + #define PTP_PREV_TX_TIMESTAMP_P2 0x101 /* 8 bytes */ 52 + #define PTP_CLK_IDENTITY_OFFSET 0x109 /* 8 bytes */ 53 + #define PTP_SCRATCH_MEM 0x111 /* 16 byte */ 54 + #define PTP_IPV4_UDP_E2E_ENABLE 0x121 /* 1 byte */ 55 + 56 + enum { 57 + PRUETH_PTP_SYNC, 58 + PRUETH_PTP_DLY_REQ, 59 + PRUETH_PTP_DLY_RESP, 60 + PRUETH_PTP_TS_EVENTS, 61 + }; 62 + 63 + #define PRUETH_PTP_TS_SIZE 12 64 + #define PRUETH_PTP_TS_NOTIFY_SIZE 1 65 + #define PRUETH_PTP_TS_NOTIFY_MASK 0xff 66 + 67 + /* Bit definitions for TIMESYNC_CTRL */ 68 + #define TIMESYNC_CTRL_BG_ENABLE BIT(0) 69 + #define TIMESYNC_CTRL_FORCED_2STEP BIT(1) 70 + 71 + static inline u32 icssm_prueth_tx_ts_offs_get(u8 port, u8 event) 72 + { 73 + return TX_SYNC_TIMESTAMP_OFFSET_P1 + port * 74 + PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_SIZE + 75 + event * PRUETH_PTP_TS_SIZE; 76 + } 77 + 78 + static inline u32 icssm_prueth_tx_ts_notify_offs_get(u8 port, u8 event) 79 + { 80 + return TX_TS_NOTIFICATION_OFFSET_SYNC_P1 + 81 + PRUETH_PTP_TS_EVENTS * PRUETH_PTP_TS_NOTIFY_SIZE * port + 82 + event * PRUETH_PTP_TS_NOTIFY_SIZE; 83 + } 84 + 85 + #endif /* PRUETH_PTP_H */
+257
drivers/net/ethernet/ti/icssm/icssm_switch.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* Copyright (C) 2015-2021 Texas Instruments Incorporated - https://www.ti.com 4 + */ 5 + 6 + #ifndef __ICSS_SWITCH_H 7 + #define __ICSS_SWITCH_H 8 + 9 + /* Basic Switch Parameters 10 + * Used to auto compute offset addresses on L3 OCMC RAM. Do not modify these 11 + * without changing firmware accordingly 12 + */ 13 + #define SWITCH_BUFFER_SIZE (64 * 1024) /* L3 buffer */ 14 + #define ICSS_BLOCK_SIZE 32 /* data bytes per BD */ 15 + #define BD_SIZE 4 /* byte buffer descriptor */ 16 + #define NUM_QUEUES 4 /* Queues on Port 0/1/2 */ 17 + 18 + #define PORT_LINK_MASK 0x1 19 + #define PORT_IS_HD_MASK 0x2 20 + 21 + /* Physical Port queue size (number of BDs). Same for both ports */ 22 + #define QUEUE_1_SIZE 97 /* Network Management high */ 23 + #define QUEUE_2_SIZE 97 /* Network Management low */ 24 + #define QUEUE_3_SIZE 97 /* Protocol specific */ 25 + #define QUEUE_4_SIZE 97 /* NRT (IP,ARP, ICMP) */ 26 + 27 + /* Host queue size (number of BDs). Each BD points to data buffer of 32 bytes. 28 + * HOST PORT QUEUES can buffer up to 4 full sized frames per queue 29 + */ 30 + #define HOST_QUEUE_1_SIZE 194 /* Protocol and VLAN priority 7 & 6 */ 31 + #define HOST_QUEUE_2_SIZE 194 /* Protocol mid */ 32 + #define HOST_QUEUE_3_SIZE 194 /* Protocol low */ 33 + #define HOST_QUEUE_4_SIZE 194 /* NRT (IP, ARP, ICMP) */ 34 + 35 + #define COL_QUEUE_SIZE 0 36 + 37 + /* NRT Buffer descriptor definition 38 + * Each buffer descriptor points to a max 32 byte block and has 32 bit in size 39 + * to have atomic operation. 40 + * PRU can address bytewise into memory. 41 + * Definition of 32 bit descriptor is as follows 42 + * 43 + * Bits Name Meaning 44 + * ============================================================================= 45 + * 0..7 Index points to index in buffer queue, max 256 x 32 46 + * byte blocks can be addressed 47 + * 6 LookupSuccess For switch, FDB lookup was successful (source 48 + * MAC address found in FDB). 49 + * For RED, NodeTable lookup was successful. 50 + * 7 Flood Packet should be flooded (destination MAC 51 + * address found in FDB). For switch only. 52 + * 8..12 Block_length number of valid bytes in this specific block. 53 + * Will be <=32 bytes on last block of packet 54 + * 13 More "More" bit indicating that there are more blocks 55 + * 14 Shadow indicates that "index" is pointing into shadow 56 + * buffer 57 + * 15 TimeStamp indicates that this packet has time stamp in 58 + * separate buffer - only needed if PTP runs on 59 + * host 60 + * 16..17 Port different meaning for ingress and egress, 61 + * Ingress: Port = 0 indicates phy port 1 and 62 + * Port = 1 indicates phy port 2. 63 + * Egress: 0 sends on phy port 1 and 1 sends on 64 + * phy port 2. Port = 2 goes over MAC table 65 + * look-up 66 + * 18..28 Length 11 bit of total packet length which is put into 67 + * first BD only so that host access only one BD 68 + * 29 VlanTag indicates that packet has Length/Type field of 69 + * 0x08100 with VLAN tag in following byte 70 + * 30 Broadcast indicates that packet goes out on both physical 71 + * ports, there will be two bd but only one buffer 72 + * 31 Error indicates there was an error in the packet 73 + */ 74 + #define PRUETH_BD_START_FLAG_MASK BIT(0) 75 + #define PRUETH_BD_START_FLAG_SHIFT 0 76 + 77 + #define PRUETH_BD_HSR_FRAME_MASK BIT(4) 78 + #define PRUETH_BD_HSR_FRAME_SHIFT 4 79 + 80 + #define PRUETH_BD_SUP_HSR_FRAME_MASK BIT(5) 81 + #define PRUETH_BD_SUP_HSR_FRAME_SHIFT 5 82 + 83 + #define PRUETH_BD_LOOKUP_SUCCESS_MASK BIT(6) 84 + #define PRUETH_BD_LOOKUP_SUCCESS_SHIFT 6 85 + 86 + #define PRUETH_BD_SW_FLOOD_MASK BIT(7) 87 + #define PRUETH_BD_SW_FLOOD_SHIFT 7 88 + 89 + #define PRUETH_BD_SHADOW_MASK BIT(14) 90 + #define PRUETH_BD_SHADOW_SHIFT 14 91 + 92 + #define PRUETH_BD_TIMESTAMP_MASK BIT(15) 93 + #define PRUETH_BD_TIMESTAMP_SHIFT 15 94 + 95 + #define PRUETH_BD_PORT_MASK GENMASK(17, 16) 96 + #define PRUETH_BD_PORT_SHIFT 16 97 + 98 + #define PRUETH_BD_LENGTH_MASK GENMASK(28, 18) 99 + #define PRUETH_BD_LENGTH_SHIFT 18 100 + 101 + #define PRUETH_BD_BROADCAST_MASK BIT(30) 102 + #define PRUETH_BD_BROADCAST_SHIFT 30 103 + 104 + #define PRUETH_BD_ERROR_MASK BIT(31) 105 + #define PRUETH_BD_ERROR_SHIFT 31 106 + 107 + /* The following offsets indicate which sections of the memory are used 108 + * for EMAC internal tasks 109 + */ 110 + #define DRAM_START_OFFSET 0x1E98 111 + #define SRAM_START_OFFSET 0x400 112 + 113 + /* General Purpose Statistics 114 + * These are present on both PRU0 and PRU1 DRAM 115 + */ 116 + /* base statistics offset */ 117 + #define STATISTICS_OFFSET 0x1F00 118 + #define STAT_SIZE 0x98 119 + 120 + /* Offset for storing 121 + * 1. Storm Prevention Params 122 + * 2. PHY Speed Offset 123 + * 3. Port Status Offset 124 + * These are present on both PRU0 and PRU1 125 + */ 126 + /* 4 bytes */ 127 + #define STORM_PREVENTION_OFFSET_BC (STATISTICS_OFFSET + STAT_SIZE) 128 + /* 4 bytes */ 129 + #define PHY_SPEED_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 4) 130 + /* 1 byte */ 131 + #define PORT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 8) 132 + /* 1 byte */ 133 + #define COLLISION_COUNTER (STATISTICS_OFFSET + STAT_SIZE + 9) 134 + /* 4 bytes */ 135 + #define RX_PKT_SIZE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 10) 136 + /* 4 bytes */ 137 + #define PORT_CONTROL_ADDR (STATISTICS_OFFSET + STAT_SIZE + 14) 138 + /* 6 bytes */ 139 + #define PORT_MAC_ADDR (STATISTICS_OFFSET + STAT_SIZE + 18) 140 + /* 1 byte */ 141 + #define RX_INT_STATUS_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 24) 142 + /* 4 bytes */ 143 + #define STORM_PREVENTION_OFFSET_MC (STATISTICS_OFFSET + STAT_SIZE + 25) 144 + /* 4 bytes */ 145 + #define STORM_PREVENTION_OFFSET_UC (STATISTICS_OFFSET + STAT_SIZE + 29) 146 + /* 4 bytes ? */ 147 + #define STP_INVALID_STATE_OFFSET (STATISTICS_OFFSET + STAT_SIZE + 33) 148 + 149 + /* DRAM Offsets for EMAC 150 + * Present on Both DRAM0 and DRAM1 151 + */ 152 + 153 + /* 4 queue descriptors for port tx = 32 bytes */ 154 + #define TX_CONTEXT_Q1_OFFSET_ADDR (PORT_QUEUE_DESC_OFFSET + 32) 155 + #define PORT_QUEUE_DESC_OFFSET (ICSS_EMAC_TTS_CYC_TX_SOF + 8) 156 + 157 + /* EMAC Time Triggered Send Offsets */ 158 + #define ICSS_EMAC_TTS_CYC_TX_SOF (ICSS_EMAC_TTS_PREV_TX_SOF + 8) 159 + #define ICSS_EMAC_TTS_PREV_TX_SOF \ 160 + (ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET + 4) 161 + #define ICSS_EMAC_TTS_MISSED_CYCLE_CNT_OFFSET (ICSS_EMAC_TTS_STATUS_OFFSET \ 162 + + 4) 163 + #define ICSS_EMAC_TTS_STATUS_OFFSET (ICSS_EMAC_TTS_CFG_TIME_OFFSET + 4) 164 + #define ICSS_EMAC_TTS_CFG_TIME_OFFSET (ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET + 4) 165 + #define ICSS_EMAC_TTS_CYCLE_PERIOD_OFFSET \ 166 + (ICSS_EMAC_TTS_CYCLE_START_OFFSET + 8) 167 + #define ICSS_EMAC_TTS_CYCLE_START_OFFSET ICSS_EMAC_TTS_BASE_OFFSET 168 + #define ICSS_EMAC_TTS_BASE_OFFSET DRAM_START_OFFSET 169 + 170 + /* Shared RAM offsets for EMAC */ 171 + 172 + /* Queue Descriptors */ 173 + 174 + /* 4 queue descriptors for port 0 (host receive). 32 bytes */ 175 + #define HOST_QUEUE_DESC_OFFSET (HOST_QUEUE_SIZE_ADDR + 16) 176 + 177 + /* table offset for queue size: 178 + * 3 ports * 4 Queues * 1 byte offset = 12 bytes 179 + */ 180 + #define HOST_QUEUE_SIZE_ADDR (HOST_QUEUE_OFFSET_ADDR + 8) 181 + /* table offset for queue: 182 + * 4 Queues * 2 byte offset = 8 bytes 183 + */ 184 + #define HOST_QUEUE_OFFSET_ADDR (HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR + 8) 185 + /* table offset for Host queue descriptors: 186 + * 1 ports * 4 Queues * 2 byte offset = 8 bytes 187 + */ 188 + #define HOST_QUEUE_DESCRIPTOR_OFFSET_ADDR (HOST_Q4_RX_CONTEXT_OFFSET + 8) 189 + 190 + /* Host Port Rx Context */ 191 + #define HOST_Q4_RX_CONTEXT_OFFSET (HOST_Q3_RX_CONTEXT_OFFSET + 8) 192 + #define HOST_Q3_RX_CONTEXT_OFFSET (HOST_Q2_RX_CONTEXT_OFFSET + 8) 193 + #define HOST_Q2_RX_CONTEXT_OFFSET (HOST_Q1_RX_CONTEXT_OFFSET + 8) 194 + #define HOST_Q1_RX_CONTEXT_OFFSET (EMAC_PROMISCUOUS_MODE_OFFSET + 4) 195 + 196 + /* Promiscuous mode control */ 197 + #define EMAC_P1_PROMISCUOUS_BIT BIT(0) 198 + #define EMAC_P2_PROMISCUOUS_BIT BIT(1) 199 + #define EMAC_PROMISCUOUS_MODE_OFFSET (EMAC_RESERVED + 4) 200 + #define EMAC_RESERVED EOF_48K_BUFFER_BD 201 + 202 + /* allow for max 48k buffer which spans the descriptors up to 0x1800 6kB */ 203 + #define EOF_48K_BUFFER_BD (P0_BUFFER_DESC_OFFSET + HOST_BD_SIZE + \ 204 + PORT_BD_SIZE) 205 + 206 + #define HOST_BD_SIZE ((HOST_QUEUE_1_SIZE + \ 207 + HOST_QUEUE_2_SIZE + HOST_QUEUE_3_SIZE + \ 208 + HOST_QUEUE_4_SIZE) * BD_SIZE) 209 + #define PORT_BD_SIZE ((QUEUE_1_SIZE + QUEUE_2_SIZE + \ 210 + QUEUE_3_SIZE + QUEUE_4_SIZE) * 2 * BD_SIZE) 211 + 212 + #define END_OF_BD_POOL (P2_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE) 213 + #define P2_Q4_BD_OFFSET (P2_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE) 214 + #define P2_Q3_BD_OFFSET (P2_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE) 215 + #define P2_Q2_BD_OFFSET (P2_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE) 216 + #define P2_Q1_BD_OFFSET (P1_Q4_BD_OFFSET + QUEUE_4_SIZE * BD_SIZE) 217 + #define P1_Q4_BD_OFFSET (P1_Q3_BD_OFFSET + QUEUE_3_SIZE * BD_SIZE) 218 + #define P1_Q3_BD_OFFSET (P1_Q2_BD_OFFSET + QUEUE_2_SIZE * BD_SIZE) 219 + #define P1_Q2_BD_OFFSET (P1_Q1_BD_OFFSET + QUEUE_1_SIZE * BD_SIZE) 220 + #define P1_Q1_BD_OFFSET (P0_Q4_BD_OFFSET + HOST_QUEUE_4_SIZE * BD_SIZE) 221 + #define P0_Q4_BD_OFFSET (P0_Q3_BD_OFFSET + HOST_QUEUE_3_SIZE * BD_SIZE) 222 + #define P0_Q3_BD_OFFSET (P0_Q2_BD_OFFSET + HOST_QUEUE_2_SIZE * BD_SIZE) 223 + #define P0_Q2_BD_OFFSET (P0_Q1_BD_OFFSET + HOST_QUEUE_1_SIZE * BD_SIZE) 224 + #define P0_Q1_BD_OFFSET P0_BUFFER_DESC_OFFSET 225 + #define P0_BUFFER_DESC_OFFSET SRAM_START_OFFSET 226 + 227 + /* Memory Usage of L3 OCMC RAM */ 228 + 229 + /* L3 64KB Memory - mainly buffer Pool */ 230 + #define END_OF_BUFFER_POOL (P2_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \ 231 + ICSS_BLOCK_SIZE) 232 + #define P2_Q4_BUFFER_OFFSET (P2_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \ 233 + ICSS_BLOCK_SIZE) 234 + #define P2_Q3_BUFFER_OFFSET (P2_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \ 235 + ICSS_BLOCK_SIZE) 236 + #define P2_Q2_BUFFER_OFFSET (P2_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \ 237 + ICSS_BLOCK_SIZE) 238 + #define P2_Q1_BUFFER_OFFSET (P1_Q4_BUFFER_OFFSET + QUEUE_4_SIZE * \ 239 + ICSS_BLOCK_SIZE) 240 + #define P1_Q4_BUFFER_OFFSET (P1_Q3_BUFFER_OFFSET + QUEUE_3_SIZE * \ 241 + ICSS_BLOCK_SIZE) 242 + #define P1_Q3_BUFFER_OFFSET (P1_Q2_BUFFER_OFFSET + QUEUE_2_SIZE * \ 243 + ICSS_BLOCK_SIZE) 244 + #define P1_Q2_BUFFER_OFFSET (P1_Q1_BUFFER_OFFSET + QUEUE_1_SIZE * \ 245 + ICSS_BLOCK_SIZE) 246 + #define P1_Q1_BUFFER_OFFSET (P0_Q4_BUFFER_OFFSET + HOST_QUEUE_4_SIZE * \ 247 + ICSS_BLOCK_SIZE) 248 + #define P0_Q4_BUFFER_OFFSET (P0_Q3_BUFFER_OFFSET + HOST_QUEUE_3_SIZE * \ 249 + ICSS_BLOCK_SIZE) 250 + #define P0_Q3_BUFFER_OFFSET (P0_Q2_BUFFER_OFFSET + HOST_QUEUE_2_SIZE * \ 251 + ICSS_BLOCK_SIZE) 252 + #define P0_Q2_BUFFER_OFFSET (P0_Q1_BUFFER_OFFSET + HOST_QUEUE_1_SIZE * \ 253 + ICSS_BLOCK_SIZE) 254 + #define P0_COL_BUFFER_OFFSET 0xEE00 255 + #define P0_Q1_BUFFER_OFFSET 0x0000 256 + 257 + #endif /* __ICSS_SWITCH_H */