diff options
author | David S. Miller <davem@davemloft.net> | 2014-08-11 14:51:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-11 14:51:19 -0400 |
commit | 217e606bf69c0c9f2ef25def38e9f2a8969578f5 (patch) | |
tree | eb1973422d780d9295bddd2da617812cd1c73456 | |
parent | f00439e2e34e97130981c8b68310b8b77b86645a (diff) | |
parent | e6ad767305eb6ea80ce06c1eaa1b0977e8361998 (diff) |
Merge branch 'apm_xgene'
Iyappan Subramanian says:
====================
net: Add APM X-Gene SoC Ethernet driver support
Adding APM X-Gene SoC Ethernet driver.
v10: Address comments from v9 review
* Documentation: aligned descriptions
* simplified struct platform_driver initialization
* fixed xgene_enet_mdio_config error path
* fixed xgene_enet_init_hw error path
* removed statistics spin_lock as it is not required
* changed raw_desc fields to type __le64
* defined helper macros for set/get raw_descriptor fields
v9: Address comments from v8 review
* changed to direct read/write, byteswap into raw descriptor
* fixed xgene_enet_create_desc_ring() error handling
* removed references to IS_ERR_OR_NULL
* disabled half duplex on phy_devce supported/advertising
* simplified xgene_enet_adjust_link() function
* fixed sparse tool compilation warnings
v8: Address comments from v7 review
* changed angle bracket to double quotes in header file include.
v7: Address comments from v6 review
* fixed skb memory leak when dma_map_single fails in xmit.
v6: Address comments from v5 review
* added basic ethtool support
* added ndo_get_stats64 call back
* deleted priting Rx error messages
* renamed set_bits to xgene_set_bits to fix kbuild error (make ARCH=powerpc)
v5: Address comments from v4 review
* Documentation: Added phy-handle, reg-names and changed mdio part
* dtb: Added reg-names supplemental property
* changed platform_get_resource to platform_get_resource_byname
* added separate tx/rx set_desc/get_desc functions to do raw_write/raw_read
* removed set_desc/get_desc table lookup logic
* added error handling logic based on per packet descriptor bits
* added software managed Rx packet and error counters
* added busy wait for register read/writes
* changed mdio_bus->id to avoid conflict
* fixed mdio_bus leak in case of mdio_config error
* changed phy reg hard coded value to MII_BMSR
* changed phy addr hard coded value to phy_device->addr
* added paranthesis around macro arguments
* converted helper macros to inline functions
* changed use of goto's only to common work such as cleanup
v4: Address comments from v3 review
* MAINTAINERS: changed status to supported
* Kconfig: made default to no
* changed to bool data type wherever applicable
* cleaned up single bit set and masking code
* removed statistics counters masking
* removed unnecessary OOM message printing
* fixed dma_map_single and dma_unmap_single size parameter
* changed set bits macro body using new set_bits function
v3: Address comments from v2 review
* cleaned up set_desc and get_desc functions
* added dtb mdio node and phy-handle subnode
* renamed dtb phy-mode to phy-connection-type
* added of_phy_connect call to connec to PHY
* added empty line after last local variable declaration
* removed type casting when not required
* removed inline keyword from source files
* removed CONFIG_CPU_BIG_ENDIAN ifdef
v2
* Completely redesigned ethernet driver
* Added support to work with big endian kernel
* Renamed dtb phyid entry to phy_addr
* Changed dtb local-mac-address entry to byte string format
* Renamed dtb eth8clk entry to menetclk
v1
* Initial version
====================
Signed-off-by: Iyappan Subramanian <isubramanian@apm.com>
Signed-off-by: Ravi Patel <rapatel@apm.com>
Signed-off-by: Keyur Chudgar <kchudgar@apm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 66 | ||||
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | arch/arm64/boot/dts/apm-mustang.dts | 4 | ||||
-rw-r--r-- | arch/arm64/boot/dts/apm-storm.dtsi | 30 | ||||
-rw-r--r-- | drivers/net/ethernet/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/Makefile | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | 125 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 728 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 337 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 951 | ||||
-rw-r--r-- | drivers/net/ethernet/apm/xgene/xgene_enet_main.h | 135 |
15 files changed, 2404 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt new file mode 100644 index 000000000000..ebcad25efd0a --- /dev/null +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt | |||
@@ -0,0 +1,66 @@ | |||
1 | APM X-Gene SoC Ethernet nodes | ||
2 | |||
3 | Ethernet nodes are defined to describe on-chip ethernet interfaces in | ||
4 | APM X-Gene SoC. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: Should be "apm,xgene-enet" | ||
8 | - reg: Address and length of the register set for the device. It contains the | ||
9 | information of registers in the same order as described by reg-names | ||
10 | - reg-names: Should contain the register set names | ||
11 | - "enet_csr": Ethernet control and status register address space | ||
12 | - "ring_csr": Descriptor ring control and status register address space | ||
13 | - "ring_cmd": Descriptor ring command register address space | ||
14 | - interrupts: Ethernet main interrupt | ||
15 | - clocks: Reference to the clock entry. | ||
16 | - local-mac-address: MAC address assigned to this device | ||
17 | - phy-connection-type: Interface type between ethernet device and PHY device | ||
18 | - phy-handle: Reference to a PHY node connected to this device | ||
19 | |||
20 | - mdio: Device tree subnode with the following required properties: | ||
21 | - compatible: Must be "apm,xgene-mdio". | ||
22 | - #address-cells: Must be <1>. | ||
23 | - #size-cells: Must be <0>. | ||
24 | |||
25 | For the phy on the mdio bus, there must be a node with the following fields: | ||
26 | - compatible: PHY identifier. Please refer ./phy.txt for the format. | ||
27 | - reg: The ID number for the phy. | ||
28 | |||
29 | Optional properties: | ||
30 | - status: Should be "ok" or "disabled" for enabled/disabled. Default is "ok". | ||
31 | |||
32 | Example: | ||
33 | menetclk: menetclk { | ||
34 | compatible = "apm,xgene-device-clock"; | ||
35 | clock-output-names = "menetclk"; | ||
36 | status = "ok"; | ||
37 | }; | ||
38 | |||
39 | menet: ethernet@17020000 { | ||
40 | compatible = "apm,xgene-enet"; | ||
41 | status = "disabled"; | ||
42 | reg = <0x0 0x17020000 0x0 0xd100>, | ||
43 | <0x0 0X17030000 0x0 0X400>, | ||
44 | <0x0 0X10000000 0x0 0X200>; | ||
45 | reg-names = "enet_csr", "ring_csr", "ring_cmd"; | ||
46 | interrupts = <0x0 0x3c 0x4>; | ||
47 | clocks = <&menetclk 0>; | ||
48 | local-mac-address = [00 01 73 00 00 01]; | ||
49 | phy-connection-type = "rgmii"; | ||
50 | phy-handle = <&menetphy>; | ||
51 | mdio { | ||
52 | compatible = "apm,xgene-mdio"; | ||
53 | #address-cells = <1>; | ||
54 | #size-cells = <0>; | ||
55 | menetphy: menetphy@3 { | ||
56 | compatible = "ethernet-phy-id001c.c915"; | ||
57 | reg = <0x3>; | ||
58 | }; | ||
59 | |||
60 | }; | ||
61 | }; | ||
62 | |||
63 | /* Board-specific peripheral configurations */ | ||
64 | &menet { | ||
65 | status = "ok"; | ||
66 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 05e545096100..e8ac35270823 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -719,6 +719,14 @@ S: Maintained | |||
719 | F: drivers/net/appletalk/ | 719 | F: drivers/net/appletalk/ |
720 | F: net/appletalk/ | 720 | F: net/appletalk/ |
721 | 721 | ||
722 | APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER | ||
723 | M: Iyappan Subramanian <isubramanian@apm.com> | ||
724 | M: Keyur Chudgar <kchudgar@apm.com> | ||
725 | M: Ravi Patel <rapatel@apm.com> | ||
726 | S: Supported | ||
727 | F: drivers/net/ethernet/apm/xgene/ | ||
728 | F: Documentation/devicetree/bindings/net/apm-xgene-enet.txt | ||
729 | |||
722 | APTINA CAMERA SENSOR PLL | 730 | APTINA CAMERA SENSOR PLL |
723 | M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> | 731 | M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> |
724 | L: linux-media@vger.kernel.org | 732 | L: linux-media@vger.kernel.org |
diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts index 6541962f5d70..b2f56229aa5e 100644 --- a/arch/arm64/boot/dts/apm-mustang.dts +++ b/arch/arm64/boot/dts/apm-mustang.dts | |||
@@ -28,3 +28,7 @@ | |||
28 | &serial0 { | 28 | &serial0 { |
29 | status = "ok"; | 29 | status = "ok"; |
30 | }; | 30 | }; |
31 | |||
32 | &menet { | ||
33 | status = "ok"; | ||
34 | }; | ||
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi index 40aa96ce13c4..c0aceef7f5b3 100644 --- a/arch/arm64/boot/dts/apm-storm.dtsi +++ b/arch/arm64/boot/dts/apm-storm.dtsi | |||
@@ -167,14 +167,13 @@ | |||
167 | clock-output-names = "ethclk"; | 167 | clock-output-names = "ethclk"; |
168 | }; | 168 | }; |
169 | 169 | ||
170 | eth8clk: eth8clk { | 170 | menetclk: menetclk { |
171 | compatible = "apm,xgene-device-clock"; | 171 | compatible = "apm,xgene-device-clock"; |
172 | #clock-cells = <1>; | 172 | #clock-cells = <1>; |
173 | clocks = <ðclk 0>; | 173 | clocks = <ðclk 0>; |
174 | clock-names = "eth8clk"; | ||
175 | reg = <0x0 0x1702C000 0x0 0x1000>; | 174 | reg = <0x0 0x1702C000 0x0 0x1000>; |
176 | reg-names = "csr-reg"; | 175 | reg-names = "csr-reg"; |
177 | clock-output-names = "eth8clk"; | 176 | clock-output-names = "menetclk"; |
178 | }; | 177 | }; |
179 | 178 | ||
180 | sataphy1clk: sataphy1clk@1f21c000 { | 179 | sataphy1clk: sataphy1clk@1f21c000 { |
@@ -397,5 +396,30 @@ | |||
397 | #clock-cells = <1>; | 396 | #clock-cells = <1>; |
398 | clocks = <&rtcclk 0>; | 397 | clocks = <&rtcclk 0>; |
399 | }; | 398 | }; |
399 | |||
400 | menet: ethernet@17020000 { | ||
401 | compatible = "apm,xgene-enet"; | ||
402 | status = "disabled"; | ||
403 | reg = <0x0 0x17020000 0x0 0xd100>, | ||
404 | <0x0 0X17030000 0x0 0X400>, | ||
405 | <0x0 0X10000000 0x0 0X200>; | ||
406 | reg-names = "enet_csr", "ring_csr", "ring_cmd"; | ||
407 | interrupts = <0x0 0x3c 0x4>; | ||
408 | dma-coherent; | ||
409 | clocks = <&menetclk 0>; | ||
410 | local-mac-address = [00 01 73 00 00 01]; | ||
411 | phy-connection-type = "rgmii"; | ||
412 | phy-handle = <&menetphy>; | ||
413 | mdio { | ||
414 | compatible = "apm,xgene-mdio"; | ||
415 | #address-cells = <1>; | ||
416 | #size-cells = <0>; | ||
417 | menetphy: menetphy@3 { | ||
418 | compatible = "ethernet-phy-id001c.c915"; | ||
419 | reg = <0x3>; | ||
420 | }; | ||
421 | |||
422 | }; | ||
423 | }; | ||
400 | }; | 424 | }; |
401 | }; | 425 | }; |
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index edb718661850..dc7406c81c45 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig | |||
@@ -24,6 +24,7 @@ source "drivers/net/ethernet/allwinner/Kconfig" | |||
24 | source "drivers/net/ethernet/alteon/Kconfig" | 24 | source "drivers/net/ethernet/alteon/Kconfig" |
25 | source "drivers/net/ethernet/altera/Kconfig" | 25 | source "drivers/net/ethernet/altera/Kconfig" |
26 | source "drivers/net/ethernet/amd/Kconfig" | 26 | source "drivers/net/ethernet/amd/Kconfig" |
27 | source "drivers/net/ethernet/apm/Kconfig" | ||
27 | source "drivers/net/ethernet/apple/Kconfig" | 28 | source "drivers/net/ethernet/apple/Kconfig" |
28 | source "drivers/net/ethernet/arc/Kconfig" | 29 | source "drivers/net/ethernet/arc/Kconfig" |
29 | source "drivers/net/ethernet/atheros/Kconfig" | 30 | source "drivers/net/ethernet/atheros/Kconfig" |
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 58de3339ab3c..224a01877149 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/ | |||
10 | obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ | 10 | obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/ |
11 | obj-$(CONFIG_ALTERA_TSE) += altera/ | 11 | obj-$(CONFIG_ALTERA_TSE) += altera/ |
12 | obj-$(CONFIG_NET_VENDOR_AMD) += amd/ | 12 | obj-$(CONFIG_NET_VENDOR_AMD) += amd/ |
13 | obj-$(CONFIG_NET_XGENE) += apm/ | ||
13 | obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ | 14 | obj-$(CONFIG_NET_VENDOR_APPLE) += apple/ |
14 | obj-$(CONFIG_NET_VENDOR_ARC) += arc/ | 15 | obj-$(CONFIG_NET_VENDOR_ARC) += arc/ |
15 | obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ | 16 | obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/ |
diff --git a/drivers/net/ethernet/apm/Kconfig b/drivers/net/ethernet/apm/Kconfig new file mode 100644 index 000000000000..ec63d706d464 --- /dev/null +++ b/drivers/net/ethernet/apm/Kconfig | |||
@@ -0,0 +1 @@ | |||
source "drivers/net/ethernet/apm/xgene/Kconfig" | |||
diff --git a/drivers/net/ethernet/apm/Makefile b/drivers/net/ethernet/apm/Makefile new file mode 100644 index 000000000000..65ce32ad1b2c --- /dev/null +++ b/drivers/net/ethernet/apm/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for APM X-GENE Ethernet driver. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_NET_XGENE) += xgene/ | ||
diff --git a/drivers/net/ethernet/apm/xgene/Kconfig b/drivers/net/ethernet/apm/xgene/Kconfig new file mode 100644 index 000000000000..616dff6d3f5f --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config NET_XGENE | ||
2 | tristate "APM X-Gene SoC Ethernet Driver" | ||
3 | select PHYLIB | ||
4 | help | ||
5 | This is the Ethernet driver for the on-chip ethernet interface on the | ||
6 | APM X-Gene SoC. | ||
7 | |||
8 | To compile this driver as a module, choose M here. This module will | ||
9 | be called xgene_enet. | ||
diff --git a/drivers/net/ethernet/apm/xgene/Makefile b/drivers/net/ethernet/apm/xgene/Makefile new file mode 100644 index 000000000000..c643e8a0a0dc --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for APM X-Gene Ethernet Driver. | ||
3 | # | ||
4 | |||
5 | xgene-enet-objs := xgene_enet_hw.o xgene_enet_main.o xgene_enet_ethtool.o | ||
6 | obj-$(CONFIG_NET_XGENE) += xgene-enet.o | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c new file mode 100644 index 000000000000..63f2aa54a594 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_ethtool.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/ethtool.h> | ||
21 | #include "xgene_enet_main.h" | ||
22 | |||
23 | struct xgene_gstrings_stats { | ||
24 | char name[ETH_GSTRING_LEN]; | ||
25 | int offset; | ||
26 | }; | ||
27 | |||
28 | #define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) } | ||
29 | |||
30 | static const struct xgene_gstrings_stats gstrings_stats[] = { | ||
31 | XGENE_STAT(rx_packets), | ||
32 | XGENE_STAT(tx_packets), | ||
33 | XGENE_STAT(rx_bytes), | ||
34 | XGENE_STAT(tx_bytes), | ||
35 | XGENE_STAT(rx_errors), | ||
36 | XGENE_STAT(tx_errors), | ||
37 | XGENE_STAT(rx_length_errors), | ||
38 | XGENE_STAT(rx_crc_errors), | ||
39 | XGENE_STAT(rx_frame_errors), | ||
40 | XGENE_STAT(rx_fifo_errors) | ||
41 | }; | ||
42 | |||
43 | #define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats) | ||
44 | |||
45 | static void xgene_get_drvinfo(struct net_device *ndev, | ||
46 | struct ethtool_drvinfo *info) | ||
47 | { | ||
48 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
49 | struct platform_device *pdev = pdata->pdev; | ||
50 | |||
51 | strcpy(info->driver, "xgene_enet"); | ||
52 | strcpy(info->version, XGENE_DRV_VERSION); | ||
53 | snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "N/A"); | ||
54 | sprintf(info->bus_info, "%s", pdev->name); | ||
55 | } | ||
56 | |||
57 | static int xgene_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) | ||
58 | { | ||
59 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
60 | struct phy_device *phydev = pdata->phy_dev; | ||
61 | |||
62 | if (phydev == NULL) | ||
63 | return -ENODEV; | ||
64 | |||
65 | return phy_ethtool_gset(phydev, cmd); | ||
66 | } | ||
67 | |||
68 | static int xgene_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) | ||
69 | { | ||
70 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
71 | struct phy_device *phydev = pdata->phy_dev; | ||
72 | |||
73 | if (phydev == NULL) | ||
74 | return -ENODEV; | ||
75 | |||
76 | return phy_ethtool_sset(phydev, cmd); | ||
77 | } | ||
78 | |||
79 | static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data) | ||
80 | { | ||
81 | int i; | ||
82 | u8 *p = data; | ||
83 | |||
84 | if (stringset != ETH_SS_STATS) | ||
85 | return; | ||
86 | |||
87 | for (i = 0; i < XGENE_STATS_LEN; i++) { | ||
88 | memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN); | ||
89 | p += ETH_GSTRING_LEN; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static int xgene_get_sset_count(struct net_device *ndev, int sset) | ||
94 | { | ||
95 | if (sset != ETH_SS_STATS) | ||
96 | return -EINVAL; | ||
97 | |||
98 | return XGENE_STATS_LEN; | ||
99 | } | ||
100 | |||
101 | static void xgene_get_ethtool_stats(struct net_device *ndev, | ||
102 | struct ethtool_stats *dummy, | ||
103 | u64 *data) | ||
104 | { | ||
105 | void *pdata = netdev_priv(ndev); | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < XGENE_STATS_LEN; i++) | ||
109 | *data++ = *(u64 *)(pdata + gstrings_stats[i].offset); | ||
110 | } | ||
111 | |||
112 | static const struct ethtool_ops xgene_ethtool_ops = { | ||
113 | .get_drvinfo = xgene_get_drvinfo, | ||
114 | .get_settings = xgene_get_settings, | ||
115 | .set_settings = xgene_set_settings, | ||
116 | .get_link = ethtool_op_get_link, | ||
117 | .get_strings = xgene_get_strings, | ||
118 | .get_sset_count = xgene_get_sset_count, | ||
119 | .get_ethtool_stats = xgene_get_ethtool_stats | ||
120 | }; | ||
121 | |||
122 | void xgene_enet_set_ethtool_ops(struct net_device *ndev) | ||
123 | { | ||
124 | ndev->ethtool_ops = &xgene_ethtool_ops; | ||
125 | } | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c new file mode 100644 index 000000000000..812d8d65159b --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Ravi Patel <rapatel@apm.com> | ||
6 | * Keyur Chudgar <kchudgar@apm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include "xgene_enet_main.h" | ||
23 | #include "xgene_enet_hw.h" | ||
24 | |||
25 | static void xgene_enet_ring_init(struct xgene_enet_desc_ring *ring) | ||
26 | { | ||
27 | u32 *ring_cfg = ring->state; | ||
28 | u64 addr = ring->dma; | ||
29 | enum xgene_enet_ring_cfgsize cfgsize = ring->cfgsize; | ||
30 | |||
31 | ring_cfg[4] |= (1 << SELTHRSH_POS) & | ||
32 | CREATE_MASK(SELTHRSH_POS, SELTHRSH_LEN); | ||
33 | ring_cfg[3] |= ACCEPTLERR; | ||
34 | ring_cfg[2] |= QCOHERENT; | ||
35 | |||
36 | addr >>= 8; | ||
37 | ring_cfg[2] |= (addr << RINGADDRL_POS) & | ||
38 | CREATE_MASK_ULL(RINGADDRL_POS, RINGADDRL_LEN); | ||
39 | addr >>= RINGADDRL_LEN; | ||
40 | ring_cfg[3] |= addr & CREATE_MASK_ULL(RINGADDRH_POS, RINGADDRH_LEN); | ||
41 | ring_cfg[3] |= ((u32)cfgsize << RINGSIZE_POS) & | ||
42 | CREATE_MASK(RINGSIZE_POS, RINGSIZE_LEN); | ||
43 | } | ||
44 | |||
45 | static void xgene_enet_ring_set_type(struct xgene_enet_desc_ring *ring) | ||
46 | { | ||
47 | u32 *ring_cfg = ring->state; | ||
48 | bool is_bufpool; | ||
49 | u32 val; | ||
50 | |||
51 | is_bufpool = xgene_enet_is_bufpool(ring->id); | ||
52 | val = (is_bufpool) ? RING_BUFPOOL : RING_REGULAR; | ||
53 | ring_cfg[4] |= (val << RINGTYPE_POS) & | ||
54 | CREATE_MASK(RINGTYPE_POS, RINGTYPE_LEN); | ||
55 | |||
56 | if (is_bufpool) { | ||
57 | ring_cfg[3] |= (BUFPOOL_MODE << RINGMODE_POS) & | ||
58 | CREATE_MASK(RINGMODE_POS, RINGMODE_LEN); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static void xgene_enet_ring_set_recombbuf(struct xgene_enet_desc_ring *ring) | ||
63 | { | ||
64 | u32 *ring_cfg = ring->state; | ||
65 | |||
66 | ring_cfg[3] |= RECOMBBUF; | ||
67 | ring_cfg[3] |= (0xf << RECOMTIMEOUTL_POS) & | ||
68 | CREATE_MASK(RECOMTIMEOUTL_POS, RECOMTIMEOUTL_LEN); | ||
69 | ring_cfg[4] |= 0x7 & CREATE_MASK(RECOMTIMEOUTH_POS, RECOMTIMEOUTH_LEN); | ||
70 | } | ||
71 | |||
72 | static void xgene_enet_ring_wr32(struct xgene_enet_desc_ring *ring, | ||
73 | u32 offset, u32 data) | ||
74 | { | ||
75 | struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); | ||
76 | |||
77 | iowrite32(data, pdata->ring_csr_addr + offset); | ||
78 | } | ||
79 | |||
80 | static void xgene_enet_ring_rd32(struct xgene_enet_desc_ring *ring, | ||
81 | u32 offset, u32 *data) | ||
82 | { | ||
83 | struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); | ||
84 | |||
85 | *data = ioread32(pdata->ring_csr_addr + offset); | ||
86 | } | ||
87 | |||
88 | static void xgene_enet_write_ring_state(struct xgene_enet_desc_ring *ring) | ||
89 | { | ||
90 | int i; | ||
91 | |||
92 | xgene_enet_ring_wr32(ring, CSR_RING_CONFIG, ring->num); | ||
93 | for (i = 0; i < NUM_RING_CONFIG; i++) { | ||
94 | xgene_enet_ring_wr32(ring, CSR_RING_WR_BASE + (i * 4), | ||
95 | ring->state[i]); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static void xgene_enet_clr_ring_state(struct xgene_enet_desc_ring *ring) | ||
100 | { | ||
101 | memset(ring->state, 0, sizeof(u32) * NUM_RING_CONFIG); | ||
102 | xgene_enet_write_ring_state(ring); | ||
103 | } | ||
104 | |||
105 | static void xgene_enet_set_ring_state(struct xgene_enet_desc_ring *ring) | ||
106 | { | ||
107 | xgene_enet_ring_set_type(ring); | ||
108 | |||
109 | if (xgene_enet_ring_owner(ring->id) == RING_OWNER_ETH0) | ||
110 | xgene_enet_ring_set_recombbuf(ring); | ||
111 | |||
112 | xgene_enet_ring_init(ring); | ||
113 | xgene_enet_write_ring_state(ring); | ||
114 | } | ||
115 | |||
116 | static void xgene_enet_set_ring_id(struct xgene_enet_desc_ring *ring) | ||
117 | { | ||
118 | u32 ring_id_val, ring_id_buf; | ||
119 | bool is_bufpool; | ||
120 | |||
121 | is_bufpool = xgene_enet_is_bufpool(ring->id); | ||
122 | |||
123 | ring_id_val = ring->id & GENMASK(9, 0); | ||
124 | ring_id_val |= OVERWRITE; | ||
125 | |||
126 | ring_id_buf = (ring->num << 9) & GENMASK(18, 9); | ||
127 | ring_id_buf |= PREFETCH_BUF_EN; | ||
128 | if (is_bufpool) | ||
129 | ring_id_buf |= IS_BUFFER_POOL; | ||
130 | |||
131 | xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id_val); | ||
132 | xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, ring_id_buf); | ||
133 | } | ||
134 | |||
135 | static void xgene_enet_clr_desc_ring_id(struct xgene_enet_desc_ring *ring) | ||
136 | { | ||
137 | u32 ring_id; | ||
138 | |||
139 | ring_id = ring->id | OVERWRITE; | ||
140 | xgene_enet_ring_wr32(ring, CSR_RING_ID, ring_id); | ||
141 | xgene_enet_ring_wr32(ring, CSR_RING_ID_BUF, 0); | ||
142 | } | ||
143 | |||
144 | struct xgene_enet_desc_ring *xgene_enet_setup_ring( | ||
145 | struct xgene_enet_desc_ring *ring) | ||
146 | { | ||
147 | u32 size = ring->size; | ||
148 | u32 i, data; | ||
149 | bool is_bufpool; | ||
150 | |||
151 | xgene_enet_clr_ring_state(ring); | ||
152 | xgene_enet_set_ring_state(ring); | ||
153 | xgene_enet_set_ring_id(ring); | ||
154 | |||
155 | ring->slots = xgene_enet_get_numslots(ring->id, size); | ||
156 | |||
157 | is_bufpool = xgene_enet_is_bufpool(ring->id); | ||
158 | if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU) | ||
159 | return ring; | ||
160 | |||
161 | for (i = 0; i < ring->slots; i++) | ||
162 | xgene_enet_mark_desc_slot_empty(&ring->raw_desc[i]); | ||
163 | |||
164 | xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data); | ||
165 | data |= BIT(31 - xgene_enet_ring_bufnum(ring->id)); | ||
166 | xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data); | ||
167 | |||
168 | return ring; | ||
169 | } | ||
170 | |||
171 | void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring) | ||
172 | { | ||
173 | u32 data; | ||
174 | bool is_bufpool; | ||
175 | |||
176 | is_bufpool = xgene_enet_is_bufpool(ring->id); | ||
177 | if (is_bufpool || xgene_enet_ring_owner(ring->id) != RING_OWNER_CPU) | ||
178 | goto out; | ||
179 | |||
180 | xgene_enet_ring_rd32(ring, CSR_RING_NE_INT_MODE, &data); | ||
181 | data &= ~BIT(31 - xgene_enet_ring_bufnum(ring->id)); | ||
182 | xgene_enet_ring_wr32(ring, CSR_RING_NE_INT_MODE, data); | ||
183 | |||
184 | out: | ||
185 | xgene_enet_clr_desc_ring_id(ring); | ||
186 | xgene_enet_clr_ring_state(ring); | ||
187 | } | ||
188 | |||
189 | void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, | ||
190 | struct xgene_enet_pdata *pdata, | ||
191 | enum xgene_enet_err_code status) | ||
192 | { | ||
193 | struct rtnl_link_stats64 *stats = &pdata->stats; | ||
194 | |||
195 | switch (status) { | ||
196 | case INGRESS_CRC: | ||
197 | stats->rx_crc_errors++; | ||
198 | break; | ||
199 | case INGRESS_CHECKSUM: | ||
200 | case INGRESS_CHECKSUM_COMPUTE: | ||
201 | stats->rx_errors++; | ||
202 | break; | ||
203 | case INGRESS_TRUNC_FRAME: | ||
204 | stats->rx_frame_errors++; | ||
205 | break; | ||
206 | case INGRESS_PKT_LEN: | ||
207 | stats->rx_length_errors++; | ||
208 | break; | ||
209 | case INGRESS_PKT_UNDER: | ||
210 | stats->rx_frame_errors++; | ||
211 | break; | ||
212 | case INGRESS_FIFO_OVERRUN: | ||
213 | stats->rx_fifo_errors++; | ||
214 | break; | ||
215 | default: | ||
216 | break; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | static void xgene_enet_wr_csr(struct xgene_enet_pdata *pdata, | ||
221 | u32 offset, u32 val) | ||
222 | { | ||
223 | void __iomem *addr = pdata->eth_csr_addr + offset; | ||
224 | |||
225 | iowrite32(val, addr); | ||
226 | } | ||
227 | |||
228 | static void xgene_enet_wr_ring_if(struct xgene_enet_pdata *pdata, | ||
229 | u32 offset, u32 val) | ||
230 | { | ||
231 | void __iomem *addr = pdata->eth_ring_if_addr + offset; | ||
232 | |||
233 | iowrite32(val, addr); | ||
234 | } | ||
235 | |||
236 | static void xgene_enet_wr_diag_csr(struct xgene_enet_pdata *pdata, | ||
237 | u32 offset, u32 val) | ||
238 | { | ||
239 | void __iomem *addr = pdata->eth_diag_csr_addr + offset; | ||
240 | |||
241 | iowrite32(val, addr); | ||
242 | } | ||
243 | |||
244 | static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata, | ||
245 | u32 offset, u32 val) | ||
246 | { | ||
247 | void __iomem *addr = pdata->mcx_mac_csr_addr + offset; | ||
248 | |||
249 | iowrite32(val, addr); | ||
250 | } | ||
251 | |||
252 | static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr, | ||
253 | void __iomem *cmd, void __iomem *cmd_done, | ||
254 | u32 wr_addr, u32 wr_data) | ||
255 | { | ||
256 | u32 done; | ||
257 | u8 wait = 10; | ||
258 | |||
259 | iowrite32(wr_addr, addr); | ||
260 | iowrite32(wr_data, wr); | ||
261 | iowrite32(XGENE_ENET_WR_CMD, cmd); | ||
262 | |||
263 | /* wait for write command to complete */ | ||
264 | while (!(done = ioread32(cmd_done)) && wait--) | ||
265 | udelay(1); | ||
266 | |||
267 | if (!done) | ||
268 | return false; | ||
269 | |||
270 | iowrite32(0, cmd); | ||
271 | |||
272 | return true; | ||
273 | } | ||
274 | |||
275 | static void xgene_enet_wr_mcx_mac(struct xgene_enet_pdata *pdata, | ||
276 | u32 wr_addr, u32 wr_data) | ||
277 | { | ||
278 | void __iomem *addr, *wr, *cmd, *cmd_done; | ||
279 | |||
280 | addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; | ||
281 | wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET; | ||
282 | cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; | ||
283 | cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
284 | |||
285 | if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data)) | ||
286 | netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n", | ||
287 | wr_addr); | ||
288 | } | ||
289 | |||
290 | static void xgene_enet_rd_csr(struct xgene_enet_pdata *pdata, | ||
291 | u32 offset, u32 *val) | ||
292 | { | ||
293 | void __iomem *addr = pdata->eth_csr_addr + offset; | ||
294 | |||
295 | *val = ioread32(addr); | ||
296 | } | ||
297 | |||
298 | static void xgene_enet_rd_diag_csr(struct xgene_enet_pdata *pdata, | ||
299 | u32 offset, u32 *val) | ||
300 | { | ||
301 | void __iomem *addr = pdata->eth_diag_csr_addr + offset; | ||
302 | |||
303 | *val = ioread32(addr); | ||
304 | } | ||
305 | |||
306 | static void xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *pdata, | ||
307 | u32 offset, u32 *val) | ||
308 | { | ||
309 | void __iomem *addr = pdata->mcx_mac_csr_addr + offset; | ||
310 | |||
311 | *val = ioread32(addr); | ||
312 | } | ||
313 | |||
314 | static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd, | ||
315 | void __iomem *cmd, void __iomem *cmd_done, | ||
316 | u32 rd_addr, u32 *rd_data) | ||
317 | { | ||
318 | u32 done; | ||
319 | u8 wait = 10; | ||
320 | |||
321 | iowrite32(rd_addr, addr); | ||
322 | iowrite32(XGENE_ENET_RD_CMD, cmd); | ||
323 | |||
324 | /* wait for read command to complete */ | ||
325 | while (!(done = ioread32(cmd_done)) && wait--) | ||
326 | udelay(1); | ||
327 | |||
328 | if (!done) | ||
329 | return false; | ||
330 | |||
331 | *rd_data = ioread32(rd); | ||
332 | iowrite32(0, cmd); | ||
333 | |||
334 | return true; | ||
335 | } | ||
336 | |||
337 | static void xgene_enet_rd_mcx_mac(struct xgene_enet_pdata *pdata, | ||
338 | u32 rd_addr, u32 *rd_data) | ||
339 | { | ||
340 | void __iomem *addr, *rd, *cmd, *cmd_done; | ||
341 | |||
342 | addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET; | ||
343 | rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET; | ||
344 | cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET; | ||
345 | cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET; | ||
346 | |||
347 | if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data)) | ||
348 | netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n", | ||
349 | rd_addr); | ||
350 | } | ||
351 | |||
352 | static int xgene_mii_phy_write(struct xgene_enet_pdata *pdata, int phy_id, | ||
353 | u32 reg, u16 data) | ||
354 | { | ||
355 | u32 addr = 0, wr_data = 0; | ||
356 | u32 done; | ||
357 | u8 wait = 10; | ||
358 | |||
359 | PHY_ADDR_SET(&addr, phy_id); | ||
360 | REG_ADDR_SET(&addr, reg); | ||
361 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); | ||
362 | |||
363 | PHY_CONTROL_SET(&wr_data, data); | ||
364 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONTROL_ADDR, wr_data); | ||
365 | do { | ||
366 | usleep_range(5, 10); | ||
367 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); | ||
368 | } while ((done & BUSY_MASK) && wait--); | ||
369 | |||
370 | if (done & BUSY_MASK) { | ||
371 | netdev_err(pdata->ndev, "MII_MGMT write failed\n"); | ||
372 | return -EBUSY; | ||
373 | } | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int xgene_mii_phy_read(struct xgene_enet_pdata *pdata, | ||
379 | u8 phy_id, u32 reg) | ||
380 | { | ||
381 | u32 addr = 0; | ||
382 | u32 data, done; | ||
383 | u8 wait = 10; | ||
384 | |||
385 | PHY_ADDR_SET(&addr, phy_id); | ||
386 | REG_ADDR_SET(&addr, reg); | ||
387 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_ADDRESS_ADDR, addr); | ||
388 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK); | ||
389 | do { | ||
390 | usleep_range(5, 10); | ||
391 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_INDICATORS_ADDR, &done); | ||
392 | } while ((done & BUSY_MASK) && wait--); | ||
393 | |||
394 | if (done & BUSY_MASK) { | ||
395 | netdev_err(pdata->ndev, "MII_MGMT read failed\n"); | ||
396 | return -EBUSY; | ||
397 | } | ||
398 | |||
399 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_STATUS_ADDR, &data); | ||
400 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_COMMAND_ADDR, 0); | ||
401 | |||
402 | return data; | ||
403 | } | ||
404 | |||
405 | void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata) | ||
406 | { | ||
407 | u32 addr0, addr1; | ||
408 | u8 *dev_addr = pdata->ndev->dev_addr; | ||
409 | |||
410 | addr0 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | | ||
411 | (dev_addr[1] << 8) | dev_addr[0]; | ||
412 | addr1 = (dev_addr[5] << 24) | (dev_addr[4] << 16); | ||
413 | addr1 |= pdata->phy_addr & 0xFFFF; | ||
414 | |||
415 | xgene_enet_wr_mcx_mac(pdata, STATION_ADDR0_ADDR, addr0); | ||
416 | xgene_enet_wr_mcx_mac(pdata, STATION_ADDR1_ADDR, addr1); | ||
417 | } | ||
418 | |||
419 | static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata) | ||
420 | { | ||
421 | struct net_device *ndev = pdata->ndev; | ||
422 | u32 data; | ||
423 | u8 wait = 10; | ||
424 | |||
425 | xgene_enet_wr_diag_csr(pdata, ENET_CFG_MEM_RAM_SHUTDOWN_ADDR, 0x0); | ||
426 | do { | ||
427 | usleep_range(100, 110); | ||
428 | xgene_enet_rd_diag_csr(pdata, ENET_BLOCK_MEM_RDY_ADDR, &data); | ||
429 | } while ((data != 0xffffffff) && wait--); | ||
430 | |||
431 | if (data != 0xffffffff) { | ||
432 | netdev_err(ndev, "Failed to release memory from shutdown\n"); | ||
433 | return -ENODEV; | ||
434 | } | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | void xgene_gmac_reset(struct xgene_enet_pdata *pdata) | ||
440 | { | ||
441 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET1); | ||
442 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0); | ||
443 | } | ||
444 | |||
445 | void xgene_gmac_init(struct xgene_enet_pdata *pdata, int speed) | ||
446 | { | ||
447 | u32 value, mc2; | ||
448 | u32 intf_ctl, rgmii; | ||
449 | u32 icm0, icm2; | ||
450 | |||
451 | xgene_gmac_reset(pdata); | ||
452 | |||
453 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, &icm0); | ||
454 | xgene_enet_rd_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, &icm2); | ||
455 | xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_2_ADDR, &mc2); | ||
456 | xgene_enet_rd_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, &intf_ctl); | ||
457 | xgene_enet_rd_csr(pdata, RGMII_REG_0_ADDR, &rgmii); | ||
458 | |||
459 | switch (speed) { | ||
460 | case SPEED_10: | ||
461 | ENET_INTERFACE_MODE2_SET(&mc2, 1); | ||
462 | CFG_MACMODE_SET(&icm0, 0); | ||
463 | CFG_WAITASYNCRD_SET(&icm2, 500); | ||
464 | rgmii &= ~CFG_SPEED_1250; | ||
465 | break; | ||
466 | case SPEED_100: | ||
467 | ENET_INTERFACE_MODE2_SET(&mc2, 1); | ||
468 | intf_ctl |= ENET_LHD_MODE; | ||
469 | CFG_MACMODE_SET(&icm0, 1); | ||
470 | CFG_WAITASYNCRD_SET(&icm2, 80); | ||
471 | rgmii &= ~CFG_SPEED_1250; | ||
472 | break; | ||
473 | default: | ||
474 | ENET_INTERFACE_MODE2_SET(&mc2, 2); | ||
475 | intf_ctl |= ENET_GHD_MODE; | ||
476 | CFG_TXCLK_MUXSEL0_SET(&rgmii, 4); | ||
477 | xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value); | ||
478 | value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX; | ||
479 | xgene_enet_wr_csr(pdata, DEBUG_REG_ADDR, value); | ||
480 | break; | ||
481 | } | ||
482 | |||
483 | mc2 |= FULL_DUPLEX2; | ||
484 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2); | ||
485 | xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl); | ||
486 | |||
487 | xgene_gmac_set_mac_addr(pdata); | ||
488 | |||
489 | /* Adjust MDC clock frequency */ | ||
490 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &value); | ||
491 | MGMT_CLOCK_SEL_SET(&value, 7); | ||
492 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, value); | ||
493 | |||
494 | /* Enable drop if bufpool not available */ | ||
495 | xgene_enet_rd_csr(pdata, RSIF_CONFIG_REG_ADDR, &value); | ||
496 | value |= CFG_RSIF_FPBUFF_TIMEOUT_EN; | ||
497 | xgene_enet_wr_csr(pdata, RSIF_CONFIG_REG_ADDR, value); | ||
498 | |||
499 | /* Rtype should be copied from FP */ | ||
500 | xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0); | ||
501 | xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii); | ||
502 | |||
503 | /* Rx-Tx traffic resume */ | ||
504 | xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0); | ||
505 | |||
506 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG0_REG_0_ADDR, icm0); | ||
507 | xgene_enet_wr_mcx_csr(pdata, ICM_CONFIG2_REG_0_ADDR, icm2); | ||
508 | |||
509 | xgene_enet_rd_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, &value); | ||
510 | value &= ~TX_DV_GATE_EN0; | ||
511 | value &= ~RX_DV_GATE_EN0; | ||
512 | value |= RESUME_RX0; | ||
513 | xgene_enet_wr_mcx_csr(pdata, RX_DV_GATE_REG_0_ADDR, value); | ||
514 | |||
515 | xgene_enet_wr_csr(pdata, CFG_BYPASS_ADDR, RESUME_TX); | ||
516 | } | ||
517 | |||
518 | static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata) | ||
519 | { | ||
520 | u32 val = 0xffffffff; | ||
521 | |||
522 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, val); | ||
523 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPQASSOC_ADDR, val); | ||
524 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEWQASSOC_ADDR, val); | ||
525 | xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIQMLITEFPQASSOC_ADDR, val); | ||
526 | } | ||
527 | |||
528 | void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, | ||
529 | u32 dst_ring_num, u16 bufpool_id) | ||
530 | { | ||
531 | u32 cb; | ||
532 | u32 fpsel; | ||
533 | |||
534 | fpsel = xgene_enet_ring_bufnum(bufpool_id) - 0x20; | ||
535 | |||
536 | xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb); | ||
537 | cb |= CFG_CLE_BYPASS_EN0; | ||
538 | CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); | ||
539 | xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb); | ||
540 | |||
541 | xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb); | ||
542 | CFG_CLE_DSTQID0_SET(&cb, dst_ring_num); | ||
543 | CFG_CLE_FPSEL0_SET(&cb, fpsel); | ||
544 | xgene_enet_wr_csr(pdata, CLE_BYPASS_REG1_0_ADDR, cb); | ||
545 | } | ||
546 | |||
547 | void xgene_gmac_rx_enable(struct xgene_enet_pdata *pdata) | ||
548 | { | ||
549 | u32 data; | ||
550 | |||
551 | xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); | ||
552 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | RX_EN); | ||
553 | } | ||
554 | |||
555 | void xgene_gmac_tx_enable(struct xgene_enet_pdata *pdata) | ||
556 | { | ||
557 | u32 data; | ||
558 | |||
559 | xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); | ||
560 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data | TX_EN); | ||
561 | } | ||
562 | |||
563 | void xgene_gmac_rx_disable(struct xgene_enet_pdata *pdata) | ||
564 | { | ||
565 | u32 data; | ||
566 | |||
567 | xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); | ||
568 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~RX_EN); | ||
569 | } | ||
570 | |||
571 | void xgene_gmac_tx_disable(struct xgene_enet_pdata *pdata) | ||
572 | { | ||
573 | u32 data; | ||
574 | |||
575 | xgene_enet_rd_mcx_mac(pdata, MAC_CONFIG_1_ADDR, &data); | ||
576 | xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, data & ~TX_EN); | ||
577 | } | ||
578 | |||
579 | void xgene_enet_reset(struct xgene_enet_pdata *pdata) | ||
580 | { | ||
581 | u32 val; | ||
582 | |||
583 | clk_prepare_enable(pdata->clk); | ||
584 | clk_disable_unprepare(pdata->clk); | ||
585 | clk_prepare_enable(pdata->clk); | ||
586 | xgene_enet_ecc_init(pdata); | ||
587 | xgene_enet_config_ring_if_assoc(pdata); | ||
588 | |||
589 | /* Enable auto-incr for scanning */ | ||
590 | xgene_enet_rd_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, &val); | ||
591 | val |= SCAN_AUTO_INCR; | ||
592 | MGMT_CLOCK_SEL_SET(&val, 1); | ||
593 | xgene_enet_wr_mcx_mac(pdata, MII_MGMT_CONFIG_ADDR, val); | ||
594 | } | ||
595 | |||
596 | void xgene_gport_shutdown(struct xgene_enet_pdata *pdata) | ||
597 | { | ||
598 | clk_disable_unprepare(pdata->clk); | ||
599 | } | ||
600 | |||
601 | static int xgene_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
602 | { | ||
603 | struct xgene_enet_pdata *pdata = bus->priv; | ||
604 | u32 val; | ||
605 | |||
606 | val = xgene_mii_phy_read(pdata, mii_id, regnum); | ||
607 | netdev_dbg(pdata->ndev, "mdio_rd: bus=%d reg=%d val=%x\n", | ||
608 | mii_id, regnum, val); | ||
609 | |||
610 | return val; | ||
611 | } | ||
612 | |||
613 | static int xgene_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, | ||
614 | u16 val) | ||
615 | { | ||
616 | struct xgene_enet_pdata *pdata = bus->priv; | ||
617 | |||
618 | netdev_dbg(pdata->ndev, "mdio_wr: bus=%d reg=%d val=%x\n", | ||
619 | mii_id, regnum, val); | ||
620 | return xgene_mii_phy_write(pdata, mii_id, regnum, val); | ||
621 | } | ||
622 | |||
623 | static void xgene_enet_adjust_link(struct net_device *ndev) | ||
624 | { | ||
625 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
626 | struct phy_device *phydev = pdata->phy_dev; | ||
627 | |||
628 | if (phydev->link) { | ||
629 | if (pdata->phy_speed != phydev->speed) { | ||
630 | xgene_gmac_init(pdata, phydev->speed); | ||
631 | xgene_gmac_rx_enable(pdata); | ||
632 | xgene_gmac_tx_enable(pdata); | ||
633 | pdata->phy_speed = phydev->speed; | ||
634 | phy_print_status(phydev); | ||
635 | } | ||
636 | } else { | ||
637 | xgene_gmac_rx_disable(pdata); | ||
638 | xgene_gmac_tx_disable(pdata); | ||
639 | pdata->phy_speed = SPEED_UNKNOWN; | ||
640 | phy_print_status(phydev); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | static int xgene_enet_phy_connect(struct net_device *ndev) | ||
645 | { | ||
646 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
647 | struct device_node *phy_np; | ||
648 | struct phy_device *phy_dev; | ||
649 | struct device *dev = &pdata->pdev->dev; | ||
650 | |||
651 | phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0); | ||
652 | if (!phy_np) { | ||
653 | netdev_dbg(ndev, "No phy-handle found\n"); | ||
654 | return -ENODEV; | ||
655 | } | ||
656 | |||
657 | phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link, | ||
658 | 0, pdata->phy_mode); | ||
659 | if (!phy_dev) { | ||
660 | netdev_err(ndev, "Could not connect to PHY\n"); | ||
661 | return -ENODEV; | ||
662 | } | ||
663 | |||
664 | pdata->phy_speed = SPEED_UNKNOWN; | ||
665 | phy_dev->supported &= ~SUPPORTED_10baseT_Half & | ||
666 | ~SUPPORTED_100baseT_Half & | ||
667 | ~SUPPORTED_1000baseT_Half; | ||
668 | phy_dev->advertising = phy_dev->supported; | ||
669 | pdata->phy_dev = phy_dev; | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata) | ||
675 | { | ||
676 | struct net_device *ndev = pdata->ndev; | ||
677 | struct device *dev = &pdata->pdev->dev; | ||
678 | struct device_node *child_np; | ||
679 | struct device_node *mdio_np = NULL; | ||
680 | struct mii_bus *mdio_bus; | ||
681 | int ret; | ||
682 | |||
683 | for_each_child_of_node(dev->of_node, child_np) { | ||
684 | if (of_device_is_compatible(child_np, "apm,xgene-mdio")) { | ||
685 | mdio_np = child_np; | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | if (!mdio_np) { | ||
691 | netdev_dbg(ndev, "No mdio node in the dts\n"); | ||
692 | return -ENXIO; | ||
693 | } | ||
694 | |||
695 | mdio_bus = mdiobus_alloc(); | ||
696 | if (!mdio_bus) | ||
697 | return -ENOMEM; | ||
698 | |||
699 | mdio_bus->name = "APM X-Gene MDIO bus"; | ||
700 | mdio_bus->read = xgene_enet_mdio_read; | ||
701 | mdio_bus->write = xgene_enet_mdio_write; | ||
702 | snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "xgene-mii", | ||
703 | ndev->name); | ||
704 | |||
705 | mdio_bus->priv = pdata; | ||
706 | mdio_bus->parent = &ndev->dev; | ||
707 | |||
708 | ret = of_mdiobus_register(mdio_bus, mdio_np); | ||
709 | if (ret) { | ||
710 | netdev_err(ndev, "Failed to register MDIO bus\n"); | ||
711 | mdiobus_free(mdio_bus); | ||
712 | return ret; | ||
713 | } | ||
714 | pdata->mdio_bus = mdio_bus; | ||
715 | |||
716 | ret = xgene_enet_phy_connect(ndev); | ||
717 | if (ret) | ||
718 | xgene_enet_mdio_remove(pdata); | ||
719 | |||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata) | ||
724 | { | ||
725 | mdiobus_unregister(pdata->mdio_bus); | ||
726 | mdiobus_free(pdata->mdio_bus); | ||
727 | pdata->mdio_bus = NULL; | ||
728 | } | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h new file mode 100644 index 000000000000..371e7a5b2507 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | |||
@@ -0,0 +1,337 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Ravi Patel <rapatel@apm.com> | ||
6 | * Keyur Chudgar <kchudgar@apm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #ifndef __XGENE_ENET_HW_H__ | ||
23 | #define __XGENE_ENET_HW_H__ | ||
24 | |||
25 | #include "xgene_enet_main.h" | ||
26 | |||
27 | struct xgene_enet_pdata; | ||
28 | struct xgene_enet_stats; | ||
29 | |||
30 | /* clears and then set bits */ | ||
31 | static inline void xgene_set_bits(u32 *dst, u32 val, u32 start, u32 len) | ||
32 | { | ||
33 | u32 end = start + len - 1; | ||
34 | u32 mask = GENMASK(end, start); | ||
35 | |||
36 | *dst &= ~mask; | ||
37 | *dst |= (val << start) & mask; | ||
38 | } | ||
39 | |||
40 | static inline u32 xgene_get_bits(u32 val, u32 start, u32 end) | ||
41 | { | ||
42 | return (val & GENMASK(end, start)) >> start; | ||
43 | } | ||
44 | |||
45 | #define CSR_RING_ID 0x0008 | ||
46 | #define OVERWRITE BIT(31) | ||
47 | #define IS_BUFFER_POOL BIT(20) | ||
48 | #define PREFETCH_BUF_EN BIT(21) | ||
49 | #define CSR_RING_ID_BUF 0x000c | ||
50 | #define CSR_RING_NE_INT_MODE 0x017c | ||
51 | #define CSR_RING_CONFIG 0x006c | ||
52 | #define CSR_RING_WR_BASE 0x0070 | ||
53 | #define NUM_RING_CONFIG 5 | ||
54 | #define BUFPOOL_MODE 3 | ||
55 | #define RM3 3 | ||
56 | #define INC_DEC_CMD_ADDR 0x002c | ||
57 | #define UDP_HDR_SIZE 2 | ||
58 | #define BUF_LEN_CODE_2K 0x5000 | ||
59 | |||
60 | #define CREATE_MASK(pos, len) GENMASK((pos)+(len)-1, (pos)) | ||
61 | #define CREATE_MASK_ULL(pos, len) GENMASK_ULL((pos)+(len)-1, (pos)) | ||
62 | |||
63 | /* Empty slot soft signature */ | ||
64 | #define EMPTY_SLOT_INDEX 1 | ||
65 | #define EMPTY_SLOT ~0ULL | ||
66 | |||
67 | #define WORK_DESC_SIZE 32 | ||
68 | #define BUFPOOL_DESC_SIZE 16 | ||
69 | |||
70 | #define RING_OWNER_MASK GENMASK(9, 6) | ||
71 | #define RING_BUFNUM_MASK GENMASK(5, 0) | ||
72 | |||
73 | #define SELTHRSH_POS 3 | ||
74 | #define SELTHRSH_LEN 3 | ||
75 | #define RINGADDRL_POS 5 | ||
76 | #define RINGADDRL_LEN 27 | ||
77 | #define RINGADDRH_POS 0 | ||
78 | #define RINGADDRH_LEN 6 | ||
79 | #define RINGSIZE_POS 23 | ||
80 | #define RINGSIZE_LEN 3 | ||
81 | #define RINGTYPE_POS 19 | ||
82 | #define RINGTYPE_LEN 2 | ||
83 | #define RINGMODE_POS 20 | ||
84 | #define RINGMODE_LEN 3 | ||
85 | #define RECOMTIMEOUTL_POS 28 | ||
86 | #define RECOMTIMEOUTL_LEN 3 | ||
87 | #define RECOMTIMEOUTH_POS 0 | ||
88 | #define RECOMTIMEOUTH_LEN 2 | ||
89 | #define NUMMSGSINQ_POS 1 | ||
90 | #define NUMMSGSINQ_LEN 16 | ||
91 | #define ACCEPTLERR BIT(19) | ||
92 | #define QCOHERENT BIT(4) | ||
93 | #define RECOMBBUF BIT(27) | ||
94 | |||
95 | #define BLOCK_ETH_CSR_OFFSET 0x2000 | ||
96 | #define BLOCK_ETH_RING_IF_OFFSET 0x9000 | ||
97 | #define BLOCK_ETH_CLKRST_CSR_OFFSET 0xC000 | ||
98 | #define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000 | ||
99 | |||
100 | #define BLOCK_ETH_MAC_OFFSET 0x0000 | ||
101 | #define BLOCK_ETH_STATS_OFFSET 0x0014 | ||
102 | #define BLOCK_ETH_MAC_CSR_OFFSET 0x2800 | ||
103 | |||
104 | #define MAC_ADDR_REG_OFFSET 0x00 | ||
105 | #define MAC_COMMAND_REG_OFFSET 0x04 | ||
106 | #define MAC_WRITE_REG_OFFSET 0x08 | ||
107 | #define MAC_READ_REG_OFFSET 0x0c | ||
108 | #define MAC_COMMAND_DONE_REG_OFFSET 0x10 | ||
109 | |||
110 | #define STAT_ADDR_REG_OFFSET 0x00 | ||
111 | #define STAT_COMMAND_REG_OFFSET 0x04 | ||
112 | #define STAT_WRITE_REG_OFFSET 0x08 | ||
113 | #define STAT_READ_REG_OFFSET 0x0c | ||
114 | #define STAT_COMMAND_DONE_REG_OFFSET 0x10 | ||
115 | |||
116 | #define MII_MGMT_CONFIG_ADDR 0x20 | ||
117 | #define MII_MGMT_COMMAND_ADDR 0x24 | ||
118 | #define MII_MGMT_ADDRESS_ADDR 0x28 | ||
119 | #define MII_MGMT_CONTROL_ADDR 0x2c | ||
120 | #define MII_MGMT_STATUS_ADDR 0x30 | ||
121 | #define MII_MGMT_INDICATORS_ADDR 0x34 | ||
122 | |||
123 | #define BUSY_MASK BIT(0) | ||
124 | #define READ_CYCLE_MASK BIT(0) | ||
125 | #define PHY_CONTROL_SET(dst, val) xgene_set_bits(dst, val, 0, 16) | ||
126 | |||
127 | #define ENET_SPARE_CFG_REG_ADDR 0x0750 | ||
128 | #define RSIF_CONFIG_REG_ADDR 0x0010 | ||
129 | #define RSIF_RAM_DBG_REG0_ADDR 0x0048 | ||
130 | #define RGMII_REG_0_ADDR 0x07e0 | ||
131 | #define CFG_LINK_AGGR_RESUME_0_ADDR 0x07c8 | ||
132 | #define DEBUG_REG_ADDR 0x0700 | ||
133 | #define CFG_BYPASS_ADDR 0x0294 | ||
134 | #define CLE_BYPASS_REG0_0_ADDR 0x0490 | ||
135 | #define CLE_BYPASS_REG1_0_ADDR 0x0494 | ||
136 | #define CFG_RSIF_FPBUFF_TIMEOUT_EN BIT(31) | ||
137 | #define RESUME_TX BIT(0) | ||
138 | #define CFG_SPEED_1250 BIT(24) | ||
139 | #define TX_PORT0 BIT(0) | ||
140 | #define CFG_BYPASS_UNISEC_TX BIT(2) | ||
141 | #define CFG_BYPASS_UNISEC_RX BIT(1) | ||
142 | #define CFG_CLE_BYPASS_EN0 BIT(31) | ||
143 | #define CFG_TXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 29, 3) | ||
144 | |||
145 | #define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2) | ||
146 | #define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12) | ||
147 | #define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4) | ||
148 | #define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2) | ||
149 | #define CFG_WAITASYNCRD_SET(dst, val) xgene_set_bits(dst, val, 0, 16) | ||
150 | #define ICM_CONFIG0_REG_0_ADDR 0x0400 | ||
151 | #define ICM_CONFIG2_REG_0_ADDR 0x0410 | ||
152 | #define RX_DV_GATE_REG_0_ADDR 0x05fc | ||
153 | #define TX_DV_GATE_EN0 BIT(2) | ||
154 | #define RX_DV_GATE_EN0 BIT(1) | ||
155 | #define RESUME_RX0 BIT(0) | ||
156 | #define ENET_CFGSSQMIWQASSOC_ADDR 0xe0 | ||
157 | #define ENET_CFGSSQMIFPQASSOC_ADDR 0xdc | ||
158 | #define ENET_CFGSSQMIQMLITEFPQASSOC_ADDR 0xf0 | ||
159 | #define ENET_CFGSSQMIQMLITEWQASSOC_ADDR 0xf4 | ||
160 | #define ENET_CFG_MEM_RAM_SHUTDOWN_ADDR 0x70 | ||
161 | #define ENET_BLOCK_MEM_RDY_ADDR 0x74 | ||
162 | #define MAC_CONFIG_1_ADDR 0x00 | ||
163 | #define MAC_CONFIG_2_ADDR 0x04 | ||
164 | #define MAX_FRAME_LEN_ADDR 0x10 | ||
165 | #define INTERFACE_CONTROL_ADDR 0x38 | ||
166 | #define STATION_ADDR0_ADDR 0x40 | ||
167 | #define STATION_ADDR1_ADDR 0x44 | ||
168 | #define PHY_ADDR_SET(dst, val) xgene_set_bits(dst, val, 8, 5) | ||
169 | #define REG_ADDR_SET(dst, val) xgene_set_bits(dst, val, 0, 5) | ||
170 | #define ENET_INTERFACE_MODE2_SET(dst, val) xgene_set_bits(dst, val, 8, 2) | ||
171 | #define MGMT_CLOCK_SEL_SET(dst, val) xgene_set_bits(dst, val, 0, 3) | ||
172 | #define SOFT_RESET1 BIT(31) | ||
173 | #define TX_EN BIT(0) | ||
174 | #define RX_EN BIT(2) | ||
175 | #define ENET_LHD_MODE BIT(25) | ||
176 | #define ENET_GHD_MODE BIT(26) | ||
177 | #define FULL_DUPLEX2 BIT(0) | ||
178 | #define SCAN_AUTO_INCR BIT(5) | ||
179 | #define TBYT_ADDR 0x38 | ||
180 | #define TPKT_ADDR 0x39 | ||
181 | #define TDRP_ADDR 0x45 | ||
182 | #define TFCS_ADDR 0x47 | ||
183 | #define TUND_ADDR 0x4a | ||
184 | |||
185 | #define TSO_IPPROTO_TCP 1 | ||
186 | #define FULL_DUPLEX 2 | ||
187 | |||
188 | #define USERINFO_POS 0 | ||
189 | #define USERINFO_LEN 32 | ||
190 | #define FPQNUM_POS 32 | ||
191 | #define FPQNUM_LEN 12 | ||
192 | #define LERR_POS 60 | ||
193 | #define LERR_LEN 3 | ||
194 | #define STASH_POS 52 | ||
195 | #define STASH_LEN 2 | ||
196 | #define BUFDATALEN_POS 48 | ||
197 | #define BUFDATALEN_LEN 12 | ||
198 | #define DATAADDR_POS 0 | ||
199 | #define DATAADDR_LEN 42 | ||
200 | #define COHERENT_POS 63 | ||
201 | #define HENQNUM_POS 48 | ||
202 | #define HENQNUM_LEN 12 | ||
203 | #define TYPESEL_POS 44 | ||
204 | #define TYPESEL_LEN 4 | ||
205 | #define ETHHDR_POS 12 | ||
206 | #define ETHHDR_LEN 8 | ||
207 | #define IC_POS 35 /* Insert CRC */ | ||
208 | #define TCPHDR_POS 0 | ||
209 | #define TCPHDR_LEN 6 | ||
210 | #define IPHDR_POS 6 | ||
211 | #define IPHDR_LEN 6 | ||
212 | #define EC_POS 22 /* Enable checksum */ | ||
213 | #define EC_LEN 1 | ||
214 | #define IS_POS 24 /* IP protocol select */ | ||
215 | #define IS_LEN 1 | ||
216 | #define TYPE_ETH_WORK_MESSAGE_POS 44 | ||
217 | |||
218 | struct xgene_enet_raw_desc { | ||
219 | __le64 m0; | ||
220 | __le64 m1; | ||
221 | __le64 m2; | ||
222 | __le64 m3; | ||
223 | }; | ||
224 | |||
225 | struct xgene_enet_raw_desc16 { | ||
226 | __le64 m0; | ||
227 | __le64 m1; | ||
228 | }; | ||
229 | |||
230 | static inline void xgene_enet_mark_desc_slot_empty(void *desc_slot_ptr) | ||
231 | { | ||
232 | __le64 *desc_slot = desc_slot_ptr; | ||
233 | |||
234 | desc_slot[EMPTY_SLOT_INDEX] = cpu_to_le64(EMPTY_SLOT); | ||
235 | } | ||
236 | |||
237 | static inline bool xgene_enet_is_desc_slot_empty(void *desc_slot_ptr) | ||
238 | { | ||
239 | __le64 *desc_slot = desc_slot_ptr; | ||
240 | |||
241 | return (desc_slot[EMPTY_SLOT_INDEX] == cpu_to_le64(EMPTY_SLOT)); | ||
242 | } | ||
243 | |||
244 | enum xgene_enet_ring_cfgsize { | ||
245 | RING_CFGSIZE_512B, | ||
246 | RING_CFGSIZE_2KB, | ||
247 | RING_CFGSIZE_16KB, | ||
248 | RING_CFGSIZE_64KB, | ||
249 | RING_CFGSIZE_512KB, | ||
250 | RING_CFGSIZE_INVALID | ||
251 | }; | ||
252 | |||
253 | enum xgene_enet_ring_type { | ||
254 | RING_DISABLED, | ||
255 | RING_REGULAR, | ||
256 | RING_BUFPOOL | ||
257 | }; | ||
258 | |||
259 | enum xgene_ring_owner { | ||
260 | RING_OWNER_ETH0, | ||
261 | RING_OWNER_CPU = 15, | ||
262 | RING_OWNER_INVALID | ||
263 | }; | ||
264 | |||
265 | enum xgene_enet_ring_bufnum { | ||
266 | RING_BUFNUM_REGULAR = 0x0, | ||
267 | RING_BUFNUM_BUFPOOL = 0x20, | ||
268 | RING_BUFNUM_INVALID | ||
269 | }; | ||
270 | |||
271 | enum xgene_enet_cmd { | ||
272 | XGENE_ENET_WR_CMD = BIT(31), | ||
273 | XGENE_ENET_RD_CMD = BIT(30) | ||
274 | }; | ||
275 | |||
276 | enum xgene_enet_err_code { | ||
277 | HBF_READ_DATA = 3, | ||
278 | HBF_LL_READ = 4, | ||
279 | BAD_WORK_MSG = 6, | ||
280 | BUFPOOL_TIMEOUT = 15, | ||
281 | INGRESS_CRC = 16, | ||
282 | INGRESS_CHECKSUM = 17, | ||
283 | INGRESS_TRUNC_FRAME = 18, | ||
284 | INGRESS_PKT_LEN = 19, | ||
285 | INGRESS_PKT_UNDER = 20, | ||
286 | INGRESS_FIFO_OVERRUN = 21, | ||
287 | INGRESS_CHECKSUM_COMPUTE = 26, | ||
288 | ERR_CODE_INVALID | ||
289 | }; | ||
290 | |||
291 | static inline enum xgene_ring_owner xgene_enet_ring_owner(u16 id) | ||
292 | { | ||
293 | return (id & RING_OWNER_MASK) >> 6; | ||
294 | } | ||
295 | |||
296 | static inline u8 xgene_enet_ring_bufnum(u16 id) | ||
297 | { | ||
298 | return id & RING_BUFNUM_MASK; | ||
299 | } | ||
300 | |||
301 | static inline bool xgene_enet_is_bufpool(u16 id) | ||
302 | { | ||
303 | return ((id & RING_BUFNUM_MASK) >= 0x20) ? true : false; | ||
304 | } | ||
305 | |||
306 | static inline u16 xgene_enet_get_numslots(u16 id, u32 size) | ||
307 | { | ||
308 | bool is_bufpool = xgene_enet_is_bufpool(id); | ||
309 | |||
310 | return (is_bufpool) ? size / BUFPOOL_DESC_SIZE : | ||
311 | size / WORK_DESC_SIZE; | ||
312 | } | ||
313 | |||
314 | struct xgene_enet_desc_ring *xgene_enet_setup_ring( | ||
315 | struct xgene_enet_desc_ring *ring); | ||
316 | void xgene_enet_clear_ring(struct xgene_enet_desc_ring *ring); | ||
317 | void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring, | ||
318 | struct xgene_enet_pdata *pdata, | ||
319 | enum xgene_enet_err_code status); | ||
320 | |||
321 | void xgene_enet_reset(struct xgene_enet_pdata *priv); | ||
322 | void xgene_gmac_reset(struct xgene_enet_pdata *priv); | ||
323 | void xgene_gmac_init(struct xgene_enet_pdata *priv, int speed); | ||
324 | void xgene_gmac_tx_enable(struct xgene_enet_pdata *priv); | ||
325 | void xgene_gmac_rx_enable(struct xgene_enet_pdata *priv); | ||
326 | void xgene_gmac_tx_disable(struct xgene_enet_pdata *priv); | ||
327 | void xgene_gmac_rx_disable(struct xgene_enet_pdata *priv); | ||
328 | void xgene_gmac_set_mac_addr(struct xgene_enet_pdata *pdata); | ||
329 | void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, | ||
330 | u32 dst_ring_num, u16 bufpool_id); | ||
331 | void xgene_gport_shutdown(struct xgene_enet_pdata *priv); | ||
332 | void xgene_gmac_get_tx_stats(struct xgene_enet_pdata *pdata); | ||
333 | |||
334 | int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata); | ||
335 | void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata); | ||
336 | |||
337 | #endif /* __XGENE_ENET_HW_H__ */ | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c new file mode 100644 index 000000000000..af7c40ac1455 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Ravi Patel <rapatel@apm.com> | ||
6 | * Keyur Chudgar <kchudgar@apm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include "xgene_enet_main.h" | ||
23 | #include "xgene_enet_hw.h" | ||
24 | |||
25 | static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool) | ||
26 | { | ||
27 | struct xgene_enet_raw_desc16 *raw_desc; | ||
28 | int i; | ||
29 | |||
30 | for (i = 0; i < buf_pool->slots; i++) { | ||
31 | raw_desc = &buf_pool->raw_desc16[i]; | ||
32 | |||
33 | /* Hardware expects descriptor in little endian format */ | ||
34 | raw_desc->m0 = cpu_to_le64(i | | ||
35 | SET_VAL(FPQNUM, buf_pool->dst_ring_num) | | ||
36 | SET_VAL(STASH, 3)); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | static int xgene_enet_refill_bufpool(struct xgene_enet_desc_ring *buf_pool, | ||
41 | u32 nbuf) | ||
42 | { | ||
43 | struct sk_buff *skb; | ||
44 | struct xgene_enet_raw_desc16 *raw_desc; | ||
45 | struct net_device *ndev; | ||
46 | struct device *dev; | ||
47 | dma_addr_t dma_addr; | ||
48 | u32 tail = buf_pool->tail; | ||
49 | u32 slots = buf_pool->slots - 1; | ||
50 | u16 bufdatalen, len; | ||
51 | int i; | ||
52 | |||
53 | ndev = buf_pool->ndev; | ||
54 | dev = ndev_to_dev(buf_pool->ndev); | ||
55 | bufdatalen = BUF_LEN_CODE_2K | (SKB_BUFFER_SIZE & GENMASK(11, 0)); | ||
56 | len = XGENE_ENET_MAX_MTU; | ||
57 | |||
58 | for (i = 0; i < nbuf; i++) { | ||
59 | raw_desc = &buf_pool->raw_desc16[tail]; | ||
60 | |||
61 | skb = netdev_alloc_skb_ip_align(ndev, len); | ||
62 | if (unlikely(!skb)) | ||
63 | return -ENOMEM; | ||
64 | buf_pool->rx_skb[tail] = skb; | ||
65 | |||
66 | dma_addr = dma_map_single(dev, skb->data, len, DMA_FROM_DEVICE); | ||
67 | if (dma_mapping_error(dev, dma_addr)) { | ||
68 | netdev_err(ndev, "DMA mapping error\n"); | ||
69 | dev_kfree_skb_any(skb); | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | |||
73 | raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | | ||
74 | SET_VAL(BUFDATALEN, bufdatalen) | | ||
75 | SET_BIT(COHERENT)); | ||
76 | tail = (tail + 1) & slots; | ||
77 | } | ||
78 | |||
79 | iowrite32(nbuf, buf_pool->cmd); | ||
80 | buf_pool->tail = tail; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring) | ||
86 | { | ||
87 | struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); | ||
88 | |||
89 | return ((u16)pdata->rm << 10) | ring->num; | ||
90 | } | ||
91 | |||
92 | static u8 xgene_enet_hdr_len(const void *data) | ||
93 | { | ||
94 | const struct ethhdr *eth = data; | ||
95 | |||
96 | return (eth->h_proto == htons(ETH_P_8021Q)) ? VLAN_ETH_HLEN : ETH_HLEN; | ||
97 | } | ||
98 | |||
99 | static u32 xgene_enet_ring_len(struct xgene_enet_desc_ring *ring) | ||
100 | { | ||
101 | u32 __iomem *cmd_base = ring->cmd_base; | ||
102 | u32 ring_state, num_msgs; | ||
103 | |||
104 | ring_state = ioread32(&cmd_base[1]); | ||
105 | num_msgs = ring_state & CREATE_MASK(NUMMSGSINQ_POS, NUMMSGSINQ_LEN); | ||
106 | |||
107 | return num_msgs >> NUMMSGSINQ_POS; | ||
108 | } | ||
109 | |||
110 | static void xgene_enet_delete_bufpool(struct xgene_enet_desc_ring *buf_pool) | ||
111 | { | ||
112 | struct xgene_enet_raw_desc16 *raw_desc; | ||
113 | u32 slots = buf_pool->slots - 1; | ||
114 | u32 tail = buf_pool->tail; | ||
115 | u32 userinfo; | ||
116 | int i, len; | ||
117 | |||
118 | len = xgene_enet_ring_len(buf_pool); | ||
119 | for (i = 0; i < len; i++) { | ||
120 | tail = (tail - 1) & slots; | ||
121 | raw_desc = &buf_pool->raw_desc16[tail]; | ||
122 | |||
123 | /* Hardware stores descriptor in little endian format */ | ||
124 | userinfo = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); | ||
125 | dev_kfree_skb_any(buf_pool->rx_skb[userinfo]); | ||
126 | } | ||
127 | |||
128 | iowrite32(-len, buf_pool->cmd); | ||
129 | buf_pool->tail = tail; | ||
130 | } | ||
131 | |||
132 | static irqreturn_t xgene_enet_rx_irq(const int irq, void *data) | ||
133 | { | ||
134 | struct xgene_enet_desc_ring *rx_ring = data; | ||
135 | |||
136 | if (napi_schedule_prep(&rx_ring->napi)) { | ||
137 | disable_irq_nosync(irq); | ||
138 | __napi_schedule(&rx_ring->napi); | ||
139 | } | ||
140 | |||
141 | return IRQ_HANDLED; | ||
142 | } | ||
143 | |||
144 | static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, | ||
145 | struct xgene_enet_raw_desc *raw_desc) | ||
146 | { | ||
147 | struct sk_buff *skb; | ||
148 | struct device *dev; | ||
149 | u16 skb_index; | ||
150 | u8 status; | ||
151 | int ret = 0; | ||
152 | |||
153 | skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); | ||
154 | skb = cp_ring->cp_skb[skb_index]; | ||
155 | |||
156 | dev = ndev_to_dev(cp_ring->ndev); | ||
157 | dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)), | ||
158 | GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)), | ||
159 | DMA_TO_DEVICE); | ||
160 | |||
161 | /* Checking for error */ | ||
162 | status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); | ||
163 | if (unlikely(status > 2)) { | ||
164 | xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev), | ||
165 | status); | ||
166 | ret = -EIO; | ||
167 | } | ||
168 | |||
169 | if (likely(skb)) { | ||
170 | dev_kfree_skb_any(skb); | ||
171 | } else { | ||
172 | netdev_err(cp_ring->ndev, "completion skb is NULL\n"); | ||
173 | ret = -EIO; | ||
174 | } | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static u64 xgene_enet_work_msg(struct sk_buff *skb) | ||
180 | { | ||
181 | struct iphdr *iph; | ||
182 | u8 l3hlen, l4hlen = 0; | ||
183 | u8 csum_enable = 0; | ||
184 | u8 proto = 0; | ||
185 | u8 ethhdr; | ||
186 | u64 hopinfo; | ||
187 | |||
188 | if (unlikely(skb->protocol != htons(ETH_P_IP)) && | ||
189 | unlikely(skb->protocol != htons(ETH_P_8021Q))) | ||
190 | goto out; | ||
191 | |||
192 | if (unlikely(!(skb->dev->features & NETIF_F_IP_CSUM))) | ||
193 | goto out; | ||
194 | |||
195 | iph = ip_hdr(skb); | ||
196 | if (unlikely(ip_is_fragment(iph))) | ||
197 | goto out; | ||
198 | |||
199 | if (likely(iph->protocol == IPPROTO_TCP)) { | ||
200 | l4hlen = tcp_hdrlen(skb) >> 2; | ||
201 | csum_enable = 1; | ||
202 | proto = TSO_IPPROTO_TCP; | ||
203 | } else if (iph->protocol == IPPROTO_UDP) { | ||
204 | l4hlen = UDP_HDR_SIZE; | ||
205 | csum_enable = 1; | ||
206 | } | ||
207 | out: | ||
208 | l3hlen = ip_hdrlen(skb) >> 2; | ||
209 | ethhdr = xgene_enet_hdr_len(skb->data); | ||
210 | hopinfo = SET_VAL(TCPHDR, l4hlen) | | ||
211 | SET_VAL(IPHDR, l3hlen) | | ||
212 | SET_VAL(ETHHDR, ethhdr) | | ||
213 | SET_VAL(EC, csum_enable) | | ||
214 | SET_VAL(IS, proto) | | ||
215 | SET_BIT(IC) | | ||
216 | SET_BIT(TYPE_ETH_WORK_MESSAGE); | ||
217 | |||
218 | return hopinfo; | ||
219 | } | ||
220 | |||
221 | static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, | ||
222 | struct sk_buff *skb) | ||
223 | { | ||
224 | struct device *dev = ndev_to_dev(tx_ring->ndev); | ||
225 | struct xgene_enet_raw_desc *raw_desc; | ||
226 | dma_addr_t dma_addr; | ||
227 | u16 tail = tx_ring->tail; | ||
228 | u64 hopinfo; | ||
229 | |||
230 | raw_desc = &tx_ring->raw_desc[tail]; | ||
231 | memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc)); | ||
232 | |||
233 | dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); | ||
234 | if (dma_mapping_error(dev, dma_addr)) { | ||
235 | netdev_err(tx_ring->ndev, "DMA mapping error\n"); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | /* Hardware expects descriptor in little endian format */ | ||
240 | raw_desc->m0 = cpu_to_le64(tail); | ||
241 | raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | | ||
242 | SET_VAL(BUFDATALEN, skb->len) | | ||
243 | SET_BIT(COHERENT)); | ||
244 | hopinfo = xgene_enet_work_msg(skb); | ||
245 | raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | | ||
246 | hopinfo); | ||
247 | tx_ring->cp_ring->cp_skb[tail] = skb; | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, | ||
253 | struct net_device *ndev) | ||
254 | { | ||
255 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
256 | struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring; | ||
257 | struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring; | ||
258 | u32 tx_level, cq_level; | ||
259 | |||
260 | tx_level = xgene_enet_ring_len(tx_ring); | ||
261 | cq_level = xgene_enet_ring_len(cp_ring); | ||
262 | if (unlikely(tx_level > pdata->tx_qcnt_hi || | ||
263 | cq_level > pdata->cp_qcnt_hi)) { | ||
264 | netif_stop_queue(ndev); | ||
265 | return NETDEV_TX_BUSY; | ||
266 | } | ||
267 | |||
268 | if (xgene_enet_setup_tx_desc(tx_ring, skb)) { | ||
269 | dev_kfree_skb_any(skb); | ||
270 | return NETDEV_TX_OK; | ||
271 | } | ||
272 | |||
273 | iowrite32(1, tx_ring->cmd); | ||
274 | skb_tx_timestamp(skb); | ||
275 | tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1); | ||
276 | |||
277 | pdata->stats.tx_packets++; | ||
278 | pdata->stats.tx_bytes += skb->len; | ||
279 | |||
280 | return NETDEV_TX_OK; | ||
281 | } | ||
282 | |||
283 | static void xgene_enet_skip_csum(struct sk_buff *skb) | ||
284 | { | ||
285 | struct iphdr *iph = ip_hdr(skb); | ||
286 | |||
287 | if (!ip_is_fragment(iph) || | ||
288 | (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) { | ||
289 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
290 | } | ||
291 | } | ||
292 | |||
293 | static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, | ||
294 | struct xgene_enet_raw_desc *raw_desc) | ||
295 | { | ||
296 | struct net_device *ndev; | ||
297 | struct xgene_enet_pdata *pdata; | ||
298 | struct device *dev; | ||
299 | struct xgene_enet_desc_ring *buf_pool; | ||
300 | u32 datalen, skb_index; | ||
301 | struct sk_buff *skb; | ||
302 | u8 status; | ||
303 | int ret = 0; | ||
304 | |||
305 | ndev = rx_ring->ndev; | ||
306 | pdata = netdev_priv(ndev); | ||
307 | dev = ndev_to_dev(rx_ring->ndev); | ||
308 | buf_pool = rx_ring->buf_pool; | ||
309 | |||
310 | dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)), | ||
311 | XGENE_ENET_MAX_MTU, DMA_FROM_DEVICE); | ||
312 | skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); | ||
313 | skb = buf_pool->rx_skb[skb_index]; | ||
314 | |||
315 | /* checking for error */ | ||
316 | status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); | ||
317 | if (unlikely(status > 2)) { | ||
318 | dev_kfree_skb_any(skb); | ||
319 | xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev), | ||
320 | status); | ||
321 | pdata->stats.rx_dropped++; | ||
322 | ret = -EIO; | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | /* strip off CRC as HW isn't doing this */ | ||
327 | datalen = GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)); | ||
328 | datalen -= 4; | ||
329 | prefetch(skb->data - NET_IP_ALIGN); | ||
330 | skb_put(skb, datalen); | ||
331 | |||
332 | skb_checksum_none_assert(skb); | ||
333 | skb->protocol = eth_type_trans(skb, ndev); | ||
334 | if (likely((ndev->features & NETIF_F_IP_CSUM) && | ||
335 | skb->protocol == htons(ETH_P_IP))) { | ||
336 | xgene_enet_skip_csum(skb); | ||
337 | } | ||
338 | |||
339 | pdata->stats.rx_packets++; | ||
340 | pdata->stats.rx_bytes += datalen; | ||
341 | napi_gro_receive(&rx_ring->napi, skb); | ||
342 | out: | ||
343 | if (--rx_ring->nbufpool == 0) { | ||
344 | ret = xgene_enet_refill_bufpool(buf_pool, NUM_BUFPOOL); | ||
345 | rx_ring->nbufpool = NUM_BUFPOOL; | ||
346 | } | ||
347 | |||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static bool is_rx_desc(struct xgene_enet_raw_desc *raw_desc) | ||
352 | { | ||
353 | return GET_VAL(FPQNUM, le64_to_cpu(raw_desc->m0)) ? true : false; | ||
354 | } | ||
355 | |||
356 | static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, | ||
357 | int budget) | ||
358 | { | ||
359 | struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); | ||
360 | struct xgene_enet_raw_desc *raw_desc; | ||
361 | u16 head = ring->head; | ||
362 | u16 slots = ring->slots - 1; | ||
363 | int ret, count = 0; | ||
364 | |||
365 | do { | ||
366 | raw_desc = &ring->raw_desc[head]; | ||
367 | if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc))) | ||
368 | break; | ||
369 | |||
370 | if (is_rx_desc(raw_desc)) | ||
371 | ret = xgene_enet_rx_frame(ring, raw_desc); | ||
372 | else | ||
373 | ret = xgene_enet_tx_completion(ring, raw_desc); | ||
374 | xgene_enet_mark_desc_slot_empty(raw_desc); | ||
375 | |||
376 | head = (head + 1) & slots; | ||
377 | count++; | ||
378 | |||
379 | if (ret) | ||
380 | break; | ||
381 | } while (--budget); | ||
382 | |||
383 | if (likely(count)) { | ||
384 | iowrite32(-count, ring->cmd); | ||
385 | ring->head = head; | ||
386 | |||
387 | if (netif_queue_stopped(ring->ndev)) { | ||
388 | if (xgene_enet_ring_len(ring) < pdata->cp_qcnt_low) | ||
389 | netif_wake_queue(ring->ndev); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return budget; | ||
394 | } | ||
395 | |||
396 | static int xgene_enet_napi(struct napi_struct *napi, const int budget) | ||
397 | { | ||
398 | struct xgene_enet_desc_ring *ring; | ||
399 | int processed; | ||
400 | |||
401 | ring = container_of(napi, struct xgene_enet_desc_ring, napi); | ||
402 | processed = xgene_enet_process_ring(ring, budget); | ||
403 | |||
404 | if (processed != budget) { | ||
405 | napi_complete(napi); | ||
406 | enable_irq(ring->irq); | ||
407 | } | ||
408 | |||
409 | return processed; | ||
410 | } | ||
411 | |||
412 | static void xgene_enet_timeout(struct net_device *ndev) | ||
413 | { | ||
414 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
415 | |||
416 | xgene_gmac_reset(pdata); | ||
417 | } | ||
418 | |||
419 | static int xgene_enet_register_irq(struct net_device *ndev) | ||
420 | { | ||
421 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
422 | struct device *dev = ndev_to_dev(ndev); | ||
423 | int ret; | ||
424 | |||
425 | ret = devm_request_irq(dev, pdata->rx_ring->irq, xgene_enet_rx_irq, | ||
426 | IRQF_SHARED, ndev->name, pdata->rx_ring); | ||
427 | if (ret) { | ||
428 | netdev_err(ndev, "rx%d interrupt request failed\n", | ||
429 | pdata->rx_ring->irq); | ||
430 | } | ||
431 | |||
432 | return ret; | ||
433 | } | ||
434 | |||
435 | static void xgene_enet_free_irq(struct net_device *ndev) | ||
436 | { | ||
437 | struct xgene_enet_pdata *pdata; | ||
438 | struct device *dev; | ||
439 | |||
440 | pdata = netdev_priv(ndev); | ||
441 | dev = ndev_to_dev(ndev); | ||
442 | devm_free_irq(dev, pdata->rx_ring->irq, pdata->rx_ring); | ||
443 | } | ||
444 | |||
445 | static int xgene_enet_open(struct net_device *ndev) | ||
446 | { | ||
447 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
448 | int ret; | ||
449 | |||
450 | xgene_gmac_tx_enable(pdata); | ||
451 | xgene_gmac_rx_enable(pdata); | ||
452 | |||
453 | ret = xgene_enet_register_irq(ndev); | ||
454 | if (ret) | ||
455 | return ret; | ||
456 | napi_enable(&pdata->rx_ring->napi); | ||
457 | |||
458 | if (pdata->phy_dev) | ||
459 | phy_start(pdata->phy_dev); | ||
460 | |||
461 | netif_start_queue(ndev); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | static int xgene_enet_close(struct net_device *ndev) | ||
467 | { | ||
468 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
469 | |||
470 | netif_stop_queue(ndev); | ||
471 | |||
472 | if (pdata->phy_dev) | ||
473 | phy_stop(pdata->phy_dev); | ||
474 | |||
475 | napi_disable(&pdata->rx_ring->napi); | ||
476 | xgene_enet_free_irq(ndev); | ||
477 | xgene_enet_process_ring(pdata->rx_ring, -1); | ||
478 | |||
479 | xgene_gmac_tx_disable(pdata); | ||
480 | xgene_gmac_rx_disable(pdata); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static void xgene_enet_delete_ring(struct xgene_enet_desc_ring *ring) | ||
486 | { | ||
487 | struct xgene_enet_pdata *pdata; | ||
488 | struct device *dev; | ||
489 | |||
490 | pdata = netdev_priv(ring->ndev); | ||
491 | dev = ndev_to_dev(ring->ndev); | ||
492 | |||
493 | xgene_enet_clear_ring(ring); | ||
494 | dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); | ||
495 | } | ||
496 | |||
497 | static void xgene_enet_delete_desc_rings(struct xgene_enet_pdata *pdata) | ||
498 | { | ||
499 | struct xgene_enet_desc_ring *buf_pool; | ||
500 | |||
501 | if (pdata->tx_ring) { | ||
502 | xgene_enet_delete_ring(pdata->tx_ring); | ||
503 | pdata->tx_ring = NULL; | ||
504 | } | ||
505 | |||
506 | if (pdata->rx_ring) { | ||
507 | buf_pool = pdata->rx_ring->buf_pool; | ||
508 | xgene_enet_delete_bufpool(buf_pool); | ||
509 | xgene_enet_delete_ring(buf_pool); | ||
510 | xgene_enet_delete_ring(pdata->rx_ring); | ||
511 | pdata->rx_ring = NULL; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | static int xgene_enet_get_ring_size(struct device *dev, | ||
516 | enum xgene_enet_ring_cfgsize cfgsize) | ||
517 | { | ||
518 | int size = -EINVAL; | ||
519 | |||
520 | switch (cfgsize) { | ||
521 | case RING_CFGSIZE_512B: | ||
522 | size = 0x200; | ||
523 | break; | ||
524 | case RING_CFGSIZE_2KB: | ||
525 | size = 0x800; | ||
526 | break; | ||
527 | case RING_CFGSIZE_16KB: | ||
528 | size = 0x4000; | ||
529 | break; | ||
530 | case RING_CFGSIZE_64KB: | ||
531 | size = 0x10000; | ||
532 | break; | ||
533 | case RING_CFGSIZE_512KB: | ||
534 | size = 0x80000; | ||
535 | break; | ||
536 | default: | ||
537 | dev_err(dev, "Unsupported cfg ring size %d\n", cfgsize); | ||
538 | break; | ||
539 | } | ||
540 | |||
541 | return size; | ||
542 | } | ||
543 | |||
544 | static void xgene_enet_free_desc_ring(struct xgene_enet_desc_ring *ring) | ||
545 | { | ||
546 | struct device *dev; | ||
547 | |||
548 | if (!ring) | ||
549 | return; | ||
550 | |||
551 | dev = ndev_to_dev(ring->ndev); | ||
552 | |||
553 | if (ring->desc_addr) { | ||
554 | xgene_enet_clear_ring(ring); | ||
555 | dma_free_coherent(dev, ring->size, ring->desc_addr, ring->dma); | ||
556 | } | ||
557 | devm_kfree(dev, ring); | ||
558 | } | ||
559 | |||
560 | static void xgene_enet_free_desc_rings(struct xgene_enet_pdata *pdata) | ||
561 | { | ||
562 | struct device *dev = &pdata->pdev->dev; | ||
563 | struct xgene_enet_desc_ring *ring; | ||
564 | |||
565 | ring = pdata->tx_ring; | ||
566 | if (ring && ring->cp_ring && ring->cp_ring->cp_skb) | ||
567 | devm_kfree(dev, ring->cp_ring->cp_skb); | ||
568 | xgene_enet_free_desc_ring(ring); | ||
569 | |||
570 | ring = pdata->rx_ring; | ||
571 | if (ring && ring->buf_pool && ring->buf_pool->rx_skb) | ||
572 | devm_kfree(dev, ring->buf_pool->rx_skb); | ||
573 | xgene_enet_free_desc_ring(ring->buf_pool); | ||
574 | xgene_enet_free_desc_ring(ring); | ||
575 | } | ||
576 | |||
577 | static struct xgene_enet_desc_ring *xgene_enet_create_desc_ring( | ||
578 | struct net_device *ndev, u32 ring_num, | ||
579 | enum xgene_enet_ring_cfgsize cfgsize, u32 ring_id) | ||
580 | { | ||
581 | struct xgene_enet_desc_ring *ring; | ||
582 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
583 | struct device *dev = ndev_to_dev(ndev); | ||
584 | u32 size; | ||
585 | |||
586 | ring = devm_kzalloc(dev, sizeof(struct xgene_enet_desc_ring), | ||
587 | GFP_KERNEL); | ||
588 | if (!ring) | ||
589 | return NULL; | ||
590 | |||
591 | ring->ndev = ndev; | ||
592 | ring->num = ring_num; | ||
593 | ring->cfgsize = cfgsize; | ||
594 | ring->id = ring_id; | ||
595 | |||
596 | size = xgene_enet_get_ring_size(dev, cfgsize); | ||
597 | ring->desc_addr = dma_zalloc_coherent(dev, size, &ring->dma, | ||
598 | GFP_KERNEL); | ||
599 | if (!ring->desc_addr) { | ||
600 | devm_kfree(dev, ring); | ||
601 | return NULL; | ||
602 | } | ||
603 | ring->size = size; | ||
604 | |||
605 | ring->cmd_base = pdata->ring_cmd_addr + (ring->num << 6); | ||
606 | ring->cmd = ring->cmd_base + INC_DEC_CMD_ADDR; | ||
607 | pdata->rm = RM3; | ||
608 | ring = xgene_enet_setup_ring(ring); | ||
609 | netdev_dbg(ndev, "ring info: num=%d size=%d id=%d slots=%d\n", | ||
610 | ring->num, ring->size, ring->id, ring->slots); | ||
611 | |||
612 | return ring; | ||
613 | } | ||
614 | |||
615 | static u16 xgene_enet_get_ring_id(enum xgene_ring_owner owner, u8 bufnum) | ||
616 | { | ||
617 | return (owner << 6) | (bufnum & GENMASK(5, 0)); | ||
618 | } | ||
619 | |||
620 | static int xgene_enet_create_desc_rings(struct net_device *ndev) | ||
621 | { | ||
622 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
623 | struct device *dev = ndev_to_dev(ndev); | ||
624 | struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring; | ||
625 | struct xgene_enet_desc_ring *buf_pool = NULL; | ||
626 | u8 cpu_bufnum = 0, eth_bufnum = 0; | ||
627 | u8 bp_bufnum = 0x20; | ||
628 | u16 ring_id, ring_num = 0; | ||
629 | int ret; | ||
630 | |||
631 | /* allocate rx descriptor ring */ | ||
632 | ring_id = xgene_enet_get_ring_id(RING_OWNER_CPU, cpu_bufnum++); | ||
633 | rx_ring = xgene_enet_create_desc_ring(ndev, ring_num++, | ||
634 | RING_CFGSIZE_16KB, ring_id); | ||
635 | if (!rx_ring) { | ||
636 | ret = -ENOMEM; | ||
637 | goto err; | ||
638 | } | ||
639 | |||
640 | /* allocate buffer pool for receiving packets */ | ||
641 | ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, bp_bufnum++); | ||
642 | buf_pool = xgene_enet_create_desc_ring(ndev, ring_num++, | ||
643 | RING_CFGSIZE_2KB, ring_id); | ||
644 | if (!buf_pool) { | ||
645 | ret = -ENOMEM; | ||
646 | goto err; | ||
647 | } | ||
648 | |||
649 | rx_ring->nbufpool = NUM_BUFPOOL; | ||
650 | rx_ring->buf_pool = buf_pool; | ||
651 | rx_ring->irq = pdata->rx_irq; | ||
652 | buf_pool->rx_skb = devm_kcalloc(dev, buf_pool->slots, | ||
653 | sizeof(struct sk_buff *), GFP_KERNEL); | ||
654 | if (!buf_pool->rx_skb) { | ||
655 | ret = -ENOMEM; | ||
656 | goto err; | ||
657 | } | ||
658 | |||
659 | buf_pool->dst_ring_num = xgene_enet_dst_ring_num(buf_pool); | ||
660 | rx_ring->buf_pool = buf_pool; | ||
661 | pdata->rx_ring = rx_ring; | ||
662 | |||
663 | /* allocate tx descriptor ring */ | ||
664 | ring_id = xgene_enet_get_ring_id(RING_OWNER_ETH0, eth_bufnum++); | ||
665 | tx_ring = xgene_enet_create_desc_ring(ndev, ring_num++, | ||
666 | RING_CFGSIZE_16KB, ring_id); | ||
667 | if (!tx_ring) { | ||
668 | ret = -ENOMEM; | ||
669 | goto err; | ||
670 | } | ||
671 | pdata->tx_ring = tx_ring; | ||
672 | |||
673 | cp_ring = pdata->rx_ring; | ||
674 | cp_ring->cp_skb = devm_kcalloc(dev, tx_ring->slots, | ||
675 | sizeof(struct sk_buff *), GFP_KERNEL); | ||
676 | if (!cp_ring->cp_skb) { | ||
677 | ret = -ENOMEM; | ||
678 | goto err; | ||
679 | } | ||
680 | pdata->tx_ring->cp_ring = cp_ring; | ||
681 | pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring); | ||
682 | |||
683 | pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2; | ||
684 | pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2; | ||
685 | pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2; | ||
686 | |||
687 | return 0; | ||
688 | |||
689 | err: | ||
690 | xgene_enet_free_desc_rings(pdata); | ||
691 | return ret; | ||
692 | } | ||
693 | |||
694 | static struct rtnl_link_stats64 *xgene_enet_get_stats64( | ||
695 | struct net_device *ndev, | ||
696 | struct rtnl_link_stats64 *storage) | ||
697 | { | ||
698 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
699 | struct rtnl_link_stats64 *stats = &pdata->stats; | ||
700 | |||
701 | stats->rx_errors += stats->rx_length_errors + | ||
702 | stats->rx_crc_errors + | ||
703 | stats->rx_frame_errors + | ||
704 | stats->rx_fifo_errors; | ||
705 | memcpy(storage, &pdata->stats, sizeof(struct rtnl_link_stats64)); | ||
706 | |||
707 | return storage; | ||
708 | } | ||
709 | |||
710 | static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr) | ||
711 | { | ||
712 | struct xgene_enet_pdata *pdata = netdev_priv(ndev); | ||
713 | int ret; | ||
714 | |||
715 | ret = eth_mac_addr(ndev, addr); | ||
716 | if (ret) | ||
717 | return ret; | ||
718 | xgene_gmac_set_mac_addr(pdata); | ||
719 | |||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | static const struct net_device_ops xgene_ndev_ops = { | ||
724 | .ndo_open = xgene_enet_open, | ||
725 | .ndo_stop = xgene_enet_close, | ||
726 | .ndo_start_xmit = xgene_enet_start_xmit, | ||
727 | .ndo_tx_timeout = xgene_enet_timeout, | ||
728 | .ndo_get_stats64 = xgene_enet_get_stats64, | ||
729 | .ndo_change_mtu = eth_change_mtu, | ||
730 | .ndo_set_mac_address = xgene_enet_set_mac_address, | ||
731 | }; | ||
732 | |||
733 | static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata) | ||
734 | { | ||
735 | struct platform_device *pdev; | ||
736 | struct net_device *ndev; | ||
737 | struct device *dev; | ||
738 | struct resource *res; | ||
739 | void __iomem *base_addr; | ||
740 | const char *mac; | ||
741 | int ret; | ||
742 | |||
743 | pdev = pdata->pdev; | ||
744 | dev = &pdev->dev; | ||
745 | ndev = pdata->ndev; | ||
746 | |||
747 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr"); | ||
748 | if (!res) { | ||
749 | dev_err(dev, "Resource enet_csr not defined\n"); | ||
750 | return -ENODEV; | ||
751 | } | ||
752 | pdata->base_addr = devm_ioremap_resource(dev, res); | ||
753 | if (IS_ERR(pdata->base_addr)) { | ||
754 | dev_err(dev, "Unable to retrieve ENET Port CSR region\n"); | ||
755 | return PTR_ERR(pdata->base_addr); | ||
756 | } | ||
757 | |||
758 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr"); | ||
759 | if (!res) { | ||
760 | dev_err(dev, "Resource ring_csr not defined\n"); | ||
761 | return -ENODEV; | ||
762 | } | ||
763 | pdata->ring_csr_addr = devm_ioremap_resource(dev, res); | ||
764 | if (IS_ERR(pdata->ring_csr_addr)) { | ||
765 | dev_err(dev, "Unable to retrieve ENET Ring CSR region\n"); | ||
766 | return PTR_ERR(pdata->ring_csr_addr); | ||
767 | } | ||
768 | |||
769 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd"); | ||
770 | if (!res) { | ||
771 | dev_err(dev, "Resource ring_cmd not defined\n"); | ||
772 | return -ENODEV; | ||
773 | } | ||
774 | pdata->ring_cmd_addr = devm_ioremap_resource(dev, res); | ||
775 | if (IS_ERR(pdata->ring_cmd_addr)) { | ||
776 | dev_err(dev, "Unable to retrieve ENET Ring command region\n"); | ||
777 | return PTR_ERR(pdata->ring_cmd_addr); | ||
778 | } | ||
779 | |||
780 | ret = platform_get_irq(pdev, 0); | ||
781 | if (ret <= 0) { | ||
782 | dev_err(dev, "Unable to get ENET Rx IRQ\n"); | ||
783 | ret = ret ? : -ENXIO; | ||
784 | return ret; | ||
785 | } | ||
786 | pdata->rx_irq = ret; | ||
787 | |||
788 | mac = of_get_mac_address(dev->of_node); | ||
789 | if (mac) | ||
790 | memcpy(ndev->dev_addr, mac, ndev->addr_len); | ||
791 | else | ||
792 | eth_hw_addr_random(ndev); | ||
793 | memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); | ||
794 | |||
795 | pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node); | ||
796 | if (pdata->phy_mode < 0) { | ||
797 | dev_err(dev, "Incorrect phy-connection-type in DTS\n"); | ||
798 | return -EINVAL; | ||
799 | } | ||
800 | |||
801 | pdata->clk = devm_clk_get(&pdev->dev, NULL); | ||
802 | ret = IS_ERR(pdata->clk); | ||
803 | if (IS_ERR(pdata->clk)) { | ||
804 | dev_err(&pdev->dev, "can't get clock\n"); | ||
805 | ret = PTR_ERR(pdata->clk); | ||
806 | return ret; | ||
807 | } | ||
808 | |||
809 | base_addr = pdata->base_addr; | ||
810 | pdata->eth_csr_addr = base_addr + BLOCK_ETH_CSR_OFFSET; | ||
811 | pdata->eth_ring_if_addr = base_addr + BLOCK_ETH_RING_IF_OFFSET; | ||
812 | pdata->eth_diag_csr_addr = base_addr + BLOCK_ETH_DIAG_CSR_OFFSET; | ||
813 | pdata->mcx_mac_addr = base_addr + BLOCK_ETH_MAC_OFFSET; | ||
814 | pdata->mcx_stats_addr = base_addr + BLOCK_ETH_STATS_OFFSET; | ||
815 | pdata->mcx_mac_csr_addr = base_addr + BLOCK_ETH_MAC_CSR_OFFSET; | ||
816 | pdata->rx_buff_cnt = NUM_PKT_BUF; | ||
817 | |||
818 | return ret; | ||
819 | } | ||
820 | |||
821 | static int xgene_enet_init_hw(struct xgene_enet_pdata *pdata) | ||
822 | { | ||
823 | struct net_device *ndev = pdata->ndev; | ||
824 | struct xgene_enet_desc_ring *buf_pool; | ||
825 | u16 dst_ring_num; | ||
826 | int ret; | ||
827 | |||
828 | xgene_gmac_tx_disable(pdata); | ||
829 | xgene_gmac_rx_disable(pdata); | ||
830 | |||
831 | ret = xgene_enet_create_desc_rings(ndev); | ||
832 | if (ret) { | ||
833 | netdev_err(ndev, "Error in ring configuration\n"); | ||
834 | return ret; | ||
835 | } | ||
836 | |||
837 | /* setup buffer pool */ | ||
838 | buf_pool = pdata->rx_ring->buf_pool; | ||
839 | xgene_enet_init_bufpool(buf_pool); | ||
840 | ret = xgene_enet_refill_bufpool(buf_pool, pdata->rx_buff_cnt); | ||
841 | if (ret) { | ||
842 | xgene_enet_delete_desc_rings(pdata); | ||
843 | return ret; | ||
844 | } | ||
845 | |||
846 | dst_ring_num = xgene_enet_dst_ring_num(pdata->rx_ring); | ||
847 | xgene_enet_cle_bypass(pdata, dst_ring_num, buf_pool->id); | ||
848 | |||
849 | return ret; | ||
850 | } | ||
851 | |||
852 | static int xgene_enet_probe(struct platform_device *pdev) | ||
853 | { | ||
854 | struct net_device *ndev; | ||
855 | struct xgene_enet_pdata *pdata; | ||
856 | struct device *dev = &pdev->dev; | ||
857 | struct napi_struct *napi; | ||
858 | int ret; | ||
859 | |||
860 | ndev = alloc_etherdev(sizeof(struct xgene_enet_pdata)); | ||
861 | if (!ndev) | ||
862 | return -ENOMEM; | ||
863 | |||
864 | pdata = netdev_priv(ndev); | ||
865 | |||
866 | pdata->pdev = pdev; | ||
867 | pdata->ndev = ndev; | ||
868 | SET_NETDEV_DEV(ndev, dev); | ||
869 | platform_set_drvdata(pdev, pdata); | ||
870 | ndev->netdev_ops = &xgene_ndev_ops; | ||
871 | xgene_enet_set_ethtool_ops(ndev); | ||
872 | ndev->features |= NETIF_F_IP_CSUM | | ||
873 | NETIF_F_GSO | | ||
874 | NETIF_F_GRO; | ||
875 | |||
876 | ret = xgene_enet_get_resources(pdata); | ||
877 | if (ret) | ||
878 | goto err; | ||
879 | |||
880 | xgene_enet_reset(pdata); | ||
881 | xgene_gmac_init(pdata, SPEED_1000); | ||
882 | |||
883 | ret = register_netdev(ndev); | ||
884 | if (ret) { | ||
885 | netdev_err(ndev, "Failed to register netdev\n"); | ||
886 | goto err; | ||
887 | } | ||
888 | |||
889 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); | ||
890 | if (ret) { | ||
891 | netdev_err(ndev, "No usable DMA configuration\n"); | ||
892 | goto err; | ||
893 | } | ||
894 | |||
895 | ret = xgene_enet_init_hw(pdata); | ||
896 | if (ret) | ||
897 | goto err; | ||
898 | |||
899 | napi = &pdata->rx_ring->napi; | ||
900 | netif_napi_add(ndev, napi, xgene_enet_napi, NAPI_POLL_WEIGHT); | ||
901 | ret = xgene_enet_mdio_config(pdata); | ||
902 | |||
903 | return ret; | ||
904 | err: | ||
905 | free_netdev(ndev); | ||
906 | return ret; | ||
907 | } | ||
908 | |||
909 | static int xgene_enet_remove(struct platform_device *pdev) | ||
910 | { | ||
911 | struct xgene_enet_pdata *pdata; | ||
912 | struct net_device *ndev; | ||
913 | |||
914 | pdata = platform_get_drvdata(pdev); | ||
915 | ndev = pdata->ndev; | ||
916 | |||
917 | xgene_gmac_rx_disable(pdata); | ||
918 | xgene_gmac_tx_disable(pdata); | ||
919 | |||
920 | netif_napi_del(&pdata->rx_ring->napi); | ||
921 | xgene_enet_mdio_remove(pdata); | ||
922 | xgene_enet_delete_desc_rings(pdata); | ||
923 | unregister_netdev(ndev); | ||
924 | xgene_gport_shutdown(pdata); | ||
925 | free_netdev(ndev); | ||
926 | |||
927 | return 0; | ||
928 | } | ||
929 | |||
930 | static struct of_device_id xgene_enet_match[] = { | ||
931 | {.compatible = "apm,xgene-enet",}, | ||
932 | {}, | ||
933 | }; | ||
934 | |||
935 | MODULE_DEVICE_TABLE(of, xgene_enet_match); | ||
936 | |||
937 | static struct platform_driver xgene_enet_driver = { | ||
938 | .driver = { | ||
939 | .name = "xgene-enet", | ||
940 | .of_match_table = xgene_enet_match, | ||
941 | }, | ||
942 | .probe = xgene_enet_probe, | ||
943 | .remove = xgene_enet_remove, | ||
944 | }; | ||
945 | |||
946 | module_platform_driver(xgene_enet_driver); | ||
947 | |||
948 | MODULE_DESCRIPTION("APM X-Gene SoC Ethernet driver"); | ||
949 | MODULE_VERSION(XGENE_DRV_VERSION); | ||
950 | MODULE_AUTHOR("Keyur Chudgar <kchudgar@apm.com>"); | ||
951 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h new file mode 100644 index 000000000000..0815866986b0 --- /dev/null +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* Applied Micro X-Gene SoC Ethernet Driver | ||
2 | * | ||
3 | * Copyright (c) 2014, Applied Micro Circuits Corporation | ||
4 | * Authors: Iyappan Subramanian <isubramanian@apm.com> | ||
5 | * Ravi Patel <rapatel@apm.com> | ||
6 | * Keyur Chudgar <kchudgar@apm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #ifndef __XGENE_ENET_MAIN_H__ | ||
23 | #define __XGENE_ENET_MAIN_H__ | ||
24 | |||
25 | #include <linux/clk.h> | ||
26 | #include <linux/of_platform.h> | ||
27 | #include <linux/of_net.h> | ||
28 | #include <linux/of_mdio.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <net/ip.h> | ||
31 | #include <linux/prefetch.h> | ||
32 | #include <linux/if_vlan.h> | ||
33 | #include <linux/phy.h> | ||
34 | #include "xgene_enet_hw.h" | ||
35 | |||
36 | #define XGENE_DRV_VERSION "v1.0" | ||
37 | #define XGENE_ENET_MAX_MTU 1536 | ||
38 | #define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN) | ||
39 | #define NUM_PKT_BUF 64 | ||
40 | #define NUM_BUFPOOL 32 | ||
41 | |||
42 | /* software context of a descriptor ring */ | ||
43 | struct xgene_enet_desc_ring { | ||
44 | struct net_device *ndev; | ||
45 | u16 id; | ||
46 | u16 num; | ||
47 | u16 head; | ||
48 | u16 tail; | ||
49 | u16 slots; | ||
50 | u16 irq; | ||
51 | u32 size; | ||
52 | u32 state[NUM_RING_CONFIG]; | ||
53 | void __iomem *cmd_base; | ||
54 | void __iomem *cmd; | ||
55 | dma_addr_t dma; | ||
56 | u16 dst_ring_num; | ||
57 | u8 nbufpool; | ||
58 | struct sk_buff *(*rx_skb); | ||
59 | struct sk_buff *(*cp_skb); | ||
60 | enum xgene_enet_ring_cfgsize cfgsize; | ||
61 | struct xgene_enet_desc_ring *cp_ring; | ||
62 | struct xgene_enet_desc_ring *buf_pool; | ||
63 | struct napi_struct napi; | ||
64 | union { | ||
65 | void *desc_addr; | ||
66 | struct xgene_enet_raw_desc *raw_desc; | ||
67 | struct xgene_enet_raw_desc16 *raw_desc16; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | /* ethernet private data */ | ||
72 | struct xgene_enet_pdata { | ||
73 | struct net_device *ndev; | ||
74 | struct mii_bus *mdio_bus; | ||
75 | struct phy_device *phy_dev; | ||
76 | int phy_speed; | ||
77 | struct clk *clk; | ||
78 | struct platform_device *pdev; | ||
79 | struct xgene_enet_desc_ring *tx_ring; | ||
80 | struct xgene_enet_desc_ring *rx_ring; | ||
81 | char *dev_name; | ||
82 | u32 rx_buff_cnt; | ||
83 | u32 tx_qcnt_hi; | ||
84 | u32 cp_qcnt_hi; | ||
85 | u32 cp_qcnt_low; | ||
86 | u32 rx_irq; | ||
87 | void __iomem *eth_csr_addr; | ||
88 | void __iomem *eth_ring_if_addr; | ||
89 | void __iomem *eth_diag_csr_addr; | ||
90 | void __iomem *mcx_mac_addr; | ||
91 | void __iomem *mcx_stats_addr; | ||
92 | void __iomem *mcx_mac_csr_addr; | ||
93 | void __iomem *base_addr; | ||
94 | void __iomem *ring_csr_addr; | ||
95 | void __iomem *ring_cmd_addr; | ||
96 | u32 phy_addr; | ||
97 | int phy_mode; | ||
98 | u32 speed; | ||
99 | u16 rm; | ||
100 | struct rtnl_link_stats64 stats; | ||
101 | }; | ||
102 | |||
103 | /* Set the specified value into a bit-field defined by its starting position | ||
104 | * and length within a single u64. | ||
105 | */ | ||
106 | static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val) | ||
107 | { | ||
108 | return (val & ((1ULL << len) - 1)) << pos; | ||
109 | } | ||
110 | |||
111 | #define SET_VAL(field, val) \ | ||
112 | xgene_enet_set_field_value(field ## _POS, field ## _LEN, val) | ||
113 | |||
114 | #define SET_BIT(field) \ | ||
115 | xgene_enet_set_field_value(field ## _POS, 1, 1) | ||
116 | |||
117 | /* Get the value from a bit-field defined by its starting position | ||
118 | * and length within the specified u64. | ||
119 | */ | ||
120 | static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) | ||
121 | { | ||
122 | return (src >> pos) & ((1ULL << len) - 1); | ||
123 | } | ||
124 | |||
125 | #define GET_VAL(field, src) \ | ||
126 | xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) | ||
127 | |||
128 | static inline struct device *ndev_to_dev(struct net_device *ndev) | ||
129 | { | ||
130 | return ndev->dev.parent; | ||
131 | } | ||
132 | |||
133 | void xgene_enet_set_ethtool_ops(struct net_device *netdev); | ||
134 | |||
135 | #endif /* __XGENE_ENET_MAIN_H__ */ | ||