1*47f164deSLendacky, Thomas /* 2*47f164deSLendacky, Thomas * AMD 10Gb Ethernet driver 3*47f164deSLendacky, Thomas * 4*47f164deSLendacky, Thomas * This file is available to you under your choice of the following two 5*47f164deSLendacky, Thomas * licenses: 6*47f164deSLendacky, Thomas * 7*47f164deSLendacky, Thomas * License 1: GPLv2 8*47f164deSLendacky, Thomas * 9*47f164deSLendacky, Thomas * Copyright (c) 2016 Advanced Micro Devices, Inc. 10*47f164deSLendacky, Thomas * 11*47f164deSLendacky, Thomas * This file is free software; you may copy, redistribute and/or modify 12*47f164deSLendacky, Thomas * it under the terms of the GNU General Public License as published by 13*47f164deSLendacky, Thomas * the Free Software Foundation, either version 2 of the License, or (at 14*47f164deSLendacky, Thomas * your option) any later version. 15*47f164deSLendacky, Thomas * 16*47f164deSLendacky, Thomas * This file is distributed in the hope that it will be useful, but 17*47f164deSLendacky, Thomas * WITHOUT ANY WARRANTY; without even the implied warranty of 18*47f164deSLendacky, Thomas * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19*47f164deSLendacky, Thomas * General Public License for more details. 20*47f164deSLendacky, Thomas * 21*47f164deSLendacky, Thomas * You should have received a copy of the GNU General Public License 22*47f164deSLendacky, Thomas * along with this program. If not, see <http://www.gnu.org/licenses/>. 23*47f164deSLendacky, Thomas * 24*47f164deSLendacky, Thomas * This file incorporates work covered by the following copyright and 25*47f164deSLendacky, Thomas * permission notice: 26*47f164deSLendacky, Thomas * The Synopsys DWC ETHER XGMAC Software Driver and documentation 27*47f164deSLendacky, Thomas * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 28*47f164deSLendacky, Thomas * Inc. unless otherwise expressly agreed to in writing between Synopsys 29*47f164deSLendacky, Thomas * and you. 30*47f164deSLendacky, Thomas * 31*47f164deSLendacky, Thomas * The Software IS NOT an item of Licensed Software or Licensed Product 32*47f164deSLendacky, Thomas * under any End User Software License Agreement or Agreement for Licensed 33*47f164deSLendacky, Thomas * Product with Synopsys or any supplement thereto. Permission is hereby 34*47f164deSLendacky, Thomas * granted, free of charge, to any person obtaining a copy of this software 35*47f164deSLendacky, Thomas * annotated with this license and the Software, to deal in the Software 36*47f164deSLendacky, Thomas * without restriction, including without limitation the rights to use, 37*47f164deSLendacky, Thomas * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 38*47f164deSLendacky, Thomas * of the Software, and to permit persons to whom the Software is furnished 39*47f164deSLendacky, Thomas * to do so, subject to the following conditions: 40*47f164deSLendacky, Thomas * 41*47f164deSLendacky, Thomas * The above copyright notice and this permission notice shall be included 42*47f164deSLendacky, Thomas * in all copies or substantial portions of the Software. 43*47f164deSLendacky, Thomas * 44*47f164deSLendacky, Thomas * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 45*47f164deSLendacky, Thomas * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46*47f164deSLendacky, Thomas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 47*47f164deSLendacky, Thomas * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 48*47f164deSLendacky, Thomas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49*47f164deSLendacky, Thomas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50*47f164deSLendacky, Thomas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51*47f164deSLendacky, Thomas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52*47f164deSLendacky, Thomas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53*47f164deSLendacky, Thomas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 54*47f164deSLendacky, Thomas * THE POSSIBILITY OF SUCH DAMAGE. 55*47f164deSLendacky, Thomas * 56*47f164deSLendacky, Thomas * 57*47f164deSLendacky, Thomas * License 2: Modified BSD 58*47f164deSLendacky, Thomas * 59*47f164deSLendacky, Thomas * Copyright (c) 2016 Advanced Micro Devices, Inc. 60*47f164deSLendacky, Thomas * All rights reserved. 61*47f164deSLendacky, Thomas * 62*47f164deSLendacky, Thomas * Redistribution and use in source and binary forms, with or without 63*47f164deSLendacky, Thomas * modification, are permitted provided that the following conditions are met: 64*47f164deSLendacky, Thomas * * Redistributions of source code must retain the above copyright 65*47f164deSLendacky, Thomas * notice, this list of conditions and the following disclaimer. 66*47f164deSLendacky, Thomas * * Redistributions in binary form must reproduce the above copyright 67*47f164deSLendacky, Thomas * notice, this list of conditions and the following disclaimer in the 68*47f164deSLendacky, Thomas * documentation and/or other materials provided with the distribution. 69*47f164deSLendacky, Thomas * * Neither the name of Advanced Micro Devices, Inc. nor the 70*47f164deSLendacky, Thomas * names of its contributors may be used to endorse or promote products 71*47f164deSLendacky, Thomas * derived from this software without specific prior written permission. 72*47f164deSLendacky, Thomas * 73*47f164deSLendacky, Thomas * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 74*47f164deSLendacky, Thomas * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75*47f164deSLendacky, Thomas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 76*47f164deSLendacky, Thomas * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 77*47f164deSLendacky, Thomas * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 78*47f164deSLendacky, Thomas * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 79*47f164deSLendacky, Thomas * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 80*47f164deSLendacky, Thomas * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 81*47f164deSLendacky, Thomas * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 82*47f164deSLendacky, Thomas * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 83*47f164deSLendacky, Thomas * 84*47f164deSLendacky, Thomas * This file incorporates work covered by the following copyright and 85*47f164deSLendacky, Thomas * permission notice: 86*47f164deSLendacky, Thomas * The Synopsys DWC ETHER XGMAC Software Driver and documentation 87*47f164deSLendacky, Thomas * (hereinafter "Software") is an unsupported proprietary work of Synopsys, 88*47f164deSLendacky, Thomas * Inc. unless otherwise expressly agreed to in writing between Synopsys 89*47f164deSLendacky, Thomas * and you. 90*47f164deSLendacky, Thomas * 91*47f164deSLendacky, Thomas * The Software IS NOT an item of Licensed Software or Licensed Product 92*47f164deSLendacky, Thomas * under any End User Software License Agreement or Agreement for Licensed 93*47f164deSLendacky, Thomas * Product with Synopsys or any supplement thereto. Permission is hereby 94*47f164deSLendacky, Thomas * granted, free of charge, to any person obtaining a copy of this software 95*47f164deSLendacky, Thomas * annotated with this license and the Software, to deal in the Software 96*47f164deSLendacky, Thomas * without restriction, including without limitation the rights to use, 97*47f164deSLendacky, Thomas * copy, modify, merge, publish, distribute, sublicense, and/or sell copies 98*47f164deSLendacky, Thomas * of the Software, and to permit persons to whom the Software is furnished 99*47f164deSLendacky, Thomas * to do so, subject to the following conditions: 100*47f164deSLendacky, Thomas * 101*47f164deSLendacky, Thomas * The above copyright notice and this permission notice shall be included 102*47f164deSLendacky, Thomas * in all copies or substantial portions of the Software. 103*47f164deSLendacky, Thomas * 104*47f164deSLendacky, Thomas * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" 105*47f164deSLendacky, Thomas * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 106*47f164deSLendacky, Thomas * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 107*47f164deSLendacky, Thomas * PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS 108*47f164deSLendacky, Thomas * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 109*47f164deSLendacky, Thomas * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 110*47f164deSLendacky, Thomas * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 111*47f164deSLendacky, Thomas * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 112*47f164deSLendacky, Thomas * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 113*47f164deSLendacky, Thomas * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 114*47f164deSLendacky, Thomas * THE POSSIBILITY OF SUCH DAMAGE. 115*47f164deSLendacky, Thomas */ 116*47f164deSLendacky, Thomas 117*47f164deSLendacky, Thomas #include <linux/module.h> 118*47f164deSLendacky, Thomas #include <linux/device.h> 119*47f164deSLendacky, Thomas #include <linux/pci.h> 120*47f164deSLendacky, Thomas #include <linux/log2.h> 121*47f164deSLendacky, Thomas 122*47f164deSLendacky, Thomas #include "xgbe.h" 123*47f164deSLendacky, Thomas #include "xgbe-common.h" 124*47f164deSLendacky, Thomas 125*47f164deSLendacky, Thomas static int xgbe_config_msi(struct xgbe_prv_data *pdata) 126*47f164deSLendacky, Thomas { 127*47f164deSLendacky, Thomas unsigned int msi_count; 128*47f164deSLendacky, Thomas unsigned int i, j; 129*47f164deSLendacky, Thomas int ret; 130*47f164deSLendacky, Thomas 131*47f164deSLendacky, Thomas msi_count = XGBE_MSIX_BASE_COUNT; 132*47f164deSLendacky, Thomas msi_count += max(pdata->rx_ring_count, 133*47f164deSLendacky, Thomas pdata->tx_ring_count); 134*47f164deSLendacky, Thomas msi_count = roundup_pow_of_two(msi_count); 135*47f164deSLendacky, Thomas 136*47f164deSLendacky, Thomas ret = pci_enable_msi_exact(pdata->pcidev, msi_count); 137*47f164deSLendacky, Thomas if (ret < 0) { 138*47f164deSLendacky, Thomas dev_info(pdata->dev, "MSI request for %u interrupts failed\n", 139*47f164deSLendacky, Thomas msi_count); 140*47f164deSLendacky, Thomas 141*47f164deSLendacky, Thomas ret = pci_enable_msi(pdata->pcidev); 142*47f164deSLendacky, Thomas if (ret < 0) { 143*47f164deSLendacky, Thomas dev_info(pdata->dev, "MSI enablement failed\n"); 144*47f164deSLendacky, Thomas return ret; 145*47f164deSLendacky, Thomas } 146*47f164deSLendacky, Thomas 147*47f164deSLendacky, Thomas msi_count = 1; 148*47f164deSLendacky, Thomas } 149*47f164deSLendacky, Thomas 150*47f164deSLendacky, Thomas pdata->irq_count = msi_count; 151*47f164deSLendacky, Thomas 152*47f164deSLendacky, Thomas pdata->dev_irq = pdata->pcidev->irq; 153*47f164deSLendacky, Thomas 154*47f164deSLendacky, Thomas if (msi_count > 1) { 155*47f164deSLendacky, Thomas pdata->ecc_irq = pdata->pcidev->irq + 1; 156*47f164deSLendacky, Thomas pdata->i2c_irq = pdata->pcidev->irq + 2; 157*47f164deSLendacky, Thomas pdata->an_irq = pdata->pcidev->irq + 3; 158*47f164deSLendacky, Thomas 159*47f164deSLendacky, Thomas for (i = XGBE_MSIX_BASE_COUNT, j = 0; 160*47f164deSLendacky, Thomas (i < msi_count) && (j < XGBE_MAX_DMA_CHANNELS); 161*47f164deSLendacky, Thomas i++, j++) 162*47f164deSLendacky, Thomas pdata->channel_irq[j] = pdata->pcidev->irq + i; 163*47f164deSLendacky, Thomas pdata->channel_irq_count = j; 164*47f164deSLendacky, Thomas 165*47f164deSLendacky, Thomas pdata->per_channel_irq = 1; 166*47f164deSLendacky, Thomas } else { 167*47f164deSLendacky, Thomas pdata->ecc_irq = pdata->pcidev->irq; 168*47f164deSLendacky, Thomas pdata->i2c_irq = pdata->pcidev->irq; 169*47f164deSLendacky, Thomas pdata->an_irq = pdata->pcidev->irq; 170*47f164deSLendacky, Thomas } 171*47f164deSLendacky, Thomas 172*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) 173*47f164deSLendacky, Thomas dev_dbg(pdata->dev, "MSI interrupts enabled\n"); 174*47f164deSLendacky, Thomas 175*47f164deSLendacky, Thomas return 0; 176*47f164deSLendacky, Thomas } 177*47f164deSLendacky, Thomas 178*47f164deSLendacky, Thomas static int xgbe_config_msix(struct xgbe_prv_data *pdata) 179*47f164deSLendacky, Thomas { 180*47f164deSLendacky, Thomas unsigned int msix_count; 181*47f164deSLendacky, Thomas unsigned int i, j; 182*47f164deSLendacky, Thomas int ret; 183*47f164deSLendacky, Thomas 184*47f164deSLendacky, Thomas msix_count = XGBE_MSIX_BASE_COUNT; 185*47f164deSLendacky, Thomas msix_count += max(pdata->rx_ring_count, 186*47f164deSLendacky, Thomas pdata->tx_ring_count); 187*47f164deSLendacky, Thomas 188*47f164deSLendacky, Thomas pdata->msix_entries = devm_kcalloc(pdata->dev, msix_count, 189*47f164deSLendacky, Thomas sizeof(struct msix_entry), 190*47f164deSLendacky, Thomas GFP_KERNEL); 191*47f164deSLendacky, Thomas if (!pdata->msix_entries) 192*47f164deSLendacky, Thomas return -ENOMEM; 193*47f164deSLendacky, Thomas 194*47f164deSLendacky, Thomas for (i = 0; i < msix_count; i++) 195*47f164deSLendacky, Thomas pdata->msix_entries[i].entry = i; 196*47f164deSLendacky, Thomas 197*47f164deSLendacky, Thomas ret = pci_enable_msix_range(pdata->pcidev, pdata->msix_entries, 198*47f164deSLendacky, Thomas XGBE_MSIX_MIN_COUNT, msix_count); 199*47f164deSLendacky, Thomas if (ret < 0) { 200*47f164deSLendacky, Thomas dev_info(pdata->dev, "MSI-X enablement failed\n"); 201*47f164deSLendacky, Thomas devm_kfree(pdata->dev, pdata->msix_entries); 202*47f164deSLendacky, Thomas pdata->msix_entries = NULL; 203*47f164deSLendacky, Thomas return ret; 204*47f164deSLendacky, Thomas } 205*47f164deSLendacky, Thomas 206*47f164deSLendacky, Thomas pdata->irq_count = ret; 207*47f164deSLendacky, Thomas 208*47f164deSLendacky, Thomas pdata->dev_irq = pdata->msix_entries[0].vector; 209*47f164deSLendacky, Thomas pdata->ecc_irq = pdata->msix_entries[1].vector; 210*47f164deSLendacky, Thomas pdata->i2c_irq = pdata->msix_entries[2].vector; 211*47f164deSLendacky, Thomas pdata->an_irq = pdata->msix_entries[3].vector; 212*47f164deSLendacky, Thomas 213*47f164deSLendacky, Thomas for (i = XGBE_MSIX_BASE_COUNT, j = 0; i < ret; i++, j++) 214*47f164deSLendacky, Thomas pdata->channel_irq[j] = pdata->msix_entries[i].vector; 215*47f164deSLendacky, Thomas pdata->channel_irq_count = j; 216*47f164deSLendacky, Thomas 217*47f164deSLendacky, Thomas pdata->per_channel_irq = 1; 218*47f164deSLendacky, Thomas 219*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) 220*47f164deSLendacky, Thomas dev_dbg(pdata->dev, "MSI-X interrupts enabled\n"); 221*47f164deSLendacky, Thomas 222*47f164deSLendacky, Thomas return 0; 223*47f164deSLendacky, Thomas } 224*47f164deSLendacky, Thomas 225*47f164deSLendacky, Thomas static int xgbe_config_irqs(struct xgbe_prv_data *pdata) 226*47f164deSLendacky, Thomas { 227*47f164deSLendacky, Thomas int ret; 228*47f164deSLendacky, Thomas 229*47f164deSLendacky, Thomas ret = xgbe_config_msix(pdata); 230*47f164deSLendacky, Thomas if (!ret) 231*47f164deSLendacky, Thomas goto out; 232*47f164deSLendacky, Thomas 233*47f164deSLendacky, Thomas ret = xgbe_config_msi(pdata); 234*47f164deSLendacky, Thomas if (!ret) 235*47f164deSLendacky, Thomas goto out; 236*47f164deSLendacky, Thomas 237*47f164deSLendacky, Thomas pdata->irq_count = 1; 238*47f164deSLendacky, Thomas pdata->irq_shared = 1; 239*47f164deSLendacky, Thomas 240*47f164deSLendacky, Thomas pdata->dev_irq = pdata->pcidev->irq; 241*47f164deSLendacky, Thomas pdata->ecc_irq = pdata->pcidev->irq; 242*47f164deSLendacky, Thomas pdata->i2c_irq = pdata->pcidev->irq; 243*47f164deSLendacky, Thomas pdata->an_irq = pdata->pcidev->irq; 244*47f164deSLendacky, Thomas 245*47f164deSLendacky, Thomas out: 246*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) { 247*47f164deSLendacky, Thomas unsigned int i; 248*47f164deSLendacky, Thomas 249*47f164deSLendacky, Thomas dev_dbg(pdata->dev, " dev irq=%d\n", pdata->dev_irq); 250*47f164deSLendacky, Thomas dev_dbg(pdata->dev, " ecc irq=%d\n", pdata->ecc_irq); 251*47f164deSLendacky, Thomas dev_dbg(pdata->dev, " i2c irq=%d\n", pdata->i2c_irq); 252*47f164deSLendacky, Thomas dev_dbg(pdata->dev, " an irq=%d\n", pdata->an_irq); 253*47f164deSLendacky, Thomas for (i = 0; i < pdata->channel_irq_count; i++) 254*47f164deSLendacky, Thomas dev_dbg(pdata->dev, " dma%u irq=%d\n", 255*47f164deSLendacky, Thomas i, pdata->channel_irq[i]); 256*47f164deSLendacky, Thomas } 257*47f164deSLendacky, Thomas 258*47f164deSLendacky, Thomas return 0; 259*47f164deSLendacky, Thomas } 260*47f164deSLendacky, Thomas 261*47f164deSLendacky, Thomas static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 262*47f164deSLendacky, Thomas { 263*47f164deSLendacky, Thomas struct xgbe_prv_data *pdata; 264*47f164deSLendacky, Thomas struct device *dev = &pdev->dev; 265*47f164deSLendacky, Thomas void __iomem * const *iomap_table; 266*47f164deSLendacky, Thomas unsigned int ma_lo, ma_hi; 267*47f164deSLendacky, Thomas unsigned int reg; 268*47f164deSLendacky, Thomas int bar_mask; 269*47f164deSLendacky, Thomas int ret; 270*47f164deSLendacky, Thomas 271*47f164deSLendacky, Thomas pdata = xgbe_alloc_pdata(dev); 272*47f164deSLendacky, Thomas if (IS_ERR(pdata)) { 273*47f164deSLendacky, Thomas ret = PTR_ERR(pdata); 274*47f164deSLendacky, Thomas goto err_alloc; 275*47f164deSLendacky, Thomas } 276*47f164deSLendacky, Thomas 277*47f164deSLendacky, Thomas pdata->pcidev = pdev; 278*47f164deSLendacky, Thomas pci_set_drvdata(pdev, pdata); 279*47f164deSLendacky, Thomas 280*47f164deSLendacky, Thomas /* Get the version data */ 281*47f164deSLendacky, Thomas pdata->vdata = (struct xgbe_version_data *)id->driver_data; 282*47f164deSLendacky, Thomas 283*47f164deSLendacky, Thomas ret = pcim_enable_device(pdev); 284*47f164deSLendacky, Thomas if (ret) { 285*47f164deSLendacky, Thomas dev_err(dev, "pcim_enable_device failed\n"); 286*47f164deSLendacky, Thomas goto err_pci_enable; 287*47f164deSLendacky, Thomas } 288*47f164deSLendacky, Thomas 289*47f164deSLendacky, Thomas /* Obtain the mmio areas for the device */ 290*47f164deSLendacky, Thomas bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); 291*47f164deSLendacky, Thomas ret = pcim_iomap_regions(pdev, bar_mask, XGBE_DRV_NAME); 292*47f164deSLendacky, Thomas if (ret) { 293*47f164deSLendacky, Thomas dev_err(dev, "pcim_iomap_regions failed\n"); 294*47f164deSLendacky, Thomas goto err_pci_enable; 295*47f164deSLendacky, Thomas } 296*47f164deSLendacky, Thomas 297*47f164deSLendacky, Thomas iomap_table = pcim_iomap_table(pdev); 298*47f164deSLendacky, Thomas if (!iomap_table) { 299*47f164deSLendacky, Thomas dev_err(dev, "pcim_iomap_table failed\n"); 300*47f164deSLendacky, Thomas ret = -ENOMEM; 301*47f164deSLendacky, Thomas goto err_pci_enable; 302*47f164deSLendacky, Thomas } 303*47f164deSLendacky, Thomas 304*47f164deSLendacky, Thomas pdata->xgmac_regs = iomap_table[XGBE_XGMAC_BAR]; 305*47f164deSLendacky, Thomas if (!pdata->xgmac_regs) { 306*47f164deSLendacky, Thomas dev_err(dev, "xgmac ioremap failed\n"); 307*47f164deSLendacky, Thomas ret = -ENOMEM; 308*47f164deSLendacky, Thomas goto err_pci_enable; 309*47f164deSLendacky, Thomas } 310*47f164deSLendacky, Thomas pdata->xprop_regs = pdata->xgmac_regs + XGBE_MAC_PROP_OFFSET; 311*47f164deSLendacky, Thomas pdata->xi2c_regs = pdata->xgmac_regs + XGBE_I2C_CTRL_OFFSET; 312*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) { 313*47f164deSLendacky, Thomas dev_dbg(dev, "xgmac_regs = %p\n", pdata->xgmac_regs); 314*47f164deSLendacky, Thomas dev_dbg(dev, "xprop_regs = %p\n", pdata->xprop_regs); 315*47f164deSLendacky, Thomas dev_dbg(dev, "xi2c_regs = %p\n", pdata->xi2c_regs); 316*47f164deSLendacky, Thomas } 317*47f164deSLendacky, Thomas 318*47f164deSLendacky, Thomas pdata->xpcs_regs = iomap_table[XGBE_XPCS_BAR]; 319*47f164deSLendacky, Thomas if (!pdata->xpcs_regs) { 320*47f164deSLendacky, Thomas dev_err(dev, "xpcs ioremap failed\n"); 321*47f164deSLendacky, Thomas ret = -ENOMEM; 322*47f164deSLendacky, Thomas goto err_pci_enable; 323*47f164deSLendacky, Thomas } 324*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) 325*47f164deSLendacky, Thomas dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs); 326*47f164deSLendacky, Thomas 327*47f164deSLendacky, Thomas /* Configure the PCS indirect addressing support */ 328*47f164deSLendacky, Thomas reg = XPCS32_IOREAD(pdata, PCS_V2_WINDOW_DEF); 329*47f164deSLendacky, Thomas pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET); 330*47f164deSLendacky, Thomas pdata->xpcs_window <<= 6; 331*47f164deSLendacky, Thomas pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE); 332*47f164deSLendacky, Thomas pdata->xpcs_window_size = 1 << (pdata->xpcs_window_size + 7); 333*47f164deSLendacky, Thomas pdata->xpcs_window_mask = pdata->xpcs_window_size - 1; 334*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) { 335*47f164deSLendacky, Thomas dev_dbg(dev, "xpcs window = %#010x\n", 336*47f164deSLendacky, Thomas pdata->xpcs_window); 337*47f164deSLendacky, Thomas dev_dbg(dev, "xpcs window size = %#010x\n", 338*47f164deSLendacky, Thomas pdata->xpcs_window_size); 339*47f164deSLendacky, Thomas dev_dbg(dev, "xpcs window mask = %#010x\n", 340*47f164deSLendacky, Thomas pdata->xpcs_window_mask); 341*47f164deSLendacky, Thomas } 342*47f164deSLendacky, Thomas 343*47f164deSLendacky, Thomas pci_set_master(pdev); 344*47f164deSLendacky, Thomas 345*47f164deSLendacky, Thomas /* Enable all interrupts in the hardware */ 346*47f164deSLendacky, Thomas XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff); 347*47f164deSLendacky, Thomas 348*47f164deSLendacky, Thomas /* Retrieve the MAC address */ 349*47f164deSLendacky, Thomas ma_lo = XP_IOREAD(pdata, XP_MAC_ADDR_LO); 350*47f164deSLendacky, Thomas ma_hi = XP_IOREAD(pdata, XP_MAC_ADDR_HI); 351*47f164deSLendacky, Thomas pdata->mac_addr[0] = ma_lo & 0xff; 352*47f164deSLendacky, Thomas pdata->mac_addr[1] = (ma_lo >> 8) & 0xff; 353*47f164deSLendacky, Thomas pdata->mac_addr[2] = (ma_lo >> 16) & 0xff; 354*47f164deSLendacky, Thomas pdata->mac_addr[3] = (ma_lo >> 24) & 0xff; 355*47f164deSLendacky, Thomas pdata->mac_addr[4] = ma_hi & 0xff; 356*47f164deSLendacky, Thomas pdata->mac_addr[5] = (ma_hi >> 8) & 0xff; 357*47f164deSLendacky, Thomas if (!XP_GET_BITS(ma_hi, XP_MAC_ADDR_HI, VALID) || 358*47f164deSLendacky, Thomas !is_valid_ether_addr(pdata->mac_addr)) { 359*47f164deSLendacky, Thomas dev_err(dev, "invalid mac address\n"); 360*47f164deSLendacky, Thomas ret = -EINVAL; 361*47f164deSLendacky, Thomas goto err_pci_enable; 362*47f164deSLendacky, Thomas } 363*47f164deSLendacky, Thomas 364*47f164deSLendacky, Thomas /* Clock settings */ 365*47f164deSLendacky, Thomas pdata->sysclk_rate = XGBE_V2_DMA_CLOCK_FREQ; 366*47f164deSLendacky, Thomas pdata->ptpclk_rate = XGBE_V2_PTP_CLOCK_FREQ; 367*47f164deSLendacky, Thomas 368*47f164deSLendacky, Thomas /* Set the DMA coherency values */ 369*47f164deSLendacky, Thomas pdata->coherent = 1; 370*47f164deSLendacky, Thomas pdata->axdomain = XGBE_DMA_OS_AXDOMAIN; 371*47f164deSLendacky, Thomas pdata->arcache = XGBE_DMA_OS_ARCACHE; 372*47f164deSLendacky, Thomas pdata->awcache = XGBE_DMA_OS_AWCACHE; 373*47f164deSLendacky, Thomas 374*47f164deSLendacky, Thomas /* Set the maximum channels and queues */ 375*47f164deSLendacky, Thomas reg = XP_IOREAD(pdata, XP_PROP_1); 376*47f164deSLendacky, Thomas pdata->tx_max_channel_count = XP_GET_BITS(reg, XP_PROP_1, MAX_TX_DMA); 377*47f164deSLendacky, Thomas pdata->rx_max_channel_count = XP_GET_BITS(reg, XP_PROP_1, MAX_RX_DMA); 378*47f164deSLendacky, Thomas pdata->tx_max_q_count = XP_GET_BITS(reg, XP_PROP_1, MAX_TX_QUEUES); 379*47f164deSLendacky, Thomas pdata->rx_max_q_count = XP_GET_BITS(reg, XP_PROP_1, MAX_RX_QUEUES); 380*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) { 381*47f164deSLendacky, Thomas dev_dbg(dev, "max tx/rx channel count = %u/%u\n", 382*47f164deSLendacky, Thomas pdata->tx_max_channel_count, 383*47f164deSLendacky, Thomas pdata->tx_max_channel_count); 384*47f164deSLendacky, Thomas dev_dbg(dev, "max tx/rx hw queue count = %u/%u\n", 385*47f164deSLendacky, Thomas pdata->tx_max_q_count, pdata->rx_max_q_count); 386*47f164deSLendacky, Thomas } 387*47f164deSLendacky, Thomas 388*47f164deSLendacky, Thomas /* Set the hardware channel and queue counts */ 389*47f164deSLendacky, Thomas xgbe_set_counts(pdata); 390*47f164deSLendacky, Thomas 391*47f164deSLendacky, Thomas /* Set the maximum fifo amounts */ 392*47f164deSLendacky, Thomas reg = XP_IOREAD(pdata, XP_PROP_2); 393*47f164deSLendacky, Thomas pdata->tx_max_fifo_size = XP_GET_BITS(reg, XP_PROP_2, TX_FIFO_SIZE); 394*47f164deSLendacky, Thomas pdata->tx_max_fifo_size *= 16384; 395*47f164deSLendacky, Thomas pdata->tx_max_fifo_size = min(pdata->tx_max_fifo_size, 396*47f164deSLendacky, Thomas pdata->vdata->tx_max_fifo_size); 397*47f164deSLendacky, Thomas pdata->rx_max_fifo_size = XP_GET_BITS(reg, XP_PROP_2, RX_FIFO_SIZE); 398*47f164deSLendacky, Thomas pdata->rx_max_fifo_size *= 16384; 399*47f164deSLendacky, Thomas pdata->rx_max_fifo_size = min(pdata->rx_max_fifo_size, 400*47f164deSLendacky, Thomas pdata->vdata->rx_max_fifo_size); 401*47f164deSLendacky, Thomas if (netif_msg_probe(pdata)) 402*47f164deSLendacky, Thomas dev_dbg(dev, "max tx/rx max fifo size = %u/%u\n", 403*47f164deSLendacky, Thomas pdata->tx_max_fifo_size, pdata->rx_max_fifo_size); 404*47f164deSLendacky, Thomas 405*47f164deSLendacky, Thomas /* Configure interrupt support */ 406*47f164deSLendacky, Thomas ret = xgbe_config_irqs(pdata); 407*47f164deSLendacky, Thomas if (ret) 408*47f164deSLendacky, Thomas goto err_pci_enable; 409*47f164deSLendacky, Thomas 410*47f164deSLendacky, Thomas /* Configure the netdev resource */ 411*47f164deSLendacky, Thomas ret = xgbe_config_netdev(pdata); 412*47f164deSLendacky, Thomas if (ret) 413*47f164deSLendacky, Thomas goto err_pci_enable; 414*47f164deSLendacky, Thomas 415*47f164deSLendacky, Thomas netdev_notice(pdata->netdev, "net device enabled\n"); 416*47f164deSLendacky, Thomas 417*47f164deSLendacky, Thomas return 0; 418*47f164deSLendacky, Thomas 419*47f164deSLendacky, Thomas err_pci_enable: 420*47f164deSLendacky, Thomas xgbe_free_pdata(pdata); 421*47f164deSLendacky, Thomas 422*47f164deSLendacky, Thomas err_alloc: 423*47f164deSLendacky, Thomas dev_notice(dev, "net device not enabled\n"); 424*47f164deSLendacky, Thomas 425*47f164deSLendacky, Thomas return ret; 426*47f164deSLendacky, Thomas } 427*47f164deSLendacky, Thomas 428*47f164deSLendacky, Thomas static void xgbe_pci_remove(struct pci_dev *pdev) 429*47f164deSLendacky, Thomas { 430*47f164deSLendacky, Thomas struct xgbe_prv_data *pdata = pci_get_drvdata(pdev); 431*47f164deSLendacky, Thomas 432*47f164deSLendacky, Thomas xgbe_deconfig_netdev(pdata); 433*47f164deSLendacky, Thomas 434*47f164deSLendacky, Thomas xgbe_free_pdata(pdata); 435*47f164deSLendacky, Thomas } 436*47f164deSLendacky, Thomas 437*47f164deSLendacky, Thomas #ifdef CONFIG_PM 438*47f164deSLendacky, Thomas static int xgbe_pci_suspend(struct pci_dev *pdev, pm_message_t state) 439*47f164deSLendacky, Thomas { 440*47f164deSLendacky, Thomas struct xgbe_prv_data *pdata = pci_get_drvdata(pdev); 441*47f164deSLendacky, Thomas struct net_device *netdev = pdata->netdev; 442*47f164deSLendacky, Thomas int ret = 0; 443*47f164deSLendacky, Thomas 444*47f164deSLendacky, Thomas if (netif_running(netdev)) 445*47f164deSLendacky, Thomas ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT); 446*47f164deSLendacky, Thomas 447*47f164deSLendacky, Thomas pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); 448*47f164deSLendacky, Thomas pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER; 449*47f164deSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); 450*47f164deSLendacky, Thomas 451*47f164deSLendacky, Thomas return ret; 452*47f164deSLendacky, Thomas } 453*47f164deSLendacky, Thomas 454*47f164deSLendacky, Thomas static int xgbe_pci_resume(struct pci_dev *pdev) 455*47f164deSLendacky, Thomas { 456*47f164deSLendacky, Thomas struct xgbe_prv_data *pdata = pci_get_drvdata(pdev); 457*47f164deSLendacky, Thomas struct net_device *netdev = pdata->netdev; 458*47f164deSLendacky, Thomas int ret = 0; 459*47f164deSLendacky, Thomas 460*47f164deSLendacky, Thomas pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER; 461*47f164deSLendacky, Thomas XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); 462*47f164deSLendacky, Thomas 463*47f164deSLendacky, Thomas if (netif_running(netdev)) { 464*47f164deSLendacky, Thomas ret = xgbe_powerup(netdev, XGMAC_DRIVER_CONTEXT); 465*47f164deSLendacky, Thomas 466*47f164deSLendacky, Thomas /* Schedule a restart in case the link or phy state changed 467*47f164deSLendacky, Thomas * while we were powered down. 468*47f164deSLendacky, Thomas */ 469*47f164deSLendacky, Thomas schedule_work(&pdata->restart_work); 470*47f164deSLendacky, Thomas } 471*47f164deSLendacky, Thomas 472*47f164deSLendacky, Thomas return ret; 473*47f164deSLendacky, Thomas } 474*47f164deSLendacky, Thomas #endif /* CONFIG_PM */ 475*47f164deSLendacky, Thomas 476*47f164deSLendacky, Thomas static const struct xgbe_version_data xgbe_v2a = { 477*47f164deSLendacky, Thomas .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, 478*47f164deSLendacky, Thomas .xpcs_access = XGBE_XPCS_ACCESS_V2, 479*47f164deSLendacky, Thomas .mmc_64bit = 1, 480*47f164deSLendacky, Thomas .tx_max_fifo_size = 229376, 481*47f164deSLendacky, Thomas .rx_max_fifo_size = 229376, 482*47f164deSLendacky, Thomas .tx_tstamp_workaround = 1, 483*47f164deSLendacky, Thomas }; 484*47f164deSLendacky, Thomas 485*47f164deSLendacky, Thomas static const struct xgbe_version_data xgbe_v2b = { 486*47f164deSLendacky, Thomas .init_function_ptrs_phy_impl = xgbe_init_function_ptrs_phy_v2, 487*47f164deSLendacky, Thomas .xpcs_access = XGBE_XPCS_ACCESS_V2, 488*47f164deSLendacky, Thomas .mmc_64bit = 1, 489*47f164deSLendacky, Thomas .tx_max_fifo_size = 65536, 490*47f164deSLendacky, Thomas .rx_max_fifo_size = 65536, 491*47f164deSLendacky, Thomas .tx_tstamp_workaround = 1, 492*47f164deSLendacky, Thomas }; 493*47f164deSLendacky, Thomas 494*47f164deSLendacky, Thomas static const struct pci_device_id xgbe_pci_table[] = { 495*47f164deSLendacky, Thomas { PCI_VDEVICE(AMD, 0x1458), 496*47f164deSLendacky, Thomas .driver_data = (kernel_ulong_t)&xgbe_v2a }, 497*47f164deSLendacky, Thomas { PCI_VDEVICE(AMD, 0x1459), 498*47f164deSLendacky, Thomas .driver_data = (kernel_ulong_t)&xgbe_v2b }, 499*47f164deSLendacky, Thomas /* Last entry must be zero */ 500*47f164deSLendacky, Thomas { 0, } 501*47f164deSLendacky, Thomas }; 502*47f164deSLendacky, Thomas MODULE_DEVICE_TABLE(pci, xgbe_pci_table); 503*47f164deSLendacky, Thomas 504*47f164deSLendacky, Thomas static struct pci_driver xgbe_driver = { 505*47f164deSLendacky, Thomas .name = XGBE_DRV_NAME, 506*47f164deSLendacky, Thomas .id_table = xgbe_pci_table, 507*47f164deSLendacky, Thomas .probe = xgbe_pci_probe, 508*47f164deSLendacky, Thomas .remove = xgbe_pci_remove, 509*47f164deSLendacky, Thomas #ifdef CONFIG_PM 510*47f164deSLendacky, Thomas .suspend = xgbe_pci_suspend, 511*47f164deSLendacky, Thomas .resume = xgbe_pci_resume, 512*47f164deSLendacky, Thomas #endif 513*47f164deSLendacky, Thomas }; 514*47f164deSLendacky, Thomas 515*47f164deSLendacky, Thomas int xgbe_pci_init(void) 516*47f164deSLendacky, Thomas { 517*47f164deSLendacky, Thomas return pci_register_driver(&xgbe_driver); 518*47f164deSLendacky, Thomas } 519*47f164deSLendacky, Thomas 520*47f164deSLendacky, Thomas void xgbe_pci_exit(void) 521*47f164deSLendacky, Thomas { 522*47f164deSLendacky, Thomas pci_unregister_driver(&xgbe_driver); 523*47f164deSLendacky, Thomas } 524