blob: 38c5985c52ef239c780f4b4f3af20407fc15574d [file] [log] [blame]
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -05001/*
2 * AMD 10Gb Ethernet driver
3 *
4 * This file is available to you under your choice of the following two
5 * licenses:
6 *
7 * License 1: GPLv2
8 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -06009 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050010 *
11 * This file is free software; you may copy, redistribute and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This file is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 * This file incorporates work covered by the following copyright and
25 * permission notice:
26 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
27 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
28 * Inc. unless otherwise expressly agreed to in writing between Synopsys
29 * and you.
30 *
31 * The Software IS NOT an item of Licensed Software or Licensed Product
32 * under any End User Software License Agreement or Agreement for Licensed
33 * Product with Synopsys or any supplement thereto. Permission is hereby
34 * granted, free of charge, to any person obtaining a copy of this software
35 * annotated with this license and the Software, to deal in the Software
36 * without restriction, including without limitation the rights to use,
37 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
38 * of the Software, and to permit persons to whom the Software is furnished
39 * to do so, subject to the following conditions:
40 *
41 * The above copyright notice and this permission notice shall be included
42 * in all copies or substantial portions of the Software.
43 *
44 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
45 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
47 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
55 *
56 *
57 * License 2: Modified BSD
58 *
Lendacky, Thomasced3fca2016-02-17 11:49:28 -060059 * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -050060 * All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions are met:
64 * * Redistributions of source code must retain the above copyright
65 * notice, this list of conditions and the following disclaimer.
66 * * Redistributions in binary form must reproduce the above copyright
67 * notice, this list of conditions and the following disclaimer in the
68 * documentation and/or other materials provided with the distribution.
69 * * Neither the name of Advanced Micro Devices, Inc. nor the
70 * names of its contributors may be used to endorse or promote products
71 * derived from this software without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
74 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
77 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
79 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
80 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
81 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
82 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83 *
84 * This file incorporates work covered by the following copyright and
85 * permission notice:
86 * The Synopsys DWC ETHER XGMAC Software Driver and documentation
87 * (hereinafter "Software") is an unsupported proprietary work of Synopsys,
88 * Inc. unless otherwise expressly agreed to in writing between Synopsys
89 * and you.
90 *
91 * The Software IS NOT an item of Licensed Software or Licensed Product
92 * under any End User Software License Agreement or Agreement for Licensed
93 * Product with Synopsys or any supplement thereto. Permission is hereby
94 * granted, free of charge, to any person obtaining a copy of this software
95 * annotated with this license and the Software, to deal in the Software
96 * without restriction, including without limitation the rights to use,
97 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98 * of the Software, and to permit persons to whom the Software is furnished
99 * to do so, subject to the following conditions:
100 *
101 * The above copyright notice and this permission notice shall be included
102 * in all copies or substantial portions of the Software.
103 *
104 * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
105 * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
106 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
107 * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
108 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
109 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
110 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
111 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
112 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
113 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
114 * THE POSSIBILITY OF SUCH DAMAGE.
115 */
116
117#include <linux/module.h>
118#include <linux/device.h>
119#include <linux/platform_device.h>
120#include <linux/spinlock.h>
121#include <linux/netdevice.h>
122#include <linux/etherdevice.h>
123#include <linux/io.h>
124#include <linux/of.h>
125#include <linux/of_net.h>
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600126#include <linux/of_address.h>
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500127#include <linux/of_platform.h>
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500128#include <linux/of_device.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500129#include <linux/clk.h>
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600130#include <linux/property.h>
131#include <linux/acpi.h>
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500132#include <linux/mdio.h>
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500133
134#include "xgbe.h"
135#include "xgbe-common.h"
136
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500137MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
138MODULE_LICENSE("Dual BSD/GPL");
139MODULE_VERSION(XGBE_DRV_VERSION);
140MODULE_DESCRIPTION(XGBE_DRV_DESC);
141
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -0500142static int debug = -1;
143module_param(debug, int, S_IWUSR | S_IRUGO);
144MODULE_PARM_DESC(debug, " Network interface message level setting");
145
146static const u32 default_msg_level = (NETIF_MSG_LINK | NETIF_MSG_IFDOWN |
147 NETIF_MSG_IFUP);
148
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500149static void xgbe_default_config(struct xgbe_prv_data *pdata)
150{
151 DBGPR("-->xgbe_default_config\n");
152
153 pdata->pblx8 = DMA_PBL_X8_ENABLE;
154 pdata->tx_sf_mode = MTL_TSF_ENABLE;
155 pdata->tx_threshold = MTL_TX_THRESHOLD_64;
156 pdata->tx_pbl = DMA_PBL_16;
157 pdata->tx_osp_mode = DMA_OSP_ENABLE;
158 pdata->rx_sf_mode = MTL_RSF_DISABLE;
159 pdata->rx_threshold = MTL_RX_THRESHOLD_64;
160 pdata->rx_pbl = DMA_PBL_16;
161 pdata->pause_autoneg = 1;
162 pdata->tx_pause = 1;
163 pdata->rx_pause = 1;
Lendacky, Thomas916102c2015-01-16 12:46:45 -0600164 pdata->phy_speed = SPEED_UNKNOWN;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500165 pdata->power_down = 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500166
167 DBGPR("<--xgbe_default_config\n");
168}
169
170static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
171{
172 xgbe_init_function_ptrs_dev(&pdata->hw_if);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500173 xgbe_init_function_ptrs_phy(&pdata->phy_if);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500174 xgbe_init_function_ptrs_desc(&pdata->desc_if);
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500175
176 pdata->vdata->init_function_ptrs_phy_impl(&pdata->phy_if);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500177}
178
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600179#ifdef CONFIG_ACPI
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500180static const struct acpi_device_id xgbe_acpi_match[];
181
182static struct xgbe_version_data *xgbe_acpi_vdata(struct xgbe_prv_data *pdata)
183{
184 const struct acpi_device_id *id;
185
186 id = acpi_match_device(xgbe_acpi_match, pdata->dev);
187
188 return id ? (struct xgbe_version_data *)id->driver_data : NULL;
189}
190
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600191static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
192{
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600193 struct device *dev = pdata->dev;
194 u32 property;
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600195 int ret;
196
197 /* Obtain the system clock setting */
198 ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property);
199 if (ret) {
200 dev_err(dev, "unable to obtain %s property\n",
201 XGBE_ACPI_DMA_FREQ);
202 return ret;
203 }
204 pdata->sysclk_rate = property;
205
206 /* Obtain the PTP clock setting */
207 ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property);
208 if (ret) {
209 dev_err(dev, "unable to obtain %s property\n",
210 XGBE_ACPI_PTP_FREQ);
211 return ret;
212 }
213 pdata->ptpclk_rate = property;
214
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600215 return 0;
216}
217#else /* CONFIG_ACPI */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500218static struct xgbe_version_data *xgbe_acpi_vdata(struct xgbe_prv_data *pdata)
219{
220 return NULL;
221}
222
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600223static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
224{
225 return -EINVAL;
226}
227#endif /* CONFIG_ACPI */
228
229#ifdef CONFIG_OF
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500230static const struct of_device_id xgbe_of_match[];
231
232static struct xgbe_version_data *xgbe_of_vdata(struct xgbe_prv_data *pdata)
233{
234 const struct of_device_id *id;
235
236 id = of_match_device(xgbe_of_match, pdata->dev);
237
238 return id ? (struct xgbe_version_data *)id->data : NULL;
239}
240
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600241static int xgbe_of_support(struct xgbe_prv_data *pdata)
242{
243 struct device *dev = pdata->dev;
244
245 /* Obtain the system clock setting */
246 pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
247 if (IS_ERR(pdata->sysclk)) {
248 dev_err(dev, "dma devm_clk_get failed\n");
249 return PTR_ERR(pdata->sysclk);
250 }
251 pdata->sysclk_rate = clk_get_rate(pdata->sysclk);
252
253 /* Obtain the PTP clock setting */
254 pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
255 if (IS_ERR(pdata->ptpclk)) {
256 dev_err(dev, "ptp devm_clk_get failed\n");
257 return PTR_ERR(pdata->ptpclk);
258 }
259 pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk);
260
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600261 return 0;
262}
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500263
264static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
265{
266 struct device *dev = pdata->dev;
267 struct device_node *phy_node;
268 struct platform_device *phy_pdev;
269
270 phy_node = of_parse_phandle(dev->of_node, "phy-handle", 0);
Lendacky, Thomas34bfff42015-05-14 11:44:21 -0500271 if (phy_node) {
272 /* Old style device tree:
273 * The XGBE and PHY resources are separate
274 */
275 phy_pdev = of_find_device_by_node(phy_node);
276 of_node_put(phy_node);
277 } else {
278 /* New style device tree:
279 * The XGBE and PHY resources are grouped together with
280 * the PHY resources listed last
281 */
282 get_device(dev);
283 phy_pdev = pdata->pdev;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500284 }
285
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500286 return phy_pdev;
287}
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600288#else /* CONFIG_OF */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500289static struct xgbe_version_data *xgbe_of_vdata(struct xgbe_prv_data *pdata)
290{
291 return NULL;
292}
293
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600294static int xgbe_of_support(struct xgbe_prv_data *pdata)
295{
296 return -EINVAL;
297}
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500298
299static struct platform_device *xgbe_of_get_phy_pdev(struct xgbe_prv_data *pdata)
300{
301 return NULL;
302}
303#endif /* CONFIG_OF */
304
305static unsigned int xgbe_resource_count(struct platform_device *pdev,
306 unsigned int type)
307{
308 unsigned int count;
309 int i;
310
311 for (i = 0, count = 0; i < pdev->num_resources; i++) {
312 struct resource *res = &pdev->resource[i];
313
314 if (type == resource_type(res))
315 count++;
316 }
317
318 return count;
319}
320
321static struct platform_device *xgbe_get_phy_pdev(struct xgbe_prv_data *pdata)
322{
323 struct platform_device *phy_pdev;
324
325 if (pdata->use_acpi) {
326 get_device(pdata->dev);
327 phy_pdev = pdata->pdev;
328 } else {
329 phy_pdev = xgbe_of_get_phy_pdev(pdata);
330 }
331
332 return phy_pdev;
333}
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600334
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500335static struct xgbe_version_data *xgbe_get_vdata(struct xgbe_prv_data *pdata)
336{
337 return pdata->use_acpi ? xgbe_acpi_vdata(pdata)
338 : xgbe_of_vdata(pdata);
339}
340
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500341static int xgbe_probe(struct platform_device *pdev)
342{
343 struct xgbe_prv_data *pdata;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500344 struct net_device *netdev;
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500345 struct device *dev = &pdev->dev;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500346 struct platform_device *phy_pdev;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500347 struct resource *res;
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600348 const char *phy_mode;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500349 unsigned int i, phy_memnum, phy_irqnum;
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700350 enum dev_dma_attr attr;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500351 int ret;
352
353 DBGPR("--> xgbe_probe\n");
354
355 netdev = alloc_etherdev_mq(sizeof(struct xgbe_prv_data),
Lendacky, Thomasd5c48582014-06-09 09:19:32 -0500356 XGBE_MAX_DMA_CHANNELS);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500357 if (!netdev) {
358 dev_err(dev, "alloc_etherdev failed\n");
359 ret = -ENOMEM;
360 goto err_alloc;
361 }
362 SET_NETDEV_DEV(netdev, dev);
363 pdata = netdev_priv(netdev);
364 pdata->netdev = netdev;
365 pdata->pdev = pdev;
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600366 pdata->adev = ACPI_COMPANION(dev);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500367 pdata->dev = dev;
368 platform_set_drvdata(pdev, netdev);
369
370 spin_lock_init(&pdata->lock);
Lendacky, Thomasced3fca2016-02-17 11:49:28 -0600371 spin_lock_init(&pdata->xpcs_lock);
Lendacky, Thomas5b9dfe22014-11-04 16:07:02 -0600372 mutex_init(&pdata->rss_mutex);
Lendacky, Thomas23e4eef2014-07-29 08:57:19 -0500373 spin_lock_init(&pdata->tstamp_lock);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500374
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -0500375 pdata->msg_enable = netif_msg_init(debug, default_msg_level);
376
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500377 set_bit(XGBE_DOWN, &pdata->dev_state);
378
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600379 /* Check if we should use ACPI or DT */
Lendacky, Thomas47f2e6c2015-09-30 08:52:45 -0500380 pdata->use_acpi = dev->of_node ? 0 : 1;
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600381
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500382 /* Get the version data */
383 pdata->vdata = xgbe_get_vdata(pdata);
384
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500385 phy_pdev = xgbe_get_phy_pdev(pdata);
386 if (!phy_pdev) {
387 dev_err(dev, "unable to obtain phy device\n");
388 ret = -EINVAL;
389 goto err_phydev;
390 }
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500391 pdata->phy_pdev = phy_pdev;
392 pdata->phy_dev = &phy_pdev->dev;
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500393
394 if (pdev == phy_pdev) {
Lendacky, Thomas34bfff42015-05-14 11:44:21 -0500395 /* New style device tree or ACPI:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500396 * The XGBE and PHY resources are grouped together with
397 * the PHY resources listed last
398 */
399 phy_memnum = xgbe_resource_count(pdev, IORESOURCE_MEM) - 3;
400 phy_irqnum = xgbe_resource_count(pdev, IORESOURCE_IRQ) - 1;
401 } else {
Lendacky, Thomas34bfff42015-05-14 11:44:21 -0500402 /* Old style device tree:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500403 * The XGBE and PHY resources are separate
404 */
405 phy_memnum = 0;
406 phy_irqnum = 0;
407 }
408
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500409 /* Set and validate the number of descriptors for a ring */
Lendacky, Thomasd0a8ba62014-06-24 16:19:06 -0500410 BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
411 pdata->tx_desc_count = XGBE_TX_DESC_CNT;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500412 if (pdata->tx_desc_count & (pdata->tx_desc_count - 1)) {
413 dev_err(dev, "tx descriptor count (%d) is not valid\n",
414 pdata->tx_desc_count);
415 ret = -EINVAL;
416 goto err_io;
417 }
Lendacky, Thomasd0a8ba62014-06-24 16:19:06 -0500418 BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_RX_DESC_CNT);
419 pdata->rx_desc_count = XGBE_RX_DESC_CNT;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500420 if (pdata->rx_desc_count & (pdata->rx_desc_count - 1)) {
421 dev_err(dev, "rx descriptor count (%d) is not valid\n",
422 pdata->rx_desc_count);
423 ret = -EINVAL;
424 goto err_io;
425 }
426
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500427 /* Obtain the mmio areas for the device */
428 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
429 pdata->xgmac_regs = devm_ioremap_resource(dev, res);
430 if (IS_ERR(pdata->xgmac_regs)) {
431 dev_err(dev, "xgmac ioremap failed\n");
432 ret = PTR_ERR(pdata->xgmac_regs);
433 goto err_io;
434 }
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -0500435 if (netif_msg_probe(pdata))
436 dev_dbg(dev, "xgmac_regs = %p\n", pdata->xgmac_regs);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500437
438 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
439 pdata->xpcs_regs = devm_ioremap_resource(dev, res);
440 if (IS_ERR(pdata->xpcs_regs)) {
441 dev_err(dev, "xpcs ioremap failed\n");
442 ret = PTR_ERR(pdata->xpcs_regs);
443 goto err_io;
444 }
Lendacky, Thomas34bf65d2015-05-14 11:44:03 -0500445 if (netif_msg_probe(pdata))
446 dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500447
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500448 res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
449 pdata->rxtx_regs = devm_ioremap_resource(dev, res);
450 if (IS_ERR(pdata->rxtx_regs)) {
451 dev_err(dev, "rxtx ioremap failed\n");
452 ret = PTR_ERR(pdata->rxtx_regs);
453 goto err_io;
454 }
455 if (netif_msg_probe(pdata))
456 dev_dbg(dev, "rxtx_regs = %p\n", pdata->rxtx_regs);
457
458 res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
459 pdata->sir0_regs = devm_ioremap_resource(dev, res);
460 if (IS_ERR(pdata->sir0_regs)) {
461 dev_err(dev, "sir0 ioremap failed\n");
462 ret = PTR_ERR(pdata->sir0_regs);
463 goto err_io;
464 }
465 if (netif_msg_probe(pdata))
466 dev_dbg(dev, "sir0_regs = %p\n", pdata->sir0_regs);
467
468 res = platform_get_resource(phy_pdev, IORESOURCE_MEM, phy_memnum++);
469 pdata->sir1_regs = devm_ioremap_resource(dev, res);
470 if (IS_ERR(pdata->sir1_regs)) {
471 dev_err(dev, "sir1 ioremap failed\n");
472 ret = PTR_ERR(pdata->sir1_regs);
473 goto err_io;
474 }
475 if (netif_msg_probe(pdata))
476 dev_dbg(dev, "sir1_regs = %p\n", pdata->sir1_regs);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500477
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600478 /* Retrieve the MAC address */
479 ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
480 pdata->mac_addr,
481 sizeof(pdata->mac_addr));
482 if (ret || !is_valid_ether_addr(pdata->mac_addr)) {
483 dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY);
484 if (!ret)
485 ret = -EINVAL;
Lendacky, Thomasf3d0e782014-08-05 13:30:38 -0500486 goto err_io;
487 }
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500488
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600489 /* Retrieve the PHY mode - it must be "xgmii" */
490 ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY,
491 &phy_mode);
492 if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) {
493 dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY);
494 if (!ret)
495 ret = -EINVAL;
496 goto err_io;
497 }
498 pdata->phy_mode = PHY_INTERFACE_MODE_XGMII;
499
500 /* Check for per channel interrupt support */
501 if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
502 pdata->per_channel_irq = 1;
503
504 /* Obtain device settings unique to ACPI/OF */
505 if (pdata->use_acpi)
506 ret = xgbe_acpi_support(pdata);
507 else
508 ret = xgbe_of_support(pdata);
509 if (ret)
510 goto err_io;
511
512 /* Set the DMA coherency values */
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700513 attr = device_get_dma_attr(dev);
514 if (attr == DEV_DMA_NOT_SUPPORTED) {
515 dev_err(dev, "DMA is not supported");
Wei Yongjun675a6ce2016-10-22 14:35:30 +0000516 ret = -ENODEV;
Suthikulpanit, Suravee1831eff2015-10-28 15:50:50 -0700517 goto err_io;
518 }
519 pdata->coherent = (attr == DEV_DMA_COHERENT);
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600520 if (pdata->coherent) {
Lendacky, Thomascfa50c72014-07-02 13:04:57 -0500521 pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
522 pdata->arcache = XGBE_DMA_OS_ARCACHE;
523 pdata->awcache = XGBE_DMA_OS_AWCACHE;
524 } else {
525 pdata->axdomain = XGBE_DMA_SYS_AXDOMAIN;
526 pdata->arcache = XGBE_DMA_SYS_ARCACHE;
527 pdata->awcache = XGBE_DMA_SYS_AWCACHE;
528 }
529
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600530 /* Get the device interrupt */
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500531 ret = platform_get_irq(pdev, 0);
532 if (ret < 0) {
Lendacky, Thomas9227dc52014-11-04 16:06:56 -0600533 dev_err(dev, "platform_get_irq 0 failed\n");
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500534 goto err_io;
535 }
Lendacky, Thomas9227dc52014-11-04 16:06:56 -0600536 pdata->dev_irq = ret;
537
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500538 /* Get the auto-negotiation interrupt */
539 ret = platform_get_irq(phy_pdev, phy_irqnum++);
540 if (ret < 0) {
541 dev_err(dev, "platform_get_irq phy 0 failed\n");
542 goto err_io;
543 }
544 pdata->an_irq = ret;
545
Lendacky, Thomas9227dc52014-11-04 16:06:56 -0600546 netdev->irq = pdata->dev_irq;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500547 netdev->base_addr = (unsigned long)pdata->xgmac_regs;
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600548 memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500549
550 /* Set all the function pointers */
551 xgbe_init_all_fptrs(pdata);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500552
553 /* Issue software reset to device */
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500554 pdata->hw_if.exit(pdata);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500555
556 /* Populate the hardware features */
557 xgbe_get_all_hw_features(pdata);
558
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500559 /* Set default configuration data */
560 xgbe_default_config(pdata);
561
Lendacky, Thomas386d3252015-03-20 11:50:22 -0500562 /* Set the DMA mask */
Lendacky, Thomas386d3252015-03-20 11:50:22 -0500563 ret = dma_set_mask_and_coherent(dev,
564 DMA_BIT_MASK(pdata->hw_feat.dma_width));
565 if (ret) {
566 dev_err(dev, "dma_set_mask_and_coherent failed\n");
567 goto err_io;
568 }
569
Lendacky, Thomas853eb162014-07-29 08:57:31 -0500570 /* Calculate the number of Tx and Rx rings to be created
571 * -Tx (DMA) Channels map 1-to-1 to Tx Queues so set
572 * the number of Tx queues to the number of Tx channels
573 * enabled
574 * -Rx (DMA) Channels do not map 1-to-1 so use the actual
575 * number of Rx queues
576 */
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500577 pdata->tx_ring_count = min_t(unsigned int, num_online_cpus(),
578 pdata->hw_feat.tx_ch_cnt);
Lendacky, Thomas853eb162014-07-29 08:57:31 -0500579 pdata->tx_q_count = pdata->tx_ring_count;
Wei Yongjun332cfc82014-07-23 08:59:40 +0800580 ret = netif_set_real_num_tx_queues(netdev, pdata->tx_ring_count);
581 if (ret) {
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500582 dev_err(dev, "error setting real tx queue count\n");
583 goto err_io;
584 }
585
586 pdata->rx_ring_count = min_t(unsigned int,
587 netif_get_num_default_rss_queues(),
588 pdata->hw_feat.rx_ch_cnt);
Lendacky, Thomas853eb162014-07-29 08:57:31 -0500589 pdata->rx_q_count = pdata->hw_feat.rx_q_cnt;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500590 ret = netif_set_real_num_rx_queues(netdev, pdata->rx_ring_count);
591 if (ret) {
592 dev_err(dev, "error setting real rx queue count\n");
593 goto err_io;
594 }
595
Lendacky, Thomas5b9dfe22014-11-04 16:07:02 -0600596 /* Initialize RSS hash key and lookup table */
Eric Dumazetb2306302014-11-16 06:23:06 -0800597 netdev_rss_key_fill(pdata->rss_key, sizeof(pdata->rss_key));
Lendacky, Thomas5b9dfe22014-11-04 16:07:02 -0600598
599 for (i = 0; i < XGBE_RSS_MAX_TABLE_SIZE; i++)
600 XGMAC_SET_BITS(pdata->rss_table[i], MAC_RSSDR, DMCH,
601 i % pdata->rx_ring_count);
602
603 XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, IP2TE, 1);
604 XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, TCP4TE, 1);
605 XGMAC_SET_BITS(pdata->rss_options, MAC_RSSCR, UDP4TE, 1);
606
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500607 /* Call MDIO/PHY initialization routine */
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500608 ret = pdata->phy_if.phy_init(pdata);
609 if (ret)
610 goto err_io;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500611
Lendacky, Thomasfca2d992014-07-29 08:57:55 -0500612 /* Set device operations */
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500613 netdev->netdev_ops = xgbe_get_netdev_ops();
614 netdev->ethtool_ops = xgbe_get_ethtool_ops();
Lendacky, Thomasfca2d992014-07-29 08:57:55 -0500615#ifdef CONFIG_AMD_XGBE_DCB
616 netdev->dcbnl_ops = xgbe_get_dcbnl_ops();
617#endif
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500618
619 /* Set device features */
620 netdev->hw_features = NETIF_F_SG |
621 NETIF_F_IP_CSUM |
622 NETIF_F_IPV6_CSUM |
623 NETIF_F_RXCSUM |
624 NETIF_F_TSO |
625 NETIF_F_TSO6 |
626 NETIF_F_GRO |
627 NETIF_F_HW_VLAN_CTAG_RX |
Lendacky, Thomas801c62d2014-06-24 16:19:24 -0500628 NETIF_F_HW_VLAN_CTAG_TX |
629 NETIF_F_HW_VLAN_CTAG_FILTER;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500630
Lendacky, Thomas5b9dfe22014-11-04 16:07:02 -0600631 if (pdata->hw_feat.rss)
632 netdev->hw_features |= NETIF_F_RXHASH;
633
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500634 netdev->vlan_features |= NETIF_F_SG |
635 NETIF_F_IP_CSUM |
636 NETIF_F_IPV6_CSUM |
637 NETIF_F_TSO |
638 NETIF_F_TSO6;
639
640 netdev->features |= netdev->hw_features;
641 pdata->netdev_features = netdev->features;
642
Lendacky, Thomasb85e4d82014-06-24 16:19:29 -0500643 netdev->priv_flags |= IFF_UNICAST_FLT;
Jarod Wilsond894be52016-10-20 13:55:16 -0400644 netdev->min_mtu = 0;
645 netdev->max_mtu = XGMAC_JUMBO_PACKET_MTU;
Lendacky, Thomasb85e4d82014-06-24 16:19:29 -0500646
Lendacky, Thomasa8373f12015-04-09 12:12:03 -0500647 /* Use default watchdog timeout */
648 netdev->watchdog_timeo = 0;
649
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500650 xgbe_init_rx_coalesce(pdata);
651 xgbe_init_tx_coalesce(pdata);
652
653 netif_carrier_off(netdev);
654 ret = register_netdev(netdev);
655 if (ret) {
656 dev_err(dev, "net device registration failed\n");
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500657 goto err_io;
658 }
659
660 /* Create the PHY/ANEG name based on netdev name */
661 snprintf(pdata->an_name, sizeof(pdata->an_name) - 1, "%s-pcs",
662 netdev_name(netdev));
663
664 /* Create workqueues */
665 pdata->dev_workqueue =
666 create_singlethread_workqueue(netdev_name(netdev));
667 if (!pdata->dev_workqueue) {
668 netdev_err(netdev, "device workqueue creation failed\n");
669 ret = -ENOMEM;
670 goto err_netdev;
671 }
672
673 pdata->an_workqueue =
674 create_singlethread_workqueue(pdata->an_name);
675 if (!pdata->an_workqueue) {
676 netdev_err(netdev, "phy workqueue creation failed\n");
677 ret = -ENOMEM;
678 goto err_wq;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500679 }
680
Lendacky, Thomas23e4eef2014-07-29 08:57:19 -0500681 xgbe_ptp_register(pdata);
682
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500683 xgbe_debugfs_init(pdata);
684
685 netdev_notice(netdev, "net device enabled\n");
686
687 DBGPR("<-- xgbe_probe\n");
688
689 return 0;
690
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500691err_wq:
692 destroy_workqueue(pdata->dev_workqueue);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500693
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500694err_netdev:
695 unregister_netdev(netdev);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500696
697err_io:
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500698 platform_device_put(phy_pdev);
699
700err_phydev:
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500701 free_netdev(netdev);
702
703err_alloc:
704 dev_notice(dev, "net device not enabled\n");
705
706 return ret;
707}
708
709static int xgbe_remove(struct platform_device *pdev)
710{
711 struct net_device *netdev = platform_get_drvdata(pdev);
712 struct xgbe_prv_data *pdata = netdev_priv(netdev);
713
714 DBGPR("-->xgbe_remove\n");
715
716 xgbe_debugfs_exit(pdata);
717
Lendacky, Thomas23e4eef2014-07-29 08:57:19 -0500718 xgbe_ptp_unregister(pdata);
719
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500720 pdata->phy_if.phy_exit(pdata);
721
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500722 flush_workqueue(pdata->an_workqueue);
723 destroy_workqueue(pdata->an_workqueue);
724
725 flush_workqueue(pdata->dev_workqueue);
726 destroy_workqueue(pdata->dev_workqueue);
727
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500728 unregister_netdev(netdev);
729
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500730 platform_device_put(pdata->phy_pdev);
731
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500732 free_netdev(netdev);
733
734 DBGPR("<--xgbe_remove\n");
735
736 return 0;
737}
738
739#ifdef CONFIG_PM
740static int xgbe_suspend(struct device *dev)
741{
742 struct net_device *netdev = dev_get_drvdata(dev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500743 struct xgbe_prv_data *pdata = netdev_priv(netdev);
744 int ret = 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500745
746 DBGPR("-->xgbe_suspend\n");
747
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500748 if (netif_running(netdev))
749 ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500750
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500751 pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
752 pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER;
753 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500754
755 DBGPR("<--xgbe_suspend\n");
756
757 return ret;
758}
759
760static int xgbe_resume(struct device *dev)
761{
762 struct net_device *netdev = dev_get_drvdata(dev);
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500763 struct xgbe_prv_data *pdata = netdev_priv(netdev);
764 int ret = 0;
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500765
766 DBGPR("-->xgbe_resume\n");
767
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500768 pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
769 XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500770
James Morsea039b632016-08-26 09:21:23 +0100771 if (netif_running(netdev)) {
Lendacky, Thomas7c12aa02015-05-14 11:44:15 -0500772 ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500773
James Morsea039b632016-08-26 09:21:23 +0100774 /* Schedule a restart in case the link or phy state changed
775 * while we were powered down.
776 */
777 schedule_work(&pdata->restart_work);
778 }
779
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500780 DBGPR("<--xgbe_resume\n");
781
782 return ret;
783}
784#endif /* CONFIG_PM */
785
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500786static const struct xgbe_version_data xgbe_v1 = {
787 .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v1,
788};
789
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600790#ifdef CONFIG_ACPI
791static const struct acpi_device_id xgbe_acpi_match[] = {
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500792 { .id = "AMDI8001",
793 .driver_data = (kernel_ulong_t)&xgbe_v1 },
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600794 {},
795};
796
797MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match);
798#endif
799
800#ifdef CONFIG_OF
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500801static const struct of_device_id xgbe_of_match[] = {
Lendacky, Thomase57f7a32016-11-03 13:18:27 -0500802 { .compatible = "amd,xgbe-seattle-v1a",
803 .data = &xgbe_v1 },
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500804 {},
805};
806
807MODULE_DEVICE_TABLE(of, xgbe_of_match);
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600808#endif
809
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500810static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume);
811
812static struct platform_driver xgbe_driver = {
813 .driver = {
814 .name = "amd-xgbe",
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600815#ifdef CONFIG_ACPI
816 .acpi_match_table = xgbe_acpi_match,
817#endif
818#ifdef CONFIG_OF
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500819 .of_match_table = xgbe_of_match,
Lendacky, Thomas82a19032015-01-16 12:47:16 -0600820#endif
Lendacky, Thomasc5aa9e32014-06-05 09:15:06 -0500821 .pm = &xgbe_pm_ops,
822 },
823 .probe = xgbe_probe,
824 .remove = xgbe_remove,
825};
826
827module_platform_driver(xgbe_driver);