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> | |
29 | #include <linux/mii.h> | |
30 | #include <net/dst.h> | |
31 | ||
32 | #include <asm/octeon/octeon.h> | |
33 | ||
34 | #include "ethernet-defines.h" | |
35 | #include "octeon-ethernet.h" | |
36 | #include "ethernet-mdio.h" | |
37 | ||
38 | #include "cvmx-helper-board.h" | |
39 | ||
40 | #include "cvmx-smix-defs.h" | |
41 | ||
42 | DECLARE_MUTEX(mdio_sem); | |
43 | ||
44 | /** | |
45 | * Perform an MII read. Called by the generic MII routines | |
46 | * | |
47 | * @dev: Device to perform read for | |
48 | * @phy_id: The MII phy id | |
49 | * @location: Register location to read | |
50 | * Returns Result from the read or zero on failure | |
51 | */ | |
52 | static int cvm_oct_mdio_read(struct net_device *dev, int phy_id, int location) | |
53 | { | |
54 | union cvmx_smix_cmd smi_cmd; | |
55 | union cvmx_smix_rd_dat smi_rd; | |
56 | ||
57 | smi_cmd.u64 = 0; | |
58 | smi_cmd.s.phy_op = 1; | |
59 | smi_cmd.s.phy_adr = phy_id; | |
60 | smi_cmd.s.reg_adr = location; | |
61 | cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64); | |
62 | ||
63 | do { | |
64 | if (!in_interrupt()) | |
65 | yield(); | |
66 | smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(0)); | |
67 | } while (smi_rd.s.pending); | |
68 | ||
69 | if (smi_rd.s.val) | |
70 | return smi_rd.s.dat; | |
71 | else | |
72 | return 0; | |
73 | } | |
74 | ||
75 | static int cvm_oct_mdio_dummy_read(struct net_device *dev, int phy_id, | |
76 | int location) | |
77 | { | |
78 | return 0xffff; | |
79 | } | |
80 | ||
81 | /** | |
82 | * Perform an MII write. Called by the generic MII routines | |
83 | * | |
84 | * @dev: Device to perform write for | |
85 | * @phy_id: The MII phy id | |
86 | * @location: Register location to write | |
87 | * @val: Value to write | |
88 | */ | |
89 | static void cvm_oct_mdio_write(struct net_device *dev, int phy_id, int location, | |
90 | int val) | |
91 | { | |
92 | union cvmx_smix_cmd smi_cmd; | |
93 | union cvmx_smix_wr_dat smi_wr; | |
94 | ||
95 | smi_wr.u64 = 0; | |
96 | smi_wr.s.dat = val; | |
97 | cvmx_write_csr(CVMX_SMIX_WR_DAT(0), smi_wr.u64); | |
98 | ||
99 | smi_cmd.u64 = 0; | |
100 | smi_cmd.s.phy_op = 0; | |
101 | smi_cmd.s.phy_adr = phy_id; | |
102 | smi_cmd.s.reg_adr = location; | |
103 | cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64); | |
104 | ||
105 | do { | |
106 | if (!in_interrupt()) | |
107 | yield(); | |
108 | smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(0)); | |
109 | } while (smi_wr.s.pending); | |
110 | } | |
111 | ||
112 | static void cvm_oct_mdio_dummy_write(struct net_device *dev, int phy_id, | |
113 | int location, int val) | |
114 | { | |
115 | } | |
116 | ||
117 | static void cvm_oct_get_drvinfo(struct net_device *dev, | |
118 | struct ethtool_drvinfo *info) | |
119 | { | |
120 | strcpy(info->driver, "cavium-ethernet"); | |
121 | strcpy(info->version, OCTEON_ETHERNET_VERSION); | |
122 | strcpy(info->bus_info, "Builtin"); | |
123 | } | |
124 | ||
125 | static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
126 | { | |
127 | struct octeon_ethernet *priv = netdev_priv(dev); | |
128 | int ret; | |
129 | ||
130 | down(&mdio_sem); | |
131 | ret = mii_ethtool_gset(&priv->mii_info, cmd); | |
132 | up(&mdio_sem); | |
133 | ||
134 | return ret; | |
135 | } | |
136 | ||
137 | static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
138 | { | |
139 | struct octeon_ethernet *priv = netdev_priv(dev); | |
140 | int ret; | |
141 | ||
142 | down(&mdio_sem); | |
143 | ret = mii_ethtool_sset(&priv->mii_info, cmd); | |
144 | up(&mdio_sem); | |
145 | ||
146 | return ret; | |
147 | } | |
148 | ||
149 | static int cvm_oct_nway_reset(struct net_device *dev) | |
150 | { | |
151 | struct octeon_ethernet *priv = netdev_priv(dev); | |
152 | int ret; | |
153 | ||
154 | down(&mdio_sem); | |
155 | ret = mii_nway_restart(&priv->mii_info); | |
156 | up(&mdio_sem); | |
157 | ||
158 | return ret; | |
159 | } | |
160 | ||
161 | static u32 cvm_oct_get_link(struct net_device *dev) | |
162 | { | |
163 | struct octeon_ethernet *priv = netdev_priv(dev); | |
164 | u32 ret; | |
165 | ||
166 | down(&mdio_sem); | |
167 | ret = mii_link_ok(&priv->mii_info); | |
168 | up(&mdio_sem); | |
169 | ||
170 | return ret; | |
171 | } | |
172 | ||
9326e361 | 173 | const struct ethtool_ops cvm_oct_ethtool_ops = { |
80ff0fd3 DD |
174 | .get_drvinfo = cvm_oct_get_drvinfo, |
175 | .get_settings = cvm_oct_get_settings, | |
176 | .set_settings = cvm_oct_set_settings, | |
177 | .nway_reset = cvm_oct_nway_reset, | |
178 | .get_link = cvm_oct_get_link, | |
179 | .get_sg = ethtool_op_get_sg, | |
180 | .get_tx_csum = ethtool_op_get_tx_csum, | |
181 | }; | |
182 | ||
183 | /** | |
184 | * IOCTL support for PHY control | |
185 | * | |
186 | * @dev: Device to change | |
187 | * @rq: the request | |
188 | * @cmd: the command | |
189 | * Returns Zero on success | |
190 | */ | |
191 | int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |
192 | { | |
193 | struct octeon_ethernet *priv = netdev_priv(dev); | |
194 | struct mii_ioctl_data *data = if_mii(rq); | |
195 | unsigned int duplex_chg; | |
196 | int ret; | |
197 | ||
198 | down(&mdio_sem); | |
199 | ret = generic_mii_ioctl(&priv->mii_info, data, cmd, &duplex_chg); | |
200 | up(&mdio_sem); | |
201 | ||
202 | return ret; | |
203 | } | |
204 | ||
205 | /** | |
206 | * Setup the MDIO device structures | |
207 | * | |
208 | * @dev: Device to setup | |
209 | * | |
210 | * Returns Zero on success, negative on failure | |
211 | */ | |
212 | int cvm_oct_mdio_setup_device(struct net_device *dev) | |
213 | { | |
214 | struct octeon_ethernet *priv = netdev_priv(dev); | |
215 | int phy_id = cvmx_helper_board_get_mii_address(priv->port); | |
216 | if (phy_id != -1) { | |
217 | priv->mii_info.dev = dev; | |
218 | priv->mii_info.phy_id = phy_id; | |
219 | priv->mii_info.phy_id_mask = 0xff; | |
220 | priv->mii_info.supports_gmii = 1; | |
221 | priv->mii_info.reg_num_mask = 0x1f; | |
222 | priv->mii_info.mdio_read = cvm_oct_mdio_read; | |
223 | priv->mii_info.mdio_write = cvm_oct_mdio_write; | |
224 | } else { | |
225 | /* Supply dummy MDIO routines so the kernel won't crash | |
226 | if the user tries to read them */ | |
227 | priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read; | |
228 | priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write; | |
229 | } | |
230 | return 0; | |
231 | } |