linux/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
<<
>>
Prefs
   1/*
   2 * aQuantia Corporation Network Driver
   3 * Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 */
   9
  10/* File aq_pci_func.c: Definition of PCI functions. */
  11
  12#include "aq_pci_func.h"
  13#include "aq_nic.h"
  14#include "aq_vec.h"
  15#include "aq_hw.h"
  16#include <linux/interrupt.h>
  17
  18struct aq_pci_func_s {
  19        struct pci_dev *pdev;
  20        struct aq_nic_s *port[AQ_CFG_PCI_FUNC_PORTS];
  21        void __iomem *mmio;
  22        void *aq_vec[AQ_CFG_PCI_FUNC_MSIX_IRQS];
  23        resource_size_t mmio_pa;
  24        unsigned int msix_entry_mask;
  25        unsigned int ports;
  26        bool is_pci_enabled;
  27        bool is_regions;
  28        bool is_pci_using_dac;
  29        struct aq_hw_caps_s aq_hw_caps;
  30};
  31
  32struct aq_pci_func_s *aq_pci_func_alloc(struct aq_hw_ops *aq_hw_ops,
  33                                        struct pci_dev *pdev,
  34                                        const struct net_device_ops *ndev_ops,
  35                                        const struct ethtool_ops *eth_ops)
  36{
  37        struct aq_pci_func_s *self = NULL;
  38        int err = 0;
  39        unsigned int port = 0U;
  40
  41        if (!aq_hw_ops) {
  42                err = -EFAULT;
  43                goto err_exit;
  44        }
  45        self = kzalloc(sizeof(*self), GFP_KERNEL);
  46        if (!self) {
  47                err = -ENOMEM;
  48                goto err_exit;
  49        }
  50
  51        pci_set_drvdata(pdev, self);
  52        self->pdev = pdev;
  53
  54        err = aq_hw_ops->get_hw_caps(NULL, &self->aq_hw_caps, pdev->device,
  55                                     pdev->subsystem_device);
  56        if (err < 0)
  57                goto err_exit;
  58
  59        self->ports = self->aq_hw_caps.ports;
  60
  61        for (port = 0; port < self->ports; ++port) {
  62                struct aq_nic_s *aq_nic = aq_nic_alloc_cold(ndev_ops, eth_ops,
  63                                                            pdev, self,
  64                                                            port, aq_hw_ops);
  65
  66                if (!aq_nic) {
  67                        err = -ENOMEM;
  68                        goto err_exit;
  69                }
  70                self->port[port] = aq_nic;
  71        }
  72
  73err_exit:
  74        if (err < 0) {
  75                if (self)
  76                        aq_pci_func_free(self);
  77                self = NULL;
  78        }
  79
  80        (void)err;
  81        return self;
  82}
  83
  84int aq_pci_func_init(struct aq_pci_func_s *self)
  85{
  86        int err = 0;
  87        unsigned int bar = 0U;
  88        unsigned int port = 0U;
  89        unsigned int numvecs = 0U;
  90
  91        err = pci_enable_device(self->pdev);
  92        if (err < 0)
  93                goto err_exit;
  94
  95        self->is_pci_enabled = true;
  96
  97        err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(64));
  98        if (!err) {
  99                err = pci_set_consistent_dma_mask(self->pdev, DMA_BIT_MASK(64));
 100                self->is_pci_using_dac = 1;
 101        }
 102        if (err) {
 103                err = pci_set_dma_mask(self->pdev, DMA_BIT_MASK(32));
 104                if (!err)
 105                        err = pci_set_consistent_dma_mask(self->pdev,
 106                                                          DMA_BIT_MASK(32));
 107                self->is_pci_using_dac = 0;
 108        }
 109        if (err != 0) {
 110                err = -ENOSR;
 111                goto err_exit;
 112        }
 113
 114        err = pci_request_regions(self->pdev, AQ_CFG_DRV_NAME "_mmio");
 115        if (err < 0)
 116                goto err_exit;
 117
 118        self->is_regions = true;
 119
 120        pci_set_master(self->pdev);
 121
 122        for (bar = 0; bar < 4; ++bar) {
 123                if (IORESOURCE_MEM & pci_resource_flags(self->pdev, bar)) {
 124                        resource_size_t reg_sz;
 125
 126                        self->mmio_pa = pci_resource_start(self->pdev, bar);
 127                        if (self->mmio_pa == 0U) {
 128                                err = -EIO;
 129                                goto err_exit;
 130                        }
 131
 132                        reg_sz = pci_resource_len(self->pdev, bar);
 133                        if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) {
 134                                err = -EIO;
 135                                goto err_exit;
 136                        }
 137
 138                        self->mmio = ioremap_nocache(self->mmio_pa, reg_sz);
 139                        if (!self->mmio) {
 140                                err = -EIO;
 141                                goto err_exit;
 142                        }
 143                        break;
 144                }
 145        }
 146
 147        numvecs = min((u8)AQ_CFG_VECS_DEF, self->aq_hw_caps.msix_irqs);
 148        numvecs = min(numvecs, num_online_cpus());
 149
 150        /* enable interrupts */
 151#if !AQ_CFG_FORCE_LEGACY_INT
 152        err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs, PCI_IRQ_MSIX);
 153
 154        if (err < 0) {
 155                err = pci_alloc_irq_vectors(self->pdev, 1, 1,
 156                                PCI_IRQ_MSI | PCI_IRQ_LEGACY);
 157                if (err < 0)
 158                        goto err_exit;
 159        }
 160#endif /* AQ_CFG_FORCE_LEGACY_INT */
 161
 162        /* net device init */
 163        for (port = 0; port < self->ports; ++port) {
 164                if (!self->port[port])
 165                        continue;
 166
 167                err = aq_nic_cfg_start(self->port[port]);
 168                if (err < 0)
 169                        goto err_exit;
 170
 171                err = aq_nic_ndev_init(self->port[port]);
 172                if (err < 0)
 173                        goto err_exit;
 174
 175                err = aq_nic_ndev_register(self->port[port]);
 176                if (err < 0)
 177                        goto err_exit;
 178        }
 179
 180err_exit:
 181        if (err < 0)
 182                aq_pci_func_deinit(self);
 183        return err;
 184}
 185
 186int aq_pci_func_alloc_irq(struct aq_pci_func_s *self, unsigned int i,
 187                          char *name, void *aq_vec, cpumask_t *affinity_mask)
 188{
 189        struct pci_dev *pdev = self->pdev;
 190        int err = 0;
 191
 192        if (pdev->msix_enabled || pdev->msi_enabled)
 193                err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr, 0,
 194                                  name, aq_vec);
 195        else
 196                err = request_irq(pci_irq_vector(pdev, i), aq_vec_isr_legacy,
 197                                  IRQF_SHARED, name, aq_vec);
 198
 199        if (err >= 0) {
 200                self->msix_entry_mask |= (1 << i);
 201                self->aq_vec[i] = aq_vec;
 202
 203                if (pdev->msix_enabled)
 204                        irq_set_affinity_hint(pci_irq_vector(pdev, i),
 205                                              affinity_mask);
 206        }
 207
 208        return err;
 209}
 210
 211void aq_pci_func_free_irqs(struct aq_pci_func_s *self)
 212{
 213        struct pci_dev *pdev = self->pdev;
 214        unsigned int i = 0U;
 215
 216        for (i = 32U; i--;) {
 217                if (!((1U << i) & self->msix_entry_mask))
 218                        continue;
 219
 220                if (pdev->msix_enabled)
 221                        irq_set_affinity_hint(pci_irq_vector(pdev, i), NULL);
 222                free_irq(pci_irq_vector(pdev, i), self->aq_vec[i]);
 223                self->msix_entry_mask &= ~(1U << i);
 224        }
 225}
 226
 227void __iomem *aq_pci_func_get_mmio(struct aq_pci_func_s *self)
 228{
 229        return self->mmio;
 230}
 231
 232unsigned int aq_pci_func_get_irq_type(struct aq_pci_func_s *self)
 233{
 234        if (self->pdev->msix_enabled)
 235                return AQ_HW_IRQ_MSIX;
 236        if (self->pdev->msi_enabled)
 237                return AQ_HW_IRQ_MSIX;
 238        return AQ_HW_IRQ_LEGACY;
 239}
 240
 241void aq_pci_func_deinit(struct aq_pci_func_s *self)
 242{
 243        if (!self)
 244                goto err_exit;
 245
 246        aq_pci_func_free_irqs(self);
 247        pci_free_irq_vectors(self->pdev);
 248
 249        if (self->is_regions)
 250                pci_release_regions(self->pdev);
 251
 252        if (self->is_pci_enabled)
 253                pci_disable_device(self->pdev);
 254
 255err_exit:;
 256}
 257
 258void aq_pci_func_free(struct aq_pci_func_s *self)
 259{
 260        unsigned int port = 0U;
 261
 262        if (!self)
 263                goto err_exit;
 264
 265        for (port = 0; port < self->ports; ++port) {
 266                if (!self->port[port])
 267                        continue;
 268
 269                aq_nic_ndev_free(self->port[port]);
 270        }
 271
 272        if (self->mmio)
 273                iounmap(self->mmio);
 274
 275        kfree(self);
 276
 277err_exit:;
 278}
 279
 280int aq_pci_func_change_pm_state(struct aq_pci_func_s *self,
 281                                pm_message_t *pm_msg)
 282{
 283        int err = 0;
 284        unsigned int port = 0U;
 285
 286        if (!self) {
 287                err = -EFAULT;
 288                goto err_exit;
 289        }
 290        for (port = 0; port < self->ports; ++port) {
 291                if (!self->port[port])
 292                        continue;
 293
 294                (void)aq_nic_change_pm_state(self->port[port], pm_msg);
 295        }
 296
 297err_exit:
 298        return err;
 299}
 300