LinuxKPI: extend pci.h by various functions for wireless driver

Add dummy functions for dealing with "HotPlug" events which we currently
do not support.

Add pci_dev_get(), pci_find_ext_capability() and pci_pme_capable().

The added pcie_find_root_port() is a bit special as we need to create
another linux pci device;  for that make lkpinew_pci_dev() public
which is also helpful for other cases when we want to use the Linux
routines to check for device identifiers only and need a container
for the "bsddev" to use natively.  This has proven to avoid basic
checking code for the sake of rewriting it to native field names
elsewhere.  Given we cache the newly created "root" we also need to
make sure we clean it up.

Sponsored by:	The FreeBSD Foundation
Reviewed by:	hselasky
Differential Revision: https://reviews.freebsd.org/D30521

(cherry picked from commit 8e106c5230)
This commit is contained in:
Bjoern A. Zeeb 2021-05-28 11:16:12 +00:00
parent af13c69522
commit 40a215e38a
2 changed files with 93 additions and 1 deletions

View file

@ -221,6 +221,7 @@ struct pci_dev {
struct list_head links;
struct pci_driver *pdrv;
struct pci_bus *bus;
struct pci_dev *root;
uint16_t device;
uint16_t vendor;
uint16_t subsystem_vendor;
@ -236,6 +237,10 @@ struct pci_dev {
TAILQ_HEAD(, pci_mmio_region) mmio;
};
/* Internal helper function(s). */
struct pci_dev *lkpinew_pci_dev(device_t);
static inline struct resource_list_entry *
linux_pci_get_rle(struct pci_dev *pdev, int type, int rid)
{
@ -327,6 +332,15 @@ pci_set_drvdata(struct pci_dev *pdev, void *data)
dev_set_drvdata(&pdev->dev, data);
}
static inline struct pci_dev *
pci_dev_get(struct pci_dev *pdev)
{
if (pdev != NULL)
get_device(&pdev->dev);
return (pdev);
}
static __inline void
pci_dev_put(struct pci_dev *pdev)
{
@ -496,6 +510,48 @@ static inline int pci_pcie_cap(struct pci_dev *dev)
return pci_find_capability(dev, PCI_CAP_ID_EXP);
}
static inline int
pci_find_ext_capability(struct pci_dev *pdev, int capid)
{
int reg;
if (pci_find_extcap(pdev->dev.bsddev, capid, &reg))
return (0);
return (reg);
}
#define PCIM_PCAP_PME_SHIFT 11
static __inline bool
pci_pme_capable(struct pci_dev *pdev, uint32_t flag)
{
struct pci_devinfo *dinfo;
pcicfgregs *cfg;
if (flag > (PCIM_PCAP_D3PME_COLD >> PCIM_PCAP_PME_SHIFT))
return (false);
dinfo = device_get_ivars(pdev->dev.bsddev);
cfg = &dinfo->cfg;
if (cfg->pp.pp_cap == 0)
return (false);
if ((cfg->pp.pp_cap & (1 << (PCIM_PCAP_PME_SHIFT + flag))) != 0)
return (true);
return (false);
}
static inline int
pci_disable_link_state(struct pci_dev *pdev, uint32_t flags)
{
if (!pci_enable_aspm)
return (-EPERM);
return (-ENXIO);
}
static inline int
pci_read_config_byte(struct pci_dev *pdev, int where, u8 *val)
{
@ -1052,6 +1108,38 @@ pcie_bandwidth_available(struct pci_dev *pdev,
return (nwidth * PCIE_SPEED2MBS_ENC(nspeed));
}
static inline struct pci_dev *
pcie_find_root_port(struct pci_dev *pdev)
{
device_t root;
if (pdev->root != NULL)
return (pdev->root);
root = pci_find_pcie_root_port(pdev->dev.bsddev);
if (root == NULL)
return (NULL);
pdev->root = lkpinew_pci_dev(root);
return (pdev->root);
}
/* This is needed when people rip out the device "HotPlug". */
static inline void
pci_lock_rescan_remove(void)
{
}
static inline void
pci_unlock_rescan_remove(void)
{
}
static __inline void
pci_stop_and_remove_bus_device(struct pci_dev *pdev)
{
}
/*
* The following functions can be used to attach/detach the LinuxKPI's
* PCI device runtime. The pci_driver and pci_device_id pointer is

View file

@ -243,11 +243,13 @@ lkpinew_pci_dev_release(struct device *dev)
struct pci_dev *pdev;
pdev = to_pci_dev(dev);
if (pdev->root != NULL)
pci_dev_put(pdev->root);
free(pdev->bus, M_DEVBUF);
free(pdev, M_DEVBUF);
}
static struct pci_dev *
struct pci_dev *
lkpinew_pci_dev(device_t dev)
{
struct pci_dev *pdev;
@ -408,6 +410,8 @@ linux_pci_detach_device(struct pci_dev *pdev)
if (pdev->pdrv != NULL)
pdev->pdrv->remove(pdev);
if (pdev->root != NULL)
pci_dev_put(pdev->root);
free(pdev->bus, M_DEVBUF);
linux_pdev_dma_uninit(pdev);