diff options
Diffstat (limited to 'drivers/staging/octeon/ethernet-mdio.c')
-rw-r--r-- | drivers/staging/octeon/ethernet-mdio.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c new file mode 100644 index 00000000000..93cab0a4892 --- /dev/null +++ b/drivers/staging/octeon/ethernet-mdio.c | |||
@@ -0,0 +1,231 @@ | |||
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 | |||
173 | struct ethtool_ops cvm_oct_ethtool_ops = { | ||
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 | } | ||