2011-03-21 09:58:24 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2010 Isilon Systems, Inc.
|
|
|
|
* Copyright (c) 2010 iX Systems, Inc.
|
|
|
|
* Copyright (c) 2010 Panasas, Inc.
|
2016-09-29 14:35:32 +00:00
|
|
|
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
|
2011-03-21 09:58:24 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice unmodified, this list of conditions, and the following
|
|
|
|
* disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2015-10-20 19:08:26 +00:00
|
|
|
*
|
|
|
|
* $FreeBSD$
|
2011-03-21 09:58:24 +00:00
|
|
|
*/
|
|
|
|
#ifndef _LINUX_PCI_H_
|
|
|
|
#define _LINUX_PCI_H_
|
|
|
|
|
|
|
|
#define CONFIG_PCI_MSI
|
|
|
|
|
|
|
|
#include <linux/types.h>
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/bus.h>
|
|
|
|
#include <sys/pciio.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
#include <dev/pci/pci_private.h>
|
|
|
|
|
|
|
|
#include <machine/resource.h>
|
|
|
|
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/dmapool.h>
|
|
|
|
#include <linux/dma-mapping.h>
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <asm/atomic.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
|
|
|
|
struct pci_device_id {
|
|
|
|
uint32_t vendor;
|
|
|
|
uint32_t device;
|
2017-07-04 01:05:20 +00:00
|
|
|
uint32_t subvendor;
|
2011-03-21 09:58:24 +00:00
|
|
|
uint32_t subdevice;
|
2017-07-04 01:05:20 +00:00
|
|
|
uint32_t class;
|
2011-03-21 09:58:24 +00:00
|
|
|
uint32_t class_mask;
|
|
|
|
uintptr_t driver_data;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define MODULE_DEVICE_TABLE(bus, table)
|
2017-07-04 00:48:50 +00:00
|
|
|
|
|
|
|
#define PCI_BASE_CLASS_DISPLAY 0x03
|
|
|
|
#define PCI_CLASS_DISPLAY_VGA 0x0300
|
|
|
|
#define PCI_CLASS_DISPLAY_OTHER 0x0380
|
|
|
|
#define PCI_BASE_CLASS_BRIDGE 0x06
|
|
|
|
#define PCI_CLASS_BRIDGE_ISA 0x0601
|
|
|
|
|
2019-01-25 20:13:28 +00:00
|
|
|
#define PCI_ANY_ID -1U
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_VENDOR_ID_APPLE 0x106b
|
|
|
|
#define PCI_VENDOR_ID_ASUSTEK 0x1043
|
|
|
|
#define PCI_VENDOR_ID_ATI 0x1002
|
|
|
|
#define PCI_VENDOR_ID_DELL 0x1028
|
|
|
|
#define PCI_VENDOR_ID_HP 0x103c
|
|
|
|
#define PCI_VENDOR_ID_IBM 0x1014
|
|
|
|
#define PCI_VENDOR_ID_INTEL 0x8086
|
2011-03-21 09:58:24 +00:00
|
|
|
#define PCI_VENDOR_ID_MELLANOX 0x15b3
|
2017-05-30 17:16:08 +00:00
|
|
|
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_VENDOR_ID_SERVERWORKS 0x1166
|
|
|
|
#define PCI_VENDOR_ID_SONY 0x104d
|
2011-03-21 09:58:24 +00:00
|
|
|
#define PCI_VENDOR_ID_TOPSPIN 0x1867
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_VENDOR_ID_VIA 0x1106
|
2017-05-30 17:16:08 +00:00
|
|
|
#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
|
|
|
|
#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
|
2011-03-21 09:58:24 +00:00
|
|
|
#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
|
|
|
|
#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
|
|
|
|
#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
|
|
|
|
#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
|
|
|
|
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
|
|
|
|
#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
|
2017-05-30 17:16:08 +00:00
|
|
|
#define PCI_SUBDEVICE_ID_QEMU 0x1100
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2013-09-29 00:35:03 +00:00
|
|
|
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
|
2018-03-23 15:50:01 +00:00
|
|
|
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
|
|
|
|
#define PCI_FUNC(devfn) ((devfn) & 0x07)
|
2018-05-31 13:17:34 +00:00
|
|
|
#define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff)
|
2011-03-21 09:58:24 +00:00
|
|
|
|
Redo r242842, now actually fixing the warnings, as follows:
- In sys/ofed/drivers/infiniband/core/cma.c, an enum struct member is
interpreted as an int, so cast it to an int.
- In sys/ofed/drivers/infiniband/core/ud_header.c, initialize the
packet_length variable in ib_ud_header_init(), to prevent undefined
behaviour.
- In sys/ofed/drivers/infiniband/ulp/sdp/sdp_rx.c, call rdma_notify()
with the correct enum type and value.
- In sys/ofed/include/linux/pci.h, change the PCI_DEVICE and PCI_VDEVICE
macros to use C99 struct initializers, so additional members can be
overridden.
Reviewed by: delphij, Garrett Cooper <yanegomi@gmail.com>
MFC after: 1 week
2012-11-12 22:01:29 +00:00
|
|
|
#define PCI_VDEVICE(_vendor, _device) \
|
|
|
|
.vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \
|
|
|
|
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
|
|
|
|
#define PCI_DEVICE(_vendor, _device) \
|
|
|
|
.vendor = (_vendor), .device = (_device), \
|
|
|
|
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
|
|
|
|
2014-08-27 13:21:53 +00:00
|
|
|
#define PCI_VENDOR_ID PCIR_DEVVENDOR
|
|
|
|
#define PCI_COMMAND PCIR_COMMAND
|
|
|
|
#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL /* Device Control */
|
|
|
|
#define PCI_EXP_LNKCTL PCIER_LINK_CTL /* Link Control */
|
|
|
|
#define PCI_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE /* Device/Port type */
|
|
|
|
#define PCI_EXP_DEVCAP PCIER_DEVICE_CAP /* Device capabilities */
|
|
|
|
#define PCI_EXP_DEVSTA PCIER_DEVICE_STA /* Device Status */
|
|
|
|
#define PCI_EXP_LNKCAP PCIER_LINK_CAP /* Link Capabilities */
|
|
|
|
#define PCI_EXP_LNKSTA PCIER_LINK_STA /* Link Status */
|
|
|
|
#define PCI_EXP_SLTCAP PCIER_SLOT_CAP /* Slot Capabilities */
|
|
|
|
#define PCI_EXP_SLTCTL PCIER_SLOT_CTL /* Slot Control */
|
|
|
|
#define PCI_EXP_SLTSTA PCIER_SLOT_STA /* Slot Status */
|
|
|
|
#define PCI_EXP_RTCTL PCIER_ROOT_CTL /* Root Control */
|
|
|
|
#define PCI_EXP_RTCAP PCIER_ROOT_CAP /* Root Capabilities */
|
|
|
|
#define PCI_EXP_RTSTA PCIER_ROOT_STA /* Root Status */
|
|
|
|
#define PCI_EXP_DEVCAP2 PCIER_DEVICE_CAP2 /* Device Capabilities 2 */
|
|
|
|
#define PCI_EXP_DEVCTL2 PCIER_DEVICE_CTL2 /* Device Control 2 */
|
|
|
|
#define PCI_EXP_LNKCAP2 PCIER_LINK_CAP2 /* Link Capabilities 2 */
|
|
|
|
#define PCI_EXP_LNKCTL2 PCIER_LINK_CTL2 /* Link Control 2 */
|
|
|
|
#define PCI_EXP_LNKSTA2 PCIER_LINK_STA2 /* Link Status 2 */
|
|
|
|
#define PCI_EXP_FLAGS PCIER_FLAGS /* Capabilities register */
|
|
|
|
#define PCI_EXP_FLAGS_VERS PCIEM_FLAGS_VERSION /* Capability version */
|
|
|
|
#define PCI_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT /* Root Port */
|
|
|
|
#define PCI_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT /* Express Endpoint */
|
|
|
|
#define PCI_EXP_TYPE_LEG_END PCIEM_TYPE_LEGACY_ENDPOINT /* Legacy Endpoint */
|
|
|
|
#define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */
|
|
|
|
#define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */
|
|
|
|
#define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */
|
2016-01-26 14:20:25 +00:00
|
|
|
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */
|
|
|
|
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */
|
2019-03-13 19:15:36 +00:00
|
|
|
#define PCI_EXP_LNKCAP_SLS_8_0GB 0x04 /* Supported Link Speed 8.0GT/s */
|
|
|
|
#define PCI_EXP_LNKCAP_SLS_16_0GB 0x08 /* Supported Link Speed 16.0GT/s */
|
2016-01-26 14:20:25 +00:00
|
|
|
#define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */
|
|
|
|
#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */
|
|
|
|
#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */
|
|
|
|
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */
|
2019-03-13 19:15:36 +00:00
|
|
|
#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_EXP_LNKCTL_HAWD PCIEM_LINK_CTL_HAWD
|
|
|
|
#define PCI_EXP_LNKCAP_CLKPM 0x00040000
|
|
|
|
#define PCI_EXP_DEVSTA_TRPND 0x0020
|
|
|
|
|
2016-09-29 14:35:32 +00:00
|
|
|
#define IORESOURCE_MEM (1 << SYS_RES_MEMORY)
|
|
|
|
#define IORESOURCE_IO (1 << SYS_RES_IOPORT)
|
|
|
|
#define IORESOURCE_IRQ (1 << SYS_RES_IRQ)
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-01-26 14:20:25 +00:00
|
|
|
enum pci_bus_speed {
|
|
|
|
PCI_SPEED_UNKNOWN = -1,
|
|
|
|
PCIE_SPEED_2_5GT,
|
|
|
|
PCIE_SPEED_5_0GT,
|
|
|
|
PCIE_SPEED_8_0GT,
|
2019-03-13 19:15:36 +00:00
|
|
|
PCIE_SPEED_16_0GT,
|
2016-01-26 14:20:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum pcie_link_width {
|
2019-03-13 19:15:36 +00:00
|
|
|
PCIE_LNK_WIDTH_RESRV = 0x00,
|
|
|
|
PCIE_LNK_X1 = 0x01,
|
|
|
|
PCIE_LNK_X2 = 0x02,
|
|
|
|
PCIE_LNK_X4 = 0x04,
|
|
|
|
PCIE_LNK_X8 = 0x08,
|
|
|
|
PCIE_LNK_X12 = 0x0c,
|
|
|
|
PCIE_LNK_X16 = 0x10,
|
|
|
|
PCIE_LNK_X32 = 0x20,
|
|
|
|
PCIE_LNK_WIDTH_UNKNOWN = 0xff,
|
2016-01-26 14:20:25 +00:00
|
|
|
};
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
typedef int pci_power_t;
|
|
|
|
|
|
|
|
#define PCI_D0 PCI_POWERSTATE_D0
|
|
|
|
#define PCI_D1 PCI_POWERSTATE_D1
|
|
|
|
#define PCI_D2 PCI_POWERSTATE_D2
|
|
|
|
#define PCI_D3hot PCI_POWERSTATE_D3
|
|
|
|
#define PCI_D3cold 4
|
|
|
|
|
|
|
|
#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
|
|
|
|
|
2016-01-26 14:20:25 +00:00
|
|
|
struct pci_dev;
|
2013-09-29 00:35:03 +00:00
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
struct pci_driver {
|
|
|
|
struct list_head links;
|
|
|
|
char *name;
|
2014-08-27 13:21:53 +00:00
|
|
|
const struct pci_device_id *id_table;
|
2011-03-21 09:58:24 +00:00
|
|
|
int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
|
|
|
|
void (*remove)(struct pci_dev *dev);
|
2016-01-15 11:18:58 +00:00
|
|
|
int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
|
|
|
|
int (*resume) (struct pci_dev *dev); /* Device woken up */
|
|
|
|
void (*shutdown) (struct pci_dev *dev); /* Device shutdown */
|
2017-07-04 00:30:48 +00:00
|
|
|
driver_t bsddriver;
|
2011-03-21 09:58:24 +00:00
|
|
|
devclass_t bsdclass;
|
2017-07-04 01:23:36 +00:00
|
|
|
struct device_driver driver;
|
|
|
|
const struct pci_error_handlers *err_handler;
|
2017-08-11 03:59:48 +00:00
|
|
|
bool isdrm;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pci_bus {
|
|
|
|
struct pci_dev *self;
|
Add necessary bits for Linux KPI to work correctly on powerpc
PowerPC, and possibly other architectures, use different address ranges for
PCI space vs physical address space, which is only mapped at resource
activation time, when the BAR gets written. The DRM kernel modules do not
activate the rman resources, soas not to waste KVA, instead only mapping
parts of the PCI memory at a time. This introduces a
BUS_TRANSLATE_RESOURCE() method, implemented in the Open Firmware/FDT PCI
driver, to perform this necessary translation without activating the
resource.
In addition to system KPI changes, LinuxKPI is updated to handle a
big-endian host, by adding proper endian swaps to the I/O functions.
Submitted by: mmacy
Reported by: hselasky
Differential Revision: https://reviews.freebsd.org/D21096
2019-08-04 19:28:10 +00:00
|
|
|
int domain;
|
2017-08-11 03:59:48 +00:00
|
|
|
int number;
|
2011-03-21 09:58:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
extern struct list_head pci_drivers;
|
|
|
|
extern struct list_head pci_devices;
|
|
|
|
extern spinlock_t pci_lock;
|
|
|
|
|
|
|
|
#define __devexit_p(x) x
|
|
|
|
|
|
|
|
struct pci_dev {
|
|
|
|
struct device dev;
|
|
|
|
struct list_head links;
|
|
|
|
struct pci_driver *pdrv;
|
2017-08-11 03:59:48 +00:00
|
|
|
struct pci_bus *bus;
|
2011-03-21 09:58:24 +00:00
|
|
|
uint16_t device;
|
|
|
|
uint16_t vendor;
|
2017-08-03 21:14:46 +00:00
|
|
|
uint16_t subsystem_vendor;
|
|
|
|
uint16_t subsystem_device;
|
2011-03-21 09:58:24 +00:00
|
|
|
unsigned int irq;
|
2015-01-06 10:02:14 +00:00
|
|
|
unsigned int devfn;
|
2017-07-04 01:05:20 +00:00
|
|
|
uint32_t class;
|
|
|
|
uint8_t revision;
|
2019-08-14 09:36:25 +00:00
|
|
|
bool msi_enabled;
|
2011-03-21 09:58:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct resource_list_entry *
|
2016-12-09 13:47:50 +00:00
|
|
|
linux_pci_get_rle(struct pci_dev *pdev, int type, int rid)
|
2011-03-21 09:58:24 +00:00
|
|
|
{
|
|
|
|
struct pci_devinfo *dinfo;
|
|
|
|
struct resource_list *rl;
|
|
|
|
|
|
|
|
dinfo = device_get_ivars(pdev->dev.bsddev);
|
|
|
|
rl = &dinfo->resources;
|
|
|
|
return resource_list_find(rl, type, rid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct resource_list_entry *
|
2016-12-09 13:47:50 +00:00
|
|
|
linux_pci_get_bar(struct pci_dev *pdev, int bar)
|
2011-03-21 09:58:24 +00:00
|
|
|
{
|
|
|
|
struct resource_list_entry *rle;
|
|
|
|
|
|
|
|
bar = PCIR_BAR(bar);
|
2016-12-09 13:47:50 +00:00
|
|
|
if ((rle = linux_pci_get_rle(pdev, SYS_RES_MEMORY, bar)) == NULL)
|
|
|
|
rle = linux_pci_get_rle(pdev, SYS_RES_IOPORT, bar);
|
2011-03-21 09:58:24 +00:00
|
|
|
return (rle);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct device *
|
2016-12-09 13:47:50 +00:00
|
|
|
linux_pci_find_irq_dev(unsigned int irq)
|
2011-03-21 09:58:24 +00:00
|
|
|
{
|
|
|
|
struct pci_dev *pdev;
|
2016-12-13 19:58:21 +00:00
|
|
|
struct device *found;
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-12-13 19:58:21 +00:00
|
|
|
found = NULL;
|
2011-03-21 09:58:24 +00:00
|
|
|
spin_lock(&pci_lock);
|
|
|
|
list_for_each_entry(pdev, &pci_devices, links) {
|
2016-12-13 19:58:21 +00:00
|
|
|
if (irq == pdev->dev.irq ||
|
2019-08-14 09:36:25 +00:00
|
|
|
(irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) {
|
2016-12-13 19:58:21 +00:00
|
|
|
found = &pdev->dev;
|
2011-03-21 09:58:24 +00:00
|
|
|
break;
|
2016-12-13 19:58:21 +00:00
|
|
|
}
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
spin_unlock(&pci_lock);
|
2016-12-13 19:58:21 +00:00
|
|
|
return (found);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
2016-09-29 14:35:32 +00:00
|
|
|
static inline int
|
|
|
|
pci_resource_type(struct pci_dev *pdev, int bar)
|
|
|
|
{
|
2016-09-30 05:51:11 +00:00
|
|
|
struct pci_map *pm;
|
2016-09-29 14:35:32 +00:00
|
|
|
|
2016-09-30 05:51:11 +00:00
|
|
|
pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar));
|
|
|
|
if (!pm)
|
2016-09-29 14:35:32 +00:00
|
|
|
return (-1);
|
2016-09-30 05:51:11 +00:00
|
|
|
|
|
|
|
if (PCI_BAR_IO(pm->pm_value))
|
|
|
|
return (SYS_RES_IOPORT);
|
|
|
|
else
|
|
|
|
return (SYS_RES_MEMORY);
|
2016-09-29 14:35:32 +00:00
|
|
|
}
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
/*
|
|
|
|
* All drivers just seem to want to inspect the type not flags.
|
|
|
|
*/
|
|
|
|
static inline int
|
|
|
|
pci_resource_flags(struct pci_dev *pdev, int bar)
|
|
|
|
{
|
2016-09-29 14:35:32 +00:00
|
|
|
int type;
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-09-29 14:35:32 +00:00
|
|
|
type = pci_resource_type(pdev, bar);
|
|
|
|
if (type < 0)
|
2011-03-21 09:58:24 +00:00
|
|
|
return (0);
|
2016-09-29 14:35:32 +00:00
|
|
|
return (1 << type);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline const char *
|
|
|
|
pci_name(struct pci_dev *d)
|
|
|
|
{
|
|
|
|
|
|
|
|
return device_get_desc(d->dev.bsddev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void *
|
|
|
|
pci_get_drvdata(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
return dev_get_drvdata(&pdev->dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
pci_set_drvdata(struct pci_dev *pdev, void *data)
|
|
|
|
{
|
|
|
|
|
|
|
|
dev_set_drvdata(&pdev->dev, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_enable_device(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
|
|
|
|
pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
pci_disable_device(struct pci_dev *pdev)
|
|
|
|
{
|
2017-06-09 19:57:27 +00:00
|
|
|
|
2018-03-22 13:30:35 +00:00
|
|
|
pci_disable_busmaster(pdev->dev.bsddev);
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_set_master(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_enable_busmaster(pdev->dev.bsddev);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
static inline int
|
|
|
|
pci_set_power_state(struct pci_dev *pdev, int state)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_set_powerstate(pdev->dev.bsddev, state);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2015-02-13 16:35:12 +00:00
|
|
|
static inline int
|
|
|
|
pci_clear_master(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_disable_busmaster(pdev->dev.bsddev);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline int
|
|
|
|
pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
|
|
|
|
{
|
|
|
|
int rid;
|
|
|
|
int type;
|
|
|
|
|
2016-09-29 14:35:32 +00:00
|
|
|
type = pci_resource_type(pdev, bar);
|
|
|
|
if (type < 0)
|
2011-03-21 09:58:24 +00:00
|
|
|
return (-ENODEV);
|
|
|
|
rid = PCIR_BAR(bar);
|
|
|
|
if (bus_alloc_resource_any(pdev->dev.bsddev, type, &rid,
|
|
|
|
RF_ACTIVE) == NULL)
|
|
|
|
return (-EINVAL);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
pci_release_region(struct pci_dev *pdev, int bar)
|
|
|
|
{
|
|
|
|
struct resource_list_entry *rle;
|
|
|
|
|
2016-12-09 13:47:50 +00:00
|
|
|
if ((rle = linux_pci_get_bar(pdev, bar)) == NULL)
|
2011-03-21 09:58:24 +00:00
|
|
|
return;
|
|
|
|
bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
pci_release_regions(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i <= PCIR_MAX_BAR_0; i++)
|
|
|
|
pci_release_region(pdev, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_request_regions(struct pci_dev *pdev, const char *res_name)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
|
|
|
|
error = pci_request_region(pdev, i, res_name);
|
|
|
|
if (error && error != -ENODEV) {
|
|
|
|
pci_release_regions(pdev);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
pci_disable_msix(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_release_msi(pdev->dev.bsddev);
|
2018-03-22 12:26:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The MSIX IRQ numbers associated with this PCI device are no
|
|
|
|
* longer valid and might be re-assigned. Make sure
|
|
|
|
* linux_pci_find_irq_dev() does no longer see them by
|
|
|
|
* resetting their references to zero:
|
|
|
|
*/
|
2019-08-14 09:36:25 +00:00
|
|
|
pdev->dev.irq_start = 0;
|
|
|
|
pdev->dev.irq_end = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define pci_disable_msi(pdev) \
|
|
|
|
linux_pci_disable_msi(pdev)
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
linux_pci_disable_msi(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_release_msi(pdev->dev.bsddev);
|
|
|
|
|
|
|
|
pdev->dev.irq_start = 0;
|
|
|
|
pdev->dev.irq_end = 0;
|
|
|
|
pdev->irq = pdev->dev.irq;
|
|
|
|
pdev->msi_enabled = false;
|
2011-03-21 09:58:24 +00:00
|
|
|
}
|
|
|
|
|
Add necessary bits for Linux KPI to work correctly on powerpc
PowerPC, and possibly other architectures, use different address ranges for
PCI space vs physical address space, which is only mapped at resource
activation time, when the BAR gets written. The DRM kernel modules do not
activate the rman resources, soas not to waste KVA, instead only mapping
parts of the PCI memory at a time. This introduces a
BUS_TRANSLATE_RESOURCE() method, implemented in the Open Firmware/FDT PCI
driver, to perform this necessary translation without activating the
resource.
In addition to system KPI changes, LinuxKPI is updated to handle a
big-endian host, by adding proper endian swaps to the I/O functions.
Submitted by: mmacy
Reported by: hselasky
Differential Revision: https://reviews.freebsd.org/D21096
2019-08-04 19:28:10 +00:00
|
|
|
unsigned long pci_resource_start(struct pci_dev *pdev, int bar);
|
|
|
|
unsigned long pci_resource_len(struct pci_dev *pdev, int bar);
|
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
static inline bus_addr_t
|
|
|
|
pci_bus_address(struct pci_dev *pdev, int bar)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (pci_resource_start(pdev, bar));
|
|
|
|
}
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
#define PCI_CAP_ID_EXP PCIY_EXPRESS
|
|
|
|
#define PCI_CAP_ID_PCIX PCIY_PCIX
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_CAP_ID_AGP PCIY_AGP
|
|
|
|
#define PCI_CAP_ID_PM PCIY_PMG
|
2011-03-21 09:58:24 +00:00
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL
|
|
|
|
#define PCI_EXP_DEVCTL_PAYLOAD PCIEM_CTL_MAX_PAYLOAD
|
|
|
|
#define PCI_EXP_DEVCTL_READRQ PCIEM_CTL_MAX_READ_REQUEST
|
|
|
|
#define PCI_EXP_LNKCTL PCIER_LINK_CTL
|
|
|
|
#define PCI_EXP_LNKSTA PCIER_LINK_STA
|
2013-09-29 00:35:03 +00:00
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline int
|
|
|
|
pci_find_capability(struct pci_dev *pdev, int capid)
|
|
|
|
{
|
|
|
|
int reg;
|
|
|
|
|
2011-03-23 13:10:15 +00:00
|
|
|
if (pci_find_cap(pdev->dev.bsddev, capid, ®))
|
2011-03-21 09:58:24 +00:00
|
|
|
return (0);
|
|
|
|
return (reg);
|
|
|
|
}
|
|
|
|
|
2013-09-29 00:35:03 +00:00
|
|
|
static inline int pci_pcie_cap(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return pci_find_capability(dev, PCI_CAP_ID_EXP);
|
2013-09-29 00:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline int
|
|
|
|
pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
|
|
|
|
{
|
|
|
|
|
|
|
|
*val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_read_config_word(struct pci_dev *pdev, int where, u16 *val)
|
|
|
|
{
|
|
|
|
|
|
|
|
*val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_read_config_dword(struct pci_dev *pdev, int where, u32 *val)
|
|
|
|
{
|
|
|
|
|
|
|
|
*val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
|
|
|
|
return (0);
|
2016-12-09 15:05:09 +00:00
|
|
|
}
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_write_config_byte(struct pci_dev *pdev, int where, u8 val)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_write_config(pdev->dev.bsddev, where, val, 1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_write_config_word(struct pci_dev *pdev, int where, u16 val)
|
|
|
|
{
|
|
|
|
|
|
|
|
pci_write_config(pdev->dev.bsddev, where, val, 2);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_write_config_dword(struct pci_dev *pdev, int where, u32 val)
|
2016-12-09 15:05:09 +00:00
|
|
|
{
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
pci_write_config(pdev->dev.bsddev, where, val, 4);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:59:48 +00:00
|
|
|
int linux_pci_register_driver(struct pci_driver *pdrv);
|
|
|
|
int linux_pci_register_drm_driver(struct pci_driver *pdrv);
|
|
|
|
void linux_pci_unregister_driver(struct pci_driver *pdrv);
|
2019-05-10 23:10:22 +00:00
|
|
|
void linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
|
2017-08-11 03:59:48 +00:00
|
|
|
|
|
|
|
#define pci_register_driver(pdrv) linux_pci_register_driver(pdrv)
|
|
|
|
#define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv)
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
struct msix_entry {
|
|
|
|
int entry;
|
|
|
|
int vector;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Enable msix, positive errors indicate actual number of available
|
|
|
|
* vectors. Negative errors are failures.
|
2014-08-20 14:57:20 +00:00
|
|
|
*
|
|
|
|
* NB: define added to prevent this definition of pci_enable_msix from
|
|
|
|
* clashing with the native FreeBSD version.
|
2011-03-21 09:58:24 +00:00
|
|
|
*/
|
2018-03-28 17:54:34 +00:00
|
|
|
#define pci_enable_msix(...) \
|
|
|
|
linux_pci_enable_msix(__VA_ARGS__)
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
static inline int
|
|
|
|
pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
|
|
|
|
{
|
|
|
|
struct resource_list_entry *rle;
|
|
|
|
int error;
|
|
|
|
int avail;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
avail = pci_msix_count(pdev->dev.bsddev);
|
|
|
|
if (avail < nreq) {
|
|
|
|
if (avail == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
return avail;
|
|
|
|
}
|
|
|
|
avail = nreq;
|
|
|
|
if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
|
|
|
|
return error;
|
2015-01-06 10:02:14 +00:00
|
|
|
/*
|
|
|
|
* Handle case where "pci_alloc_msix()" may allocate less
|
|
|
|
* interrupts than available and return with no error:
|
|
|
|
*/
|
|
|
|
if (avail < nreq) {
|
|
|
|
pci_release_msi(pdev->dev.bsddev);
|
|
|
|
return avail;
|
|
|
|
}
|
2016-12-09 13:47:50 +00:00
|
|
|
rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
|
2019-08-14 09:36:25 +00:00
|
|
|
pdev->dev.irq_start = rle->start;
|
|
|
|
pdev->dev.irq_end = rle->start + avail;
|
2011-03-21 09:58:24 +00:00
|
|
|
for (i = 0; i < nreq; i++)
|
2019-08-14 09:36:25 +00:00
|
|
|
entries[i].vector = pdev->dev.irq_start + i;
|
2011-03-21 09:58:24 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2018-03-28 17:54:34 +00:00
|
|
|
#define pci_enable_msix_range(...) \
|
|
|
|
linux_pci_enable_msix_range(__VA_ARGS__)
|
|
|
|
|
2015-02-13 16:35:12 +00:00
|
|
|
static inline int
|
|
|
|
pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
|
|
|
|
int minvec, int maxvec)
|
|
|
|
{
|
|
|
|
int nvec = maxvec;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (maxvec < minvec)
|
|
|
|
return (-ERANGE);
|
|
|
|
|
|
|
|
do {
|
|
|
|
rc = pci_enable_msix(dev, entries, nvec);
|
|
|
|
if (rc < 0) {
|
|
|
|
return (rc);
|
|
|
|
} else if (rc > 0) {
|
|
|
|
if (rc < minvec)
|
|
|
|
return (-ENOSPC);
|
|
|
|
nvec = rc;
|
|
|
|
}
|
|
|
|
} while (rc);
|
|
|
|
return (nvec);
|
|
|
|
}
|
|
|
|
|
2019-08-14 09:36:25 +00:00
|
|
|
#define pci_enable_msi(pdev) \
|
|
|
|
linux_pci_enable_msi(pdev)
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_enable_msi(struct pci_dev *pdev)
|
|
|
|
{
|
|
|
|
struct resource_list_entry *rle;
|
|
|
|
int error;
|
|
|
|
int avail;
|
|
|
|
|
|
|
|
avail = pci_msi_count(pdev->dev.bsddev);
|
|
|
|
if (avail < 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
avail = 1; /* this function only enable one MSI IRQ */
|
|
|
|
if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0)
|
|
|
|
return error;
|
|
|
|
|
|
|
|
rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1);
|
|
|
|
pdev->dev.irq_start = rle->start;
|
|
|
|
pdev->dev.irq_end = rle->start + avail;
|
|
|
|
pdev->irq = rle->start;
|
|
|
|
pdev->msi_enabled = true;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2018-12-05 13:17:45 +00:00
|
|
|
static inline int
|
|
|
|
pci_channel_offline(struct pci_dev *pdev)
|
2013-09-29 00:35:03 +00:00
|
|
|
{
|
2018-12-05 13:17:45 +00:00
|
|
|
|
2019-05-06 16:22:45 +00:00
|
|
|
return (pci_get_vendor(pdev->dev.bsddev) == PCIV_INVALID);
|
2013-09-29 00:35:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return -ENODEV;
|
2013-09-29 00:35:03 +00:00
|
|
|
}
|
|
|
|
static inline void pci_disable_sriov(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DEFINE_PCI_DEVICE_TABLE(_table) \
|
|
|
|
const struct pci_device_id _table[] __devinitdata
|
|
|
|
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
/* XXX This should not be necessary. */
|
|
|
|
#define pcix_set_mmrbc(d, v) 0
|
|
|
|
#define pcix_get_max_mmrbc(d) 0
|
Add necessary bits for Linux KPI to work correctly on powerpc
PowerPC, and possibly other architectures, use different address ranges for
PCI space vs physical address space, which is only mapped at resource
activation time, when the BAR gets written. The DRM kernel modules do not
activate the rman resources, soas not to waste KVA, instead only mapping
parts of the PCI memory at a time. This introduces a
BUS_TRANSLATE_RESOURCE() method, implemented in the Open Firmware/FDT PCI
driver, to perform this necessary translation without activating the
resource.
In addition to system KPI changes, LinuxKPI is updated to handle a
big-endian host, by adding proper endian swaps to the I/O functions.
Submitted by: mmacy
Reported by: hselasky
Differential Revision: https://reviews.freebsd.org/D21096
2019-08-04 19:28:10 +00:00
|
|
|
#define pcie_set_readrq(d, v) pci_set_max_read_req(&(d)->dev, (v))
|
2011-03-21 09:58:24 +00:00
|
|
|
|
|
|
|
#define PCI_DMA_BIDIRECTIONAL 0
|
|
|
|
#define PCI_DMA_TODEVICE 1
|
|
|
|
#define PCI_DMA_FROMDEVICE 2
|
|
|
|
#define PCI_DMA_NONE 3
|
|
|
|
|
|
|
|
#define pci_pool dma_pool
|
2016-12-09 15:01:37 +00:00
|
|
|
#define pci_pool_destroy(...) dma_pool_destroy(__VA_ARGS__)
|
|
|
|
#define pci_pool_alloc(...) dma_pool_alloc(__VA_ARGS__)
|
|
|
|
#define pci_pool_free(...) dma_pool_free(__VA_ARGS__)
|
2011-03-21 09:58:24 +00:00
|
|
|
#define pci_pool_create(_name, _pdev, _size, _align, _alloc) \
|
|
|
|
dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
|
|
|
|
#define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \
|
|
|
|
dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
|
|
|
|
_size, _vaddr, _dma_handle)
|
|
|
|
#define pci_map_sg(_hwdev, _sg, _nents, _dir) \
|
|
|
|
dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
|
|
|
|
_sg, _nents, (enum dma_data_direction)_dir)
|
|
|
|
#define pci_map_single(_hwdev, _ptr, _size, _dir) \
|
|
|
|
dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
|
|
|
|
(_ptr), (_size), (enum dma_data_direction)_dir)
|
|
|
|
#define pci_unmap_single(_hwdev, _addr, _size, _dir) \
|
|
|
|
dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
|
|
|
|
_addr, _size, (enum dma_data_direction)_dir)
|
|
|
|
#define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \
|
|
|
|
dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
|
|
|
|
_sg, _nents, (enum dma_data_direction)_dir)
|
|
|
|
#define pci_map_page(_hwdev, _page, _offset, _size, _dir) \
|
|
|
|
dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
|
|
|
|
_offset, _size, (enum dma_data_direction)_dir)
|
|
|
|
#define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \
|
|
|
|
dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
|
|
|
|
_dma_address, _size, (enum dma_data_direction)_dir)
|
|
|
|
#define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask))
|
|
|
|
#define pci_dma_mapping_error(_pdev, _dma_addr) \
|
|
|
|
dma_mapping_error(&(_pdev)->dev, _dma_addr)
|
|
|
|
#define pci_set_consistent_dma_mask(_pdev, _mask) \
|
|
|
|
dma_set_coherent_mask(&(_pdev)->dev, (_mask))
|
|
|
|
#define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x);
|
|
|
|
#define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x);
|
|
|
|
#define pci_unmap_addr dma_unmap_addr
|
|
|
|
#define pci_unmap_addr_set dma_unmap_addr_set
|
|
|
|
#define pci_unmap_len dma_unmap_len
|
|
|
|
#define pci_unmap_len_set dma_unmap_len_set
|
|
|
|
|
2013-09-29 00:35:03 +00:00
|
|
|
typedef unsigned int __bitwise pci_channel_state_t;
|
|
|
|
typedef unsigned int __bitwise pci_ers_result_t;
|
|
|
|
|
|
|
|
enum pci_channel_state {
|
2018-03-23 15:50:01 +00:00
|
|
|
pci_channel_io_normal = 1,
|
|
|
|
pci_channel_io_frozen = 2,
|
|
|
|
pci_channel_io_perm_failure = 3,
|
2013-09-29 00:35:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum pci_ers_result {
|
2018-03-23 15:50:01 +00:00
|
|
|
PCI_ERS_RESULT_NONE = 1,
|
|
|
|
PCI_ERS_RESULT_CAN_RECOVER = 2,
|
|
|
|
PCI_ERS_RESULT_NEED_RESET = 3,
|
|
|
|
PCI_ERS_RESULT_DISCONNECT = 4,
|
|
|
|
PCI_ERS_RESULT_RECOVERED = 5,
|
2013-09-29 00:35:03 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* PCI bus error event callbacks */
|
|
|
|
struct pci_error_handlers {
|
2018-03-23 15:50:01 +00:00
|
|
|
pci_ers_result_t (*error_detected)(struct pci_dev *dev,
|
|
|
|
enum pci_channel_state error);
|
|
|
|
pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
|
|
|
|
pci_ers_result_t (*link_reset)(struct pci_dev *dev);
|
|
|
|
pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
|
|
|
|
void (*resume)(struct pci_dev *dev);
|
2013-09-29 00:35:03 +00:00
|
|
|
};
|
|
|
|
|
2016-01-26 14:20:25 +00:00
|
|
|
/* FreeBSD does not support SRIOV - yet */
|
2014-08-27 13:21:53 +00:00
|
|
|
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return dev;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool pci_is_pcie(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return !!pci_pcie_cap(dev);
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16 pcie_flags_reg(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
int pos;
|
|
|
|
u16 reg16;
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
|
|
|
if (!pos)
|
|
|
|
return 0;
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16);
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return reg16;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline int pci_pcie_type(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int pcie_cap_version(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
int type = pci_pcie_type(dev);
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pcie_cap_version(dev) > 1 ||
|
|
|
|
type == PCI_EXP_TYPE_ROOT_PORT ||
|
|
|
|
type == PCI_EXP_TYPE_ENDPOINT ||
|
|
|
|
type == PCI_EXP_TYPE_LEG_END;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
return true;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
int type = pci_pcie_type(dev);
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
|
|
|
|
(type == PCI_EXP_TYPE_DOWNSTREAM &&
|
|
|
|
pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
int type = pci_pcie_type(dev);
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
|
|
|
|
type == PCI_EXP_TYPE_RC_EC;
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
if (!pci_is_pcie(dev))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (pos) {
|
|
|
|
case PCI_EXP_FLAGS_TYPE:
|
|
|
|
return true;
|
|
|
|
case PCI_EXP_DEVCAP:
|
|
|
|
case PCI_EXP_DEVCTL:
|
|
|
|
case PCI_EXP_DEVSTA:
|
|
|
|
return pcie_cap_has_devctl(dev);
|
|
|
|
case PCI_EXP_LNKCAP:
|
|
|
|
case PCI_EXP_LNKCTL:
|
|
|
|
case PCI_EXP_LNKSTA:
|
|
|
|
return pcie_cap_has_lnkctl(dev);
|
|
|
|
case PCI_EXP_SLTCAP:
|
|
|
|
case PCI_EXP_SLTCTL:
|
|
|
|
case PCI_EXP_SLTSTA:
|
|
|
|
return pcie_cap_has_sltctl(dev);
|
|
|
|
case PCI_EXP_RTCTL:
|
|
|
|
case PCI_EXP_RTCAP:
|
|
|
|
case PCI_EXP_RTSTA:
|
|
|
|
return pcie_cap_has_rtctl(dev);
|
|
|
|
case PCI_EXP_DEVCAP2:
|
|
|
|
case PCI_EXP_DEVCTL2:
|
|
|
|
case PCI_EXP_LNKCAP2:
|
|
|
|
case PCI_EXP_LNKCTL2:
|
|
|
|
case PCI_EXP_LNKSTA2:
|
|
|
|
return pcie_cap_version(dev) > 1;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
static inline int
|
|
|
|
pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
|
2016-01-26 14:20:25 +00:00
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
if (pos & 3)
|
|
|
|
return -EINVAL;
|
2016-01-26 14:20:25 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
if (!pcie_capability_reg_implemented(dev, pos))
|
|
|
|
return -EINVAL;
|
2016-01-26 14:20:25 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst);
|
2016-01-26 14:20:25 +00:00
|
|
|
}
|
|
|
|
|
2016-12-09 15:05:09 +00:00
|
|
|
static inline int
|
|
|
|
pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst)
|
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
if (pos & 3)
|
|
|
|
return -EINVAL;
|
2016-12-09 15:05:09 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
if (!pcie_capability_reg_implemented(dev, pos))
|
|
|
|
return -EINVAL;
|
2016-12-09 15:05:09 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst);
|
2016-12-09 15:05:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
|
2014-08-27 13:21:53 +00:00
|
|
|
{
|
2018-03-23 15:50:01 +00:00
|
|
|
if (pos & 1)
|
|
|
|
return -EINVAL;
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
if (!pcie_capability_reg_implemented(dev, pos))
|
|
|
|
return 0;
|
2014-08-27 13:21:53 +00:00
|
|
|
|
2018-03-23 15:50:01 +00:00
|
|
|
return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
|
2014-08-27 13:21:53 +00:00
|
|
|
}
|
2013-09-29 00:35:03 +00:00
|
|
|
|
2016-01-26 14:20:25 +00:00
|
|
|
static inline int pcie_get_minimum_link(struct pci_dev *dev,
|
|
|
|
enum pci_bus_speed *speed, enum pcie_link_width *width)
|
|
|
|
{
|
|
|
|
*speed = PCI_SPEED_UNKNOWN;
|
|
|
|
*width = PCIE_LNK_WIDTH_UNKNOWN;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
pci_num_vf(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2019-03-13 19:15:36 +00:00
|
|
|
static inline enum pci_bus_speed
|
|
|
|
pcie_get_speed_cap(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
device_t root;
|
|
|
|
uint32_t lnkcap, lnkcap2;
|
|
|
|
int error, pos;
|
|
|
|
|
|
|
|
root = device_get_parent(dev->dev.bsddev);
|
|
|
|
if (root == NULL)
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
root = device_get_parent(root);
|
|
|
|
if (root == NULL)
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
root = device_get_parent(root);
|
|
|
|
if (root == NULL)
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
|
|
|
|
if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
|
|
|
|
pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
|
|
|
|
if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0)
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
|
|
|
|
lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4);
|
|
|
|
|
|
|
|
if (lnkcap2) { /* PCIe r3.0-compliant */
|
|
|
|
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
|
|
|
|
return (PCIE_SPEED_2_5GT);
|
|
|
|
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
|
|
|
|
return (PCIE_SPEED_5_0GT);
|
|
|
|
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
|
|
|
|
return (PCIE_SPEED_8_0GT);
|
|
|
|
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
|
|
|
|
return (PCIE_SPEED_16_0GT);
|
|
|
|
} else { /* pre-r3.0 */
|
|
|
|
lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
|
|
|
|
if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
|
|
|
|
return (PCIE_SPEED_2_5GT);
|
|
|
|
if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
|
|
|
|
return (PCIE_SPEED_5_0GT);
|
|
|
|
if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
|
|
|
|
return (PCIE_SPEED_8_0GT);
|
|
|
|
if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
|
|
|
|
return (PCIE_SPEED_16_0GT);
|
|
|
|
}
|
|
|
|
return (PCI_SPEED_UNKNOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline enum pcie_link_width
|
|
|
|
pcie_get_width_cap(struct pci_dev *dev)
|
|
|
|
{
|
|
|
|
uint32_t lnkcap;
|
|
|
|
|
|
|
|
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
|
|
|
|
if (lnkcap)
|
|
|
|
return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
|
|
|
|
|
|
|
|
return (PCIE_LNK_WIDTH_UNKNOWN);
|
|
|
|
}
|
|
|
|
|
2011-03-21 09:58:24 +00:00
|
|
|
#endif /* _LINUX_PCI_H_ */
|