162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * AMD 10Gb Ethernet driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is available to you under your choice of the following two
562306a36Sopenharmony_ci * licenses:
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * License 1: GPLv2
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * This file is free software; you may copy, redistribute and/or modify
1262306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
1362306a36Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or (at
1462306a36Sopenharmony_ci * your option) any later version.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but
1762306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
1862306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1962306a36Sopenharmony_ci * General Public License for more details.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
2262306a36Sopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
2562306a36Sopenharmony_ci * permission notice:
2662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
2762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
2862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
2962306a36Sopenharmony_ci *     and you.
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
3262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
3362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
3462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
3562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
3662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
3762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
3862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
3962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
4262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
4562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
4762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
4862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
5462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * License 2: Modified BSD
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Copyright (c) 2016 Advanced Micro Devices, Inc.
6062306a36Sopenharmony_ci * All rights reserved.
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
6362306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
6462306a36Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
6562306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer.
6662306a36Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
6762306a36Sopenharmony_ci *       notice, this list of conditions and the following disclaimer in the
6862306a36Sopenharmony_ci *       documentation and/or other materials provided with the distribution.
6962306a36Sopenharmony_ci *     * Neither the name of Advanced Micro Devices, Inc. nor the
7062306a36Sopenharmony_ci *       names of its contributors may be used to endorse or promote products
7162306a36Sopenharmony_ci *       derived from this software without specific prior written permission.
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
7462306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
7562306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
7662306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
7762306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7862306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7962306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
8062306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
8162306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
8262306a36Sopenharmony_ci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8362306a36Sopenharmony_ci *
8462306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and
8562306a36Sopenharmony_ci * permission notice:
8662306a36Sopenharmony_ci *     The Synopsys DWC ETHER XGMAC Software Driver and documentation
8762306a36Sopenharmony_ci *     (hereinafter "Software") is an unsupported proprietary work of Synopsys,
8862306a36Sopenharmony_ci *     Inc. unless otherwise expressly agreed to in writing between Synopsys
8962306a36Sopenharmony_ci *     and you.
9062306a36Sopenharmony_ci *
9162306a36Sopenharmony_ci *     The Software IS NOT an item of Licensed Software or Licensed Product
9262306a36Sopenharmony_ci *     under any End User Software License Agreement or Agreement for Licensed
9362306a36Sopenharmony_ci *     Product with Synopsys or any supplement thereto.  Permission is hereby
9462306a36Sopenharmony_ci *     granted, free of charge, to any person obtaining a copy of this software
9562306a36Sopenharmony_ci *     annotated with this license and the Software, to deal in the Software
9662306a36Sopenharmony_ci *     without restriction, including without limitation the rights to use,
9762306a36Sopenharmony_ci *     copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9862306a36Sopenharmony_ci *     of the Software, and to permit persons to whom the Software is furnished
9962306a36Sopenharmony_ci *     to do so, subject to the following conditions:
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci *     The above copyright notice and this permission notice shall be included
10262306a36Sopenharmony_ci *     in all copies or substantial portions of the Software.
10362306a36Sopenharmony_ci *
10462306a36Sopenharmony_ci *     THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
10562306a36Sopenharmony_ci *     BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
10662306a36Sopenharmony_ci *     TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
10762306a36Sopenharmony_ci *     PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS
10862306a36Sopenharmony_ci *     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10962306a36Sopenharmony_ci *     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
11062306a36Sopenharmony_ci *     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
11162306a36Sopenharmony_ci *     INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
11262306a36Sopenharmony_ci *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
11362306a36Sopenharmony_ci *     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
11462306a36Sopenharmony_ci *     THE POSSIBILITY OF SUCH DAMAGE.
11562306a36Sopenharmony_ci */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#include <linux/module.h>
11862306a36Sopenharmony_ci#include <linux/device.h>
11962306a36Sopenharmony_ci#include <linux/pci.h>
12062306a36Sopenharmony_ci#include <linux/log2.h>
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#include "xgbe.h"
12362306a36Sopenharmony_ci#include "xgbe-common.h"
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int xgbe_config_multi_msi(struct xgbe_prv_data *pdata)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	unsigned int vector_count;
12862306a36Sopenharmony_ci	unsigned int i, j;
12962306a36Sopenharmony_ci	int ret;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	vector_count = XGBE_MSI_BASE_COUNT;
13262306a36Sopenharmony_ci	vector_count += max(pdata->rx_ring_count,
13362306a36Sopenharmony_ci			    pdata->tx_ring_count);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(pdata->pcidev, XGBE_MSI_MIN_COUNT,
13662306a36Sopenharmony_ci				    vector_count, PCI_IRQ_MSI | PCI_IRQ_MSIX);
13762306a36Sopenharmony_ci	if (ret < 0) {
13862306a36Sopenharmony_ci		dev_info(pdata->dev, "multi MSI/MSI-X enablement failed\n");
13962306a36Sopenharmony_ci		return ret;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	pdata->isr_as_tasklet = 1;
14362306a36Sopenharmony_ci	pdata->irq_count = ret;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0);
14662306a36Sopenharmony_ci	pdata->ecc_irq = pci_irq_vector(pdata->pcidev, 1);
14762306a36Sopenharmony_ci	pdata->i2c_irq = pci_irq_vector(pdata->pcidev, 2);
14862306a36Sopenharmony_ci	pdata->an_irq = pci_irq_vector(pdata->pcidev, 3);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	for (i = XGBE_MSI_BASE_COUNT, j = 0; i < ret; i++, j++)
15162306a36Sopenharmony_ci		pdata->channel_irq[j] = pci_irq_vector(pdata->pcidev, i);
15262306a36Sopenharmony_ci	pdata->channel_irq_count = j;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	pdata->per_channel_irq = 1;
15562306a36Sopenharmony_ci	pdata->channel_irq_mode = XGBE_IRQ_MODE_LEVEL;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (netif_msg_probe(pdata))
15862306a36Sopenharmony_ci		dev_dbg(pdata->dev, "multi %s interrupts enabled\n",
15962306a36Sopenharmony_ci			pdata->pcidev->msix_enabled ? "MSI-X" : "MSI");
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return 0;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic int xgbe_config_irqs(struct xgbe_prv_data *pdata)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int ret;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	ret = xgbe_config_multi_msi(pdata);
16962306a36Sopenharmony_ci	if (!ret)
17062306a36Sopenharmony_ci		goto out;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(pdata->pcidev, 1, 1,
17362306a36Sopenharmony_ci				    PCI_IRQ_LEGACY | PCI_IRQ_MSI);
17462306a36Sopenharmony_ci	if (ret < 0) {
17562306a36Sopenharmony_ci		dev_info(pdata->dev, "single IRQ enablement failed\n");
17662306a36Sopenharmony_ci		return ret;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	pdata->isr_as_tasklet = pdata->pcidev->msi_enabled ? 1 : 0;
18062306a36Sopenharmony_ci	pdata->irq_count = 1;
18162306a36Sopenharmony_ci	pdata->channel_irq_count = 1;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	pdata->dev_irq = pci_irq_vector(pdata->pcidev, 0);
18462306a36Sopenharmony_ci	pdata->ecc_irq = pci_irq_vector(pdata->pcidev, 0);
18562306a36Sopenharmony_ci	pdata->i2c_irq = pci_irq_vector(pdata->pcidev, 0);
18662306a36Sopenharmony_ci	pdata->an_irq = pci_irq_vector(pdata->pcidev, 0);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	if (netif_msg_probe(pdata))
18962306a36Sopenharmony_ci		dev_dbg(pdata->dev, "single %s interrupt enabled\n",
19062306a36Sopenharmony_ci			pdata->pcidev->msi_enabled ?  "MSI" : "legacy");
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ciout:
19362306a36Sopenharmony_ci	if (netif_msg_probe(pdata)) {
19462306a36Sopenharmony_ci		unsigned int i;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		dev_dbg(pdata->dev, " dev irq=%d\n", pdata->dev_irq);
19762306a36Sopenharmony_ci		dev_dbg(pdata->dev, " ecc irq=%d\n", pdata->ecc_irq);
19862306a36Sopenharmony_ci		dev_dbg(pdata->dev, " i2c irq=%d\n", pdata->i2c_irq);
19962306a36Sopenharmony_ci		dev_dbg(pdata->dev, "  an irq=%d\n", pdata->an_irq);
20062306a36Sopenharmony_ci		for (i = 0; i < pdata->channel_irq_count; i++)
20162306a36Sopenharmony_ci			dev_dbg(pdata->dev, " dma%u irq=%d\n",
20262306a36Sopenharmony_ci				i, pdata->channel_irq[i]);
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct xgbe_prv_data *pdata;
21162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
21262306a36Sopenharmony_ci	void __iomem * const *iomap_table;
21362306a36Sopenharmony_ci	struct pci_dev *rdev;
21462306a36Sopenharmony_ci	unsigned int ma_lo, ma_hi;
21562306a36Sopenharmony_ci	unsigned int reg;
21662306a36Sopenharmony_ci	int bar_mask;
21762306a36Sopenharmony_ci	int ret;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	pdata = xgbe_alloc_pdata(dev);
22062306a36Sopenharmony_ci	if (IS_ERR(pdata)) {
22162306a36Sopenharmony_ci		ret = PTR_ERR(pdata);
22262306a36Sopenharmony_ci		goto err_alloc;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	pdata->pcidev = pdev;
22662306a36Sopenharmony_ci	pci_set_drvdata(pdev, pdata);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* Get the version data */
22962306a36Sopenharmony_ci	pdata->vdata = (struct xgbe_version_data *)id->driver_data;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ret = pcim_enable_device(pdev);
23262306a36Sopenharmony_ci	if (ret) {
23362306a36Sopenharmony_ci		dev_err(dev, "pcim_enable_device failed\n");
23462306a36Sopenharmony_ci		goto err_pci_enable;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Obtain the mmio areas for the device */
23862306a36Sopenharmony_ci	bar_mask = pci_select_bars(pdev, IORESOURCE_MEM);
23962306a36Sopenharmony_ci	ret = pcim_iomap_regions(pdev, bar_mask, XGBE_DRV_NAME);
24062306a36Sopenharmony_ci	if (ret) {
24162306a36Sopenharmony_ci		dev_err(dev, "pcim_iomap_regions failed\n");
24262306a36Sopenharmony_ci		goto err_pci_enable;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	iomap_table = pcim_iomap_table(pdev);
24662306a36Sopenharmony_ci	if (!iomap_table) {
24762306a36Sopenharmony_ci		dev_err(dev, "pcim_iomap_table failed\n");
24862306a36Sopenharmony_ci		ret = -ENOMEM;
24962306a36Sopenharmony_ci		goto err_pci_enable;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	pdata->xgmac_regs = iomap_table[XGBE_XGMAC_BAR];
25362306a36Sopenharmony_ci	if (!pdata->xgmac_regs) {
25462306a36Sopenharmony_ci		dev_err(dev, "xgmac ioremap failed\n");
25562306a36Sopenharmony_ci		ret = -ENOMEM;
25662306a36Sopenharmony_ci		goto err_pci_enable;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci	pdata->xprop_regs = pdata->xgmac_regs + XGBE_MAC_PROP_OFFSET;
25962306a36Sopenharmony_ci	pdata->xi2c_regs = pdata->xgmac_regs + XGBE_I2C_CTRL_OFFSET;
26062306a36Sopenharmony_ci	if (netif_msg_probe(pdata)) {
26162306a36Sopenharmony_ci		dev_dbg(dev, "xgmac_regs = %p\n", pdata->xgmac_regs);
26262306a36Sopenharmony_ci		dev_dbg(dev, "xprop_regs = %p\n", pdata->xprop_regs);
26362306a36Sopenharmony_ci		dev_dbg(dev, "xi2c_regs  = %p\n", pdata->xi2c_regs);
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	pdata->xpcs_regs = iomap_table[XGBE_XPCS_BAR];
26762306a36Sopenharmony_ci	if (!pdata->xpcs_regs) {
26862306a36Sopenharmony_ci		dev_err(dev, "xpcs ioremap failed\n");
26962306a36Sopenharmony_ci		ret = -ENOMEM;
27062306a36Sopenharmony_ci		goto err_pci_enable;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci	if (netif_msg_probe(pdata))
27362306a36Sopenharmony_ci		dev_dbg(dev, "xpcs_regs  = %p\n", pdata->xpcs_regs);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* Set the PCS indirect addressing definition registers */
27662306a36Sopenharmony_ci	rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
27762306a36Sopenharmony_ci	if (rdev &&
27862306a36Sopenharmony_ci	    (rdev->vendor == PCI_VENDOR_ID_AMD) && (rdev->device == 0x15d0)) {
27962306a36Sopenharmony_ci		pdata->xpcs_window_def_reg = PCS_V2_RV_WINDOW_DEF;
28062306a36Sopenharmony_ci		pdata->xpcs_window_sel_reg = PCS_V2_RV_WINDOW_SELECT;
28162306a36Sopenharmony_ci	} else if (rdev && (rdev->vendor == PCI_VENDOR_ID_AMD) &&
28262306a36Sopenharmony_ci		   (rdev->device == 0x14b5)) {
28362306a36Sopenharmony_ci		pdata->xpcs_window_def_reg = PCS_V2_YC_WINDOW_DEF;
28462306a36Sopenharmony_ci		pdata->xpcs_window_sel_reg = PCS_V2_YC_WINDOW_SELECT;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		/* Yellow Carp devices do not need cdr workaround */
28762306a36Sopenharmony_ci		pdata->vdata->an_cdr_workaround = 0;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		/* Yellow Carp devices do not need rrc */
29062306a36Sopenharmony_ci		pdata->vdata->enable_rrc = 0;
29162306a36Sopenharmony_ci	} else {
29262306a36Sopenharmony_ci		pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
29362306a36Sopenharmony_ci		pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci	pci_dev_put(rdev);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* Configure the PCS indirect addressing support */
29862306a36Sopenharmony_ci	reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg);
29962306a36Sopenharmony_ci	pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET);
30062306a36Sopenharmony_ci	pdata->xpcs_window <<= 6;
30162306a36Sopenharmony_ci	pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE);
30262306a36Sopenharmony_ci	pdata->xpcs_window_size = 1 << (pdata->xpcs_window_size + 7);
30362306a36Sopenharmony_ci	pdata->xpcs_window_mask = pdata->xpcs_window_size - 1;
30462306a36Sopenharmony_ci	if (netif_msg_probe(pdata)) {
30562306a36Sopenharmony_ci		dev_dbg(dev, "xpcs window def  = %#010x\n",
30662306a36Sopenharmony_ci			pdata->xpcs_window_def_reg);
30762306a36Sopenharmony_ci		dev_dbg(dev, "xpcs window sel  = %#010x\n",
30862306a36Sopenharmony_ci			pdata->xpcs_window_sel_reg);
30962306a36Sopenharmony_ci		dev_dbg(dev, "xpcs window      = %#010x\n",
31062306a36Sopenharmony_ci			pdata->xpcs_window);
31162306a36Sopenharmony_ci		dev_dbg(dev, "xpcs window size = %#010x\n",
31262306a36Sopenharmony_ci			pdata->xpcs_window_size);
31362306a36Sopenharmony_ci		dev_dbg(dev, "xpcs window mask = %#010x\n",
31462306a36Sopenharmony_ci			pdata->xpcs_window_mask);
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	pci_set_master(pdev);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Enable all interrupts in the hardware */
32062306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/* Retrieve the MAC address */
32362306a36Sopenharmony_ci	ma_lo = XP_IOREAD(pdata, XP_MAC_ADDR_LO);
32462306a36Sopenharmony_ci	ma_hi = XP_IOREAD(pdata, XP_MAC_ADDR_HI);
32562306a36Sopenharmony_ci	pdata->mac_addr[0] = ma_lo & 0xff;
32662306a36Sopenharmony_ci	pdata->mac_addr[1] = (ma_lo >> 8) & 0xff;
32762306a36Sopenharmony_ci	pdata->mac_addr[2] = (ma_lo >> 16) & 0xff;
32862306a36Sopenharmony_ci	pdata->mac_addr[3] = (ma_lo >> 24) & 0xff;
32962306a36Sopenharmony_ci	pdata->mac_addr[4] = ma_hi & 0xff;
33062306a36Sopenharmony_ci	pdata->mac_addr[5] = (ma_hi >> 8) & 0xff;
33162306a36Sopenharmony_ci	if (!XP_GET_BITS(ma_hi, XP_MAC_ADDR_HI, VALID) ||
33262306a36Sopenharmony_ci	    !is_valid_ether_addr(pdata->mac_addr)) {
33362306a36Sopenharmony_ci		dev_err(dev, "invalid mac address\n");
33462306a36Sopenharmony_ci		ret = -EINVAL;
33562306a36Sopenharmony_ci		goto err_pci_enable;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Clock settings */
33962306a36Sopenharmony_ci	pdata->sysclk_rate = XGBE_V2_DMA_CLOCK_FREQ;
34062306a36Sopenharmony_ci	pdata->ptpclk_rate = XGBE_V2_PTP_CLOCK_FREQ;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Set the DMA coherency values */
34362306a36Sopenharmony_ci	pdata->coherent = 1;
34462306a36Sopenharmony_ci	pdata->arcr = XGBE_DMA_PCI_ARCR;
34562306a36Sopenharmony_ci	pdata->awcr = XGBE_DMA_PCI_AWCR;
34662306a36Sopenharmony_ci	pdata->awarcr = XGBE_DMA_PCI_AWARCR;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Read the port property registers */
34962306a36Sopenharmony_ci	pdata->pp0 = XP_IOREAD(pdata, XP_PROP_0);
35062306a36Sopenharmony_ci	pdata->pp1 = XP_IOREAD(pdata, XP_PROP_1);
35162306a36Sopenharmony_ci	pdata->pp2 = XP_IOREAD(pdata, XP_PROP_2);
35262306a36Sopenharmony_ci	pdata->pp3 = XP_IOREAD(pdata, XP_PROP_3);
35362306a36Sopenharmony_ci	pdata->pp4 = XP_IOREAD(pdata, XP_PROP_4);
35462306a36Sopenharmony_ci	if (netif_msg_probe(pdata)) {
35562306a36Sopenharmony_ci		dev_dbg(dev, "port property 0 = %#010x\n", pdata->pp0);
35662306a36Sopenharmony_ci		dev_dbg(dev, "port property 1 = %#010x\n", pdata->pp1);
35762306a36Sopenharmony_ci		dev_dbg(dev, "port property 2 = %#010x\n", pdata->pp2);
35862306a36Sopenharmony_ci		dev_dbg(dev, "port property 3 = %#010x\n", pdata->pp3);
35962306a36Sopenharmony_ci		dev_dbg(dev, "port property 4 = %#010x\n", pdata->pp4);
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Set the maximum channels and queues */
36362306a36Sopenharmony_ci	pdata->tx_max_channel_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
36462306a36Sopenharmony_ci						  MAX_TX_DMA);
36562306a36Sopenharmony_ci	pdata->rx_max_channel_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
36662306a36Sopenharmony_ci						  MAX_RX_DMA);
36762306a36Sopenharmony_ci	pdata->tx_max_q_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
36862306a36Sopenharmony_ci					    MAX_TX_QUEUES);
36962306a36Sopenharmony_ci	pdata->rx_max_q_count = XP_GET_BITS(pdata->pp1, XP_PROP_1,
37062306a36Sopenharmony_ci					    MAX_RX_QUEUES);
37162306a36Sopenharmony_ci	if (netif_msg_probe(pdata)) {
37262306a36Sopenharmony_ci		dev_dbg(dev, "max tx/rx channel count = %u/%u\n",
37362306a36Sopenharmony_ci			pdata->tx_max_channel_count,
37462306a36Sopenharmony_ci			pdata->rx_max_channel_count);
37562306a36Sopenharmony_ci		dev_dbg(dev, "max tx/rx hw queue count = %u/%u\n",
37662306a36Sopenharmony_ci			pdata->tx_max_q_count, pdata->rx_max_q_count);
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Set the hardware channel and queue counts */
38062306a36Sopenharmony_ci	xgbe_set_counts(pdata);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Set the maximum fifo amounts */
38362306a36Sopenharmony_ci	pdata->tx_max_fifo_size = XP_GET_BITS(pdata->pp2, XP_PROP_2,
38462306a36Sopenharmony_ci					      TX_FIFO_SIZE);
38562306a36Sopenharmony_ci	pdata->tx_max_fifo_size *= 16384;
38662306a36Sopenharmony_ci	pdata->tx_max_fifo_size = min(pdata->tx_max_fifo_size,
38762306a36Sopenharmony_ci				      pdata->vdata->tx_max_fifo_size);
38862306a36Sopenharmony_ci	pdata->rx_max_fifo_size = XP_GET_BITS(pdata->pp2, XP_PROP_2,
38962306a36Sopenharmony_ci					      RX_FIFO_SIZE);
39062306a36Sopenharmony_ci	pdata->rx_max_fifo_size *= 16384;
39162306a36Sopenharmony_ci	pdata->rx_max_fifo_size = min(pdata->rx_max_fifo_size,
39262306a36Sopenharmony_ci				      pdata->vdata->rx_max_fifo_size);
39362306a36Sopenharmony_ci	if (netif_msg_probe(pdata))
39462306a36Sopenharmony_ci		dev_dbg(dev, "max tx/rx max fifo size = %u/%u\n",
39562306a36Sopenharmony_ci			pdata->tx_max_fifo_size, pdata->rx_max_fifo_size);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* Configure interrupt support */
39862306a36Sopenharmony_ci	ret = xgbe_config_irqs(pdata);
39962306a36Sopenharmony_ci	if (ret)
40062306a36Sopenharmony_ci		goto err_pci_enable;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Configure the netdev resource */
40362306a36Sopenharmony_ci	ret = xgbe_config_netdev(pdata);
40462306a36Sopenharmony_ci	if (ret)
40562306a36Sopenharmony_ci		goto err_irq_vectors;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	netdev_notice(pdata->netdev, "net device enabled\n");
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	return 0;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cierr_irq_vectors:
41262306a36Sopenharmony_ci	pci_free_irq_vectors(pdata->pcidev);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cierr_pci_enable:
41562306a36Sopenharmony_ci	xgbe_free_pdata(pdata);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cierr_alloc:
41862306a36Sopenharmony_ci	dev_notice(dev, "net device not enabled\n");
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return ret;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void xgbe_pci_remove(struct pci_dev *pdev)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = pci_get_drvdata(pdev);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	xgbe_deconfig_netdev(pdata);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	pci_free_irq_vectors(pdata->pcidev);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* Disable all interrupts in the hardware */
43262306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_INT_EN, 0x0);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	xgbe_free_pdata(pdata);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic int __maybe_unused xgbe_pci_suspend(struct device *dev)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = dev_get_drvdata(dev);
44062306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
44162306a36Sopenharmony_ci	int ret = 0;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (netif_running(netdev))
44462306a36Sopenharmony_ci		ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1);
44762306a36Sopenharmony_ci	pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER;
44862306a36Sopenharmony_ci	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return ret;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int __maybe_unused xgbe_pci_resume(struct device *dev)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct xgbe_prv_data *pdata = dev_get_drvdata(dev);
45662306a36Sopenharmony_ci	struct net_device *netdev = pdata->netdev;
45762306a36Sopenharmony_ci	int ret = 0;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
46262306a36Sopenharmony_ci	XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (netif_running(netdev)) {
46562306a36Sopenharmony_ci		ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		/* Schedule a restart in case the link or phy state changed
46862306a36Sopenharmony_ci		 * while we were powered down.
46962306a36Sopenharmony_ci		 */
47062306a36Sopenharmony_ci		schedule_work(&pdata->restart_work);
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	return ret;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic struct xgbe_version_data xgbe_v2a = {
47762306a36Sopenharmony_ci	.init_function_ptrs_phy_impl	= xgbe_init_function_ptrs_phy_v2,
47862306a36Sopenharmony_ci	.xpcs_access			= XGBE_XPCS_ACCESS_V2,
47962306a36Sopenharmony_ci	.mmc_64bit			= 1,
48062306a36Sopenharmony_ci	.tx_max_fifo_size		= 229376,
48162306a36Sopenharmony_ci	.rx_max_fifo_size		= 229376,
48262306a36Sopenharmony_ci	.tx_tstamp_workaround		= 1,
48362306a36Sopenharmony_ci	.ecc_support			= 1,
48462306a36Sopenharmony_ci	.i2c_support			= 1,
48562306a36Sopenharmony_ci	.irq_reissue_support		= 1,
48662306a36Sopenharmony_ci	.tx_desc_prefetch		= 5,
48762306a36Sopenharmony_ci	.rx_desc_prefetch		= 5,
48862306a36Sopenharmony_ci	.an_cdr_workaround		= 1,
48962306a36Sopenharmony_ci	.enable_rrc			= 1,
49062306a36Sopenharmony_ci};
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic struct xgbe_version_data xgbe_v2b = {
49362306a36Sopenharmony_ci	.init_function_ptrs_phy_impl	= xgbe_init_function_ptrs_phy_v2,
49462306a36Sopenharmony_ci	.xpcs_access			= XGBE_XPCS_ACCESS_V2,
49562306a36Sopenharmony_ci	.mmc_64bit			= 1,
49662306a36Sopenharmony_ci	.tx_max_fifo_size		= 65536,
49762306a36Sopenharmony_ci	.rx_max_fifo_size		= 65536,
49862306a36Sopenharmony_ci	.tx_tstamp_workaround		= 1,
49962306a36Sopenharmony_ci	.ecc_support			= 1,
50062306a36Sopenharmony_ci	.i2c_support			= 1,
50162306a36Sopenharmony_ci	.irq_reissue_support		= 1,
50262306a36Sopenharmony_ci	.tx_desc_prefetch		= 5,
50362306a36Sopenharmony_ci	.rx_desc_prefetch		= 5,
50462306a36Sopenharmony_ci	.an_cdr_workaround		= 1,
50562306a36Sopenharmony_ci	.enable_rrc			= 1,
50662306a36Sopenharmony_ci};
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic const struct pci_device_id xgbe_pci_table[] = {
50962306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1458),
51062306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&xgbe_v2a },
51162306a36Sopenharmony_ci	{ PCI_VDEVICE(AMD, 0x1459),
51262306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&xgbe_v2b },
51362306a36Sopenharmony_ci	/* Last entry must be zero */
51462306a36Sopenharmony_ci	{ 0, }
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, xgbe_pci_table);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(xgbe_pci_pm_ops, xgbe_pci_suspend, xgbe_pci_resume);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic struct pci_driver xgbe_driver = {
52162306a36Sopenharmony_ci	.name = XGBE_DRV_NAME,
52262306a36Sopenharmony_ci	.id_table = xgbe_pci_table,
52362306a36Sopenharmony_ci	.probe = xgbe_pci_probe,
52462306a36Sopenharmony_ci	.remove = xgbe_pci_remove,
52562306a36Sopenharmony_ci	.driver = {
52662306a36Sopenharmony_ci		.pm = &xgbe_pci_pm_ops,
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ciint xgbe_pci_init(void)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	return pci_register_driver(&xgbe_driver);
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_civoid xgbe_pci_exit(void)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	pci_unregister_driver(&xgbe_driver);
53862306a36Sopenharmony_ci}
539