linux/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*******************************************************************************
   3  This contains the functions to handle the pci driver.
   4
   5  Copyright (C) 2011-2012  Vayavya Labs Pvt Ltd
   6
   7
   8  Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
   9  Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
  10*******************************************************************************/
  11
  12#include <linux/clk-provider.h>
  13#include <linux/pci.h>
  14#include <linux/dmi.h>
  15
  16#include "stmmac.h"
  17
  18struct stmmac_pci_info {
  19        int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat);
  20};
  21
  22static void common_default_data(struct plat_stmmacenet_data *plat)
  23{
  24        plat->clk_csr = 2;      /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
  25        plat->has_gmac = 1;
  26        plat->force_sf_dma_mode = 1;
  27
  28        plat->mdio_bus_data->needs_reset = true;
  29
  30        /* Set default value for multicast hash bins */
  31        plat->multicast_filter_bins = HASH_TABLE_SIZE;
  32
  33        /* Set default value for unicast filter entries */
  34        plat->unicast_filter_entries = 1;
  35
  36        /* Set the maxmtu to a default of JUMBO_LEN */
  37        plat->maxmtu = JUMBO_LEN;
  38
  39        /* Set default number of RX and TX queues to use */
  40        plat->tx_queues_to_use = 1;
  41        plat->rx_queues_to_use = 1;
  42
  43        /* Disable Priority config by default */
  44        plat->tx_queues_cfg[0].use_prio = false;
  45        plat->rx_queues_cfg[0].use_prio = false;
  46
  47        /* Disable RX queues routing by default */
  48        plat->rx_queues_cfg[0].pkt_route = 0x0;
  49}
  50
  51static int stmmac_default_data(struct pci_dev *pdev,
  52                               struct plat_stmmacenet_data *plat)
  53{
  54        /* Set common default data first */
  55        common_default_data(plat);
  56
  57        plat->bus_id = 1;
  58        plat->phy_addr = 0;
  59        plat->phy_interface = PHY_INTERFACE_MODE_GMII;
  60
  61        plat->dma_cfg->pbl = 32;
  62        plat->dma_cfg->pblx8 = true;
  63        /* TODO: AXI */
  64
  65        return 0;
  66}
  67
  68static const struct stmmac_pci_info stmmac_pci_info = {
  69        .setup = stmmac_default_data,
  70};
  71
  72static int snps_gmac5_default_data(struct pci_dev *pdev,
  73                                   struct plat_stmmacenet_data *plat)
  74{
  75        int i;
  76
  77        plat->clk_csr = 5;
  78        plat->has_gmac4 = 1;
  79        plat->force_sf_dma_mode = 1;
  80        plat->tso_en = 1;
  81        plat->pmt = 1;
  82
  83        /* Set default value for multicast hash bins */
  84        plat->multicast_filter_bins = HASH_TABLE_SIZE;
  85
  86        /* Set default value for unicast filter entries */
  87        plat->unicast_filter_entries = 1;
  88
  89        /* Set the maxmtu to a default of JUMBO_LEN */
  90        plat->maxmtu = JUMBO_LEN;
  91
  92        /* Set default number of RX and TX queues to use */
  93        plat->tx_queues_to_use = 4;
  94        plat->rx_queues_to_use = 4;
  95
  96        plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR;
  97        for (i = 0; i < plat->tx_queues_to_use; i++) {
  98                plat->tx_queues_cfg[i].use_prio = false;
  99                plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
 100                plat->tx_queues_cfg[i].weight = 25;
 101                if (i > 0)
 102                        plat->tx_queues_cfg[i].tbs_en = 1;
 103        }
 104
 105        plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP;
 106        for (i = 0; i < plat->rx_queues_to_use; i++) {
 107                plat->rx_queues_cfg[i].use_prio = false;
 108                plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB;
 109                plat->rx_queues_cfg[i].pkt_route = 0x0;
 110                plat->rx_queues_cfg[i].chan = i;
 111        }
 112
 113        plat->bus_id = 1;
 114        plat->phy_addr = -1;
 115        plat->phy_interface = PHY_INTERFACE_MODE_GMII;
 116
 117        plat->dma_cfg->pbl = 32;
 118        plat->dma_cfg->pblx8 = true;
 119
 120        /* Axi Configuration */
 121        plat->axi = devm_kzalloc(&pdev->dev, sizeof(*plat->axi), GFP_KERNEL);
 122        if (!plat->axi)
 123                return -ENOMEM;
 124
 125        plat->axi->axi_wr_osr_lmt = 31;
 126        plat->axi->axi_rd_osr_lmt = 31;
 127
 128        plat->axi->axi_fb = false;
 129        plat->axi->axi_blen[0] = 4;
 130        plat->axi->axi_blen[1] = 8;
 131        plat->axi->axi_blen[2] = 16;
 132        plat->axi->axi_blen[3] = 32;
 133
 134        return 0;
 135}
 136
 137static const struct stmmac_pci_info snps_gmac5_pci_info = {
 138        .setup = snps_gmac5_default_data,
 139};
 140
 141/**
 142 * stmmac_pci_probe
 143 *
 144 * @pdev: pci device pointer
 145 * @id: pointer to table of device id/id's.
 146 *
 147 * Description: This probing function gets called for all PCI devices which
 148 * match the ID table and are not "owned" by other driver yet. This function
 149 * gets passed a "struct pci_dev *" for each device whose entry in the ID table
 150 * matches the device. The probe functions returns zero when the driver choose
 151 * to take "ownership" of the device or an error code(-ve no) otherwise.
 152 */
 153static int stmmac_pci_probe(struct pci_dev *pdev,
 154                            const struct pci_device_id *id)
 155{
 156        struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
 157        struct plat_stmmacenet_data *plat;
 158        struct stmmac_resources res;
 159        int i;
 160        int ret;
 161
 162        plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
 163        if (!plat)
 164                return -ENOMEM;
 165
 166        plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
 167                                           sizeof(*plat->mdio_bus_data),
 168                                           GFP_KERNEL);
 169        if (!plat->mdio_bus_data)
 170                return -ENOMEM;
 171
 172        plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
 173                                     GFP_KERNEL);
 174        if (!plat->dma_cfg)
 175                return -ENOMEM;
 176
 177        /* Enable pci device */
 178        ret = pci_enable_device(pdev);
 179        if (ret) {
 180                dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n",
 181                        __func__);
 182                return ret;
 183        }
 184
 185        /* Get the base address of device */
 186        for (i = 0; i < PCI_STD_NUM_BARS; i++) {
 187                if (pci_resource_len(pdev, i) == 0)
 188                        continue;
 189                ret = pcim_iomap_regions(pdev, BIT(i), pci_name(pdev));
 190                if (ret)
 191                        return ret;
 192                break;
 193        }
 194
 195        pci_set_master(pdev);
 196
 197        ret = info->setup(pdev, plat);
 198        if (ret)
 199                return ret;
 200
 201        pci_enable_msi(pdev);
 202
 203        memset(&res, 0, sizeof(res));
 204        res.addr = pcim_iomap_table(pdev)[i];
 205        res.wol_irq = pdev->irq;
 206        res.irq = pdev->irq;
 207
 208        return stmmac_dvr_probe(&pdev->dev, plat, &res);
 209}
 210
 211/**
 212 * stmmac_pci_remove
 213 *
 214 * @pdev: platform device pointer
 215 * Description: this function calls the main to free the net resources
 216 * and releases the PCI resources.
 217 */
 218static void stmmac_pci_remove(struct pci_dev *pdev)
 219{
 220        int i;
 221
 222        stmmac_dvr_remove(&pdev->dev);
 223
 224        for (i = 0; i < PCI_STD_NUM_BARS; i++) {
 225                if (pci_resource_len(pdev, i) == 0)
 226                        continue;
 227                pcim_iounmap_regions(pdev, BIT(i));
 228                break;
 229        }
 230
 231        pci_disable_device(pdev);
 232}
 233
 234static int __maybe_unused stmmac_pci_suspend(struct device *dev)
 235{
 236        struct pci_dev *pdev = to_pci_dev(dev);
 237        int ret;
 238
 239        ret = stmmac_suspend(dev);
 240        if (ret)
 241                return ret;
 242
 243        ret = pci_save_state(pdev);
 244        if (ret)
 245                return ret;
 246
 247        pci_disable_device(pdev);
 248        pci_wake_from_d3(pdev, true);
 249        return 0;
 250}
 251
 252static int __maybe_unused stmmac_pci_resume(struct device *dev)
 253{
 254        struct pci_dev *pdev = to_pci_dev(dev);
 255        int ret;
 256
 257        pci_restore_state(pdev);
 258        pci_set_power_state(pdev, PCI_D0);
 259
 260        ret = pci_enable_device(pdev);
 261        if (ret)
 262                return ret;
 263
 264        pci_set_master(pdev);
 265
 266        return stmmac_resume(dev);
 267}
 268
 269static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
 270
 271/* synthetic ID, no official vendor */
 272#define PCI_VENDOR_ID_STMMAC            0x0700
 273
 274#define PCI_DEVICE_ID_STMMAC_STMMAC             0x1108
 275#define PCI_DEVICE_ID_SYNOPSYS_GMAC5_ID         0x7102
 276
 277static const struct pci_device_id stmmac_id_table[] = {
 278        { PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info) },
 279        { PCI_DEVICE_DATA(STMICRO, MAC, &stmmac_pci_info) },
 280        { PCI_DEVICE_DATA(SYNOPSYS, GMAC5_ID, &snps_gmac5_pci_info) },
 281        {}
 282};
 283
 284MODULE_DEVICE_TABLE(pci, stmmac_id_table);
 285
 286static struct pci_driver stmmac_pci_driver = {
 287        .name = STMMAC_RESOURCE_NAME,
 288        .id_table = stmmac_id_table,
 289        .probe = stmmac_pci_probe,
 290        .remove = stmmac_pci_remove,
 291        .driver         = {
 292                .pm     = &stmmac_pm_ops,
 293        },
 294};
 295
 296module_pci_driver(stmmac_pci_driver);
 297
 298MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
 299MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
 300MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
 301MODULE_LICENSE("GPL");
 302