diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -221,6 +221,7 @@ 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 @@ 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 @@ 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 @@ 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, ®)) + 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 @@ 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 diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -243,11 +243,13 @@ 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 @@ 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);