Commit | Line | Data |
---|---|---|
80ff0fd3 DD |
1 | /********************************************************************** |
2 | * Author: Cavium Networks | |
3 | * | |
4 | * Contact: support@caviumnetworks.com | |
5 | * This file is part of the OCTEON SDK | |
6 | * | |
7 | * Copyright (c) 2003-2007 Cavium Networks | |
8 | * | |
9 | * This file is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License, Version 2, as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This file is distributed in the hope that it will be useful, but | |
14 | * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty | |
15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or | |
16 | * NONINFRINGEMENT. See the GNU General Public License for more | |
17 | * details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this file; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * or visit http://www.gnu.org/licenses/. | |
23 | * | |
24 | * This file may also be available under a different license from Cavium. | |
25 | * Contact Cavium Networks for more information | |
26 | **********************************************************************/ | |
27 | #include <linux/kernel.h> | |
28 | #include <linux/ethtool.h> | |
f6ed1b3b | 29 | #include <linux/phy.h> |
7a2eaf93 | 30 | #include <linux/ratelimit.h> |
df9244c5 | 31 | #include <linux/of_mdio.h> |
f6ed1b3b | 32 | |
80ff0fd3 DD |
33 | #include <net/dst.h> |
34 | ||
35 | #include <asm/octeon/octeon.h> | |
36 | ||
37 | #include "ethernet-defines.h" | |
38 | #include "octeon-ethernet.h" | |
39 | #include "ethernet-mdio.h" | |
f6ed1b3b | 40 | #include "ethernet-util.h" |
80ff0fd3 | 41 | |
af866496 | 42 | #include <asm/octeon/cvmx-helper-board.h> |
80ff0fd3 | 43 | |
af866496 | 44 | #include <asm/octeon/cvmx-smix-defs.h> |
80ff0fd3 | 45 | |
80ff0fd3 DD |
46 | static void cvm_oct_get_drvinfo(struct net_device *dev, |
47 | struct ethtool_drvinfo *info) | |
48 | { | |
7826d43f JP |
49 | strlcpy(info->driver, "cavium-ethernet", sizeof(info->driver)); |
50 | strlcpy(info->version, OCTEON_ETHERNET_VERSION, sizeof(info->version)); | |
51 | strlcpy(info->bus_info, "Builtin", sizeof(info->bus_info)); | |
80ff0fd3 DD |
52 | } |
53 | ||
54 | static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
55 | { | |
56 | struct octeon_ethernet *priv = netdev_priv(dev); | |
80ff0fd3 | 57 | |
f6ed1b3b DD |
58 | if (priv->phydev) |
59 | return phy_ethtool_gset(priv->phydev, cmd); | |
80ff0fd3 | 60 | |
f6ed1b3b | 61 | return -EINVAL; |
80ff0fd3 DD |
62 | } |
63 | ||
64 | static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
65 | { | |
66 | struct octeon_ethernet *priv = netdev_priv(dev); | |
80ff0fd3 | 67 | |
f6ed1b3b DD |
68 | if (!capable(CAP_NET_ADMIN)) |
69 | return -EPERM; | |
70 | ||
71 | if (priv->phydev) | |
72 | return phy_ethtool_sset(priv->phydev, cmd); | |
80ff0fd3 | 73 | |
f6ed1b3b | 74 | return -EINVAL; |
80ff0fd3 DD |
75 | } |
76 | ||
77 | static int cvm_oct_nway_reset(struct net_device *dev) | |
78 | { | |
79 | struct octeon_ethernet *priv = netdev_priv(dev); | |
80ff0fd3 | 80 | |
f6ed1b3b DD |
81 | if (!capable(CAP_NET_ADMIN)) |
82 | return -EPERM; | |
80ff0fd3 | 83 | |
f6ed1b3b DD |
84 | if (priv->phydev) |
85 | return phy_start_aneg(priv->phydev); | |
80ff0fd3 | 86 | |
f6ed1b3b | 87 | return -EINVAL; |
80ff0fd3 DD |
88 | } |
89 | ||
9326e361 | 90 | const struct ethtool_ops cvm_oct_ethtool_ops = { |
80ff0fd3 DD |
91 | .get_drvinfo = cvm_oct_get_drvinfo, |
92 | .get_settings = cvm_oct_get_settings, | |
93 | .set_settings = cvm_oct_set_settings, | |
94 | .nway_reset = cvm_oct_nway_reset, | |
f6ed1b3b | 95 | .get_link = ethtool_op_get_link, |
80ff0fd3 DD |
96 | }; |
97 | ||
98 | /** | |
ec977c5b | 99 | * cvm_oct_ioctl - IOCTL support for PHY control |
80ff0fd3 DD |
100 | * @dev: Device to change |
101 | * @rq: the request | |
102 | * @cmd: the command | |
ec977c5b | 103 | * |
80ff0fd3 DD |
104 | * Returns Zero on success |
105 | */ | |
106 | int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |
107 | { | |
108 | struct octeon_ethernet *priv = netdev_priv(dev); | |
80ff0fd3 | 109 | |
f6ed1b3b DD |
110 | if (!netif_running(dev)) |
111 | return -EINVAL; | |
112 | ||
113 | if (!priv->phydev) | |
114 | return -EINVAL; | |
115 | ||
28b04113 | 116 | return phy_mii_ioctl(priv->phydev, rq, cmd); |
f6ed1b3b | 117 | } |
80ff0fd3 | 118 | |
f6ed1b3b DD |
119 | static void cvm_oct_adjust_link(struct net_device *dev) |
120 | { | |
121 | struct octeon_ethernet *priv = netdev_priv(dev); | |
122 | cvmx_helper_link_info_t link_info; | |
123 | ||
124 | if (priv->last_link != priv->phydev->link) { | |
125 | priv->last_link = priv->phydev->link; | |
126 | link_info.u64 = 0; | |
127 | link_info.s.link_up = priv->last_link ? 1 : 0; | |
128 | link_info.s.full_duplex = priv->phydev->duplex ? 1 : 0; | |
129 | link_info.s.speed = priv->phydev->speed; | |
130 | cvmx_helper_link_set( priv->port, link_info); | |
131 | if (priv->last_link) { | |
132 | netif_carrier_on(dev); | |
133 | if (priv->queue != -1) | |
7a2eaf93 CD |
134 | printk_ratelimited("%s: %u Mbps %s duplex, " |
135 | "port %2d, queue %2d\n", | |
136 | dev->name, priv->phydev->speed, | |
137 | priv->phydev->duplex ? | |
138 | "Full" : "Half", | |
139 | priv->port, priv->queue); | |
f6ed1b3b | 140 | else |
7a2eaf93 CD |
141 | printk_ratelimited("%s: %u Mbps %s duplex, " |
142 | "port %2d, POW\n", | |
143 | dev->name, priv->phydev->speed, | |
144 | priv->phydev->duplex ? | |
145 | "Full" : "Half", | |
146 | priv->port); | |
f6ed1b3b DD |
147 | } else { |
148 | netif_carrier_off(dev); | |
7a2eaf93 | 149 | printk_ratelimited("%s: Link down\n", dev->name); |
f6ed1b3b DD |
150 | } |
151 | } | |
80ff0fd3 DD |
152 | } |
153 | ||
f6ed1b3b | 154 | |
80ff0fd3 | 155 | /** |
ec977c5b | 156 | * cvm_oct_phy_setup_device - setup the PHY |
80ff0fd3 DD |
157 | * |
158 | * @dev: Device to setup | |
159 | * | |
160 | * Returns Zero on success, negative on failure | |
161 | */ | |
f6ed1b3b | 162 | int cvm_oct_phy_setup_device(struct net_device *dev) |
80ff0fd3 DD |
163 | { |
164 | struct octeon_ethernet *priv = netdev_priv(dev); | |
df9244c5 | 165 | struct device_node *phy_node; |
f6ed1b3b | 166 | |
df9244c5 DD |
167 | if (!priv->of_node) |
168 | return 0; | |
f6ed1b3b | 169 | |
df9244c5 DD |
170 | phy_node = of_parse_phandle(priv->of_node, "phy-handle", 0); |
171 | if (!phy_node) | |
172 | return 0; | |
f6ed1b3b | 173 | |
df9244c5 DD |
174 | priv->phydev = of_phy_connect(dev, phy_node, cvm_oct_adjust_link, 0, |
175 | PHY_INTERFACE_MODE_GMII); | |
176 | ||
177 | if (priv->phydev == NULL) | |
178 | return -ENODEV; | |
179 | ||
180 | priv->last_link = 0; | |
181 | phy_start_aneg(priv->phydev); | |
f6ed1b3b | 182 | |
80ff0fd3 DD |
183 | return 0; |
184 | } |