void zpci_event_availability(void *data) { struct zpci_ccdf_avail *ccdf = data; struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct pci_dev *pdev = zdev ? zdev->pdev : NULL; int ret; pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); zpci_err("avail CCDF:\n"); zpci_err_hex(ccdf, sizeof(*ccdf)); switch (ccdf->pec) { case 0x0301: /* Standby -> Configured */ if (!zdev || zdev->state == ZPCI_FN_STATE_CONFIGURED) break; zdev->state = ZPCI_FN_STATE_CONFIGURED; ret = zpci_enable_device(zdev); if (ret) break; pci_rescan_bus(zdev->bus); break; case 0x0302: /* Reserved -> Standby */ clp_add_pci_device(ccdf->fid, ccdf->fh, 0); break; case 0x0303: /* Deconfiguration requested */ if (pdev) pci_stop_and_remove_bus_device(pdev); ret = zpci_disable_device(zdev); if (ret) break; ret = sclp_pci_deconfigure(zdev->fid); zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); if (!ret) zdev->state = ZPCI_FN_STATE_STANDBY; break; case 0x0304: /* Configured -> Standby */ if (pdev) pci_stop_and_remove_bus_device(pdev); zpci_disable_device(zdev); zdev->state = ZPCI_FN_STATE_STANDBY; break; case 0x0306: /* 0x308 or 0x302 for multiple devices */ clp_rescan_pci_devices(); break; case 0x0308: /* Standby -> Reserved */ pci_stop_root_bus(zdev->bus); pci_remove_root_bus(zdev->bus); break; default: break; } }
static ssize_t recover_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pci_dev *pdev = to_pci_dev(dev); struct zpci_dev *zdev = to_zpci(pdev); int ret; if (!device_remove_file_self(dev, attr)) return count; pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(pdev); ret = zpci_disable_device(zdev); if (ret) goto error; ret = zpci_enable_device(zdev); if (ret) goto error; pci_rescan_bus(zdev->bus); pci_unlock_rescan_remove(); return count; error: pci_unlock_rescan_remove(); return ret; }
/************************************************************************* * IXDP2x00-common PCI init * * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board * contains two NPUs (ingress and egress) connected over PCI, both running * instances of the kernel. So far so good. Peers on the PCI bus running * Linux is a common design in telecom systems. The problem is that instead * of all the devices being controlled by a single host, different * devices are controlled by different NPUs on the same bus, leading to * multiple hosts on the bus. The exact bus layout looks like: * * Bus 0 * Master NPU <-------------------+-------------------> Slave NPU * | * | * P2P * | * * Bus 1 | * <--+------+---------+---------+------+--> * | | | | | * | | | | | * ... Dev PMC Media Eth0 Eth1 ... * * The master controls all but Eth1, which is controlled by the * slave. What this means is that the both the master and the slave * have to scan the bus, but only one of them can enumerate the bus. * In addition, after the bus is scanned, each kernel must remove * the device(s) it does not control from the PCI dev list otherwise * a driver on each NPU will try to manage it and we will have horrible * conflicts. Oh..and the slave NPU needs to see the master NPU * for Intel's drivers to work properly. Closed source drivers... * * The way we deal with this is fairly simple but ugly: * * 1) Let master scan and enumerate the bus completely. * 2) Master deletes Eth1 from device list. * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) * from device list. * 4) Find HW designers and LART them. * * The boards also do not do normal PCI IRQ routing, or any sort of * sensical swizzling, so we just need to check where on the bus a * device sits and figure out to which CPLD pin the interrupt is routed. * See ixdp2[48]00.c files. * *************************************************************************/ void ixdp2x00_slave_pci_postinit(void) { struct pci_dev *dev; /* * Remove PMC device is there is one */ if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) { pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); } dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN); pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); }
int cpci_unconfigure_slot(struct slot* slot) { int i; struct pci_dev *dev; dbg("%s - enter", __func__); if (!slot->dev) { err("No device for slot %02x\n", slot->number); return -ENODEV; } for (i = 0; i < 8; i++) { dev = pci_get_slot(slot->bus, PCI_DEVFN(PCI_SLOT(slot->devfn), i)); if (dev) { pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); } } pci_dev_put(slot->dev); slot->dev = NULL; dbg("%s - exit", __func__); return 0; }
int __init ixdp2800_pci_init(void) { if (machine_is_ixdp2800()) { struct pci_dev *dev; pci_common_init(&ixdp2800_pci); if (ixdp2x00_master_npu()) { dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN); pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); ixdp2800_master_enable_slave(); ixdp2800_master_wait_for_slave_bus_scan(); } else { dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN); pci_stop_and_remove_bus_device(dev); pci_dev_put(dev); } } return 0; }
static void *eeh_rmv_device(void *data, void *userdata) { struct pci_driver *driver; struct eeh_dev *edev = (struct eeh_dev *)data; struct pci_dev *dev = eeh_dev_to_pci_dev(edev); int *removed = (int *)userdata; /* * Actually, we should remove the PCI bridges as well. * However, that's lots of complexity to do that, * particularly some of devices under the bridge might * support EEH. So we just care about PCI devices for * simplicity here. */ if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) return NULL; /* * We rely on count-based pcibios_release_device() to * detach permanently offlined PEs. Unfortunately, that's * not reliable enough. We might have the permanently * offlined PEs attached, but we needn't take care of * them and their child devices. */ if (eeh_dev_removed(edev)) return NULL; driver = eeh_pcid_get(dev); if (driver) { eeh_pcid_put(dev); if (driver->err_handler) return NULL; } /* Remove it from PCI subsystem */ pr_debug("EEH: Removing %s without EEH sensitive driver\n", pci_name(dev)); edev->bus = dev->bus; edev->mode |= EEH_DEV_DISCONNECTED; (*removed)++; pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); pci_unlock_rescan_remove(); return NULL; }
int pcie_wifi_pwrctrl_save(void) { /* the precondition of invoking pci_get_class: there is only one bridge in the system, and the bridge vendor is hisilicon. otherwise, we have to invoke other api, such as pci_get_subsys */ pcie_port_dev = pci_get_class((PCI_CLASS_BRIDGE_PCI << 8), NULL); if(!pcie_port_dev) { printk(KERN_ERR "bridge not found,please check.\n"); return -EIO; } pcie_wifi_dev = pci_get_subsys(WIFI_VENDOR_ID,WIFI_DEVICE_ID, WIFI_SS_VENDOR_ID,WIFI_SS_ID,NULL); if(!pcie_wifi_dev) { printk(KERN_ERR "wifi dev not found,please check.\n"); return -EIO; } /*save interrupt pin&line*/ pcie_port_dev_int_pin = pcie_port_dev->pin; pcie_port_dev_int_irq = pcie_port_dev->irq; pcie_wifi_dev_int_pin = pcie_wifi_dev->pin; pcie_wifi_dev_int_irq = pcie_wifi_dev->irq; pci_unregister_driver(&pcie_portdriver); pcie_port_bus_unregister(); root_bus = pcie_port_dev->bus; pci_stop_and_remove_bus_device(pcie_port_dev); pcie_port_dev = NULL; pcie_wifi_powerdown(); pcie_ltssm_enable(false); disable_irq(INT_LVL_PCIE0_LINK_DOWN); #if !defined(BSP_CONFIG_V7R2_SFT) /* the power consumption when disable clk and reset is more than only diable clk. */ /*pcie_phy_ctrl_reset();*/ pcie_clk_disable(); #endif return regulator_disable(pcie_regulator); }
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev) { pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); pci_unlock_rescan_remove(); }
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf) { struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); struct pci_dev *pdev = zdev ? zdev->pdev : NULL; int ret; pr_info("%s: Event 0x%x reconfigured PCI function 0x%x\n", pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid); zpci_err("avail CCDF:\n"); zpci_err_hex(ccdf, sizeof(*ccdf)); switch (ccdf->pec) { case 0x0301: /* Reserved|Standby -> Configured */ if (!zdev) { ret = clp_add_pci_device(ccdf->fid, ccdf->fh, 0); if (ret) break; zdev = get_zdev_by_fid(ccdf->fid); } if (!zdev || zdev->state != ZPCI_FN_STATE_STANDBY) break; zdev->state = ZPCI_FN_STATE_CONFIGURED; zdev->fh = ccdf->fh; ret = zpci_enable_device(zdev); if (ret) break; pci_rescan_bus(zdev->bus); break; case 0x0302: /* Reserved -> Standby */ if (!zdev) clp_add_pci_device(ccdf->fid, ccdf->fh, 0); break; case 0x0303: /* Deconfiguration requested */ if (pdev) pci_stop_and_remove_bus_device(pdev); ret = zpci_disable_device(zdev); if (ret) break; ret = sclp_pci_deconfigure(zdev->fid); zpci_dbg(3, "deconf fid:%x, rc:%d\n", zdev->fid, ret); if (!ret) zdev->state = ZPCI_FN_STATE_STANDBY; break; case 0x0304: /* Configured -> Standby */ if (pdev) { /* Give the driver a hint that the function is * already unusable. */ pdev->error_state = pci_channel_io_perm_failure; pci_stop_and_remove_bus_device(pdev); } zdev->fh = ccdf->fh; zpci_disable_device(zdev); zdev->state = ZPCI_FN_STATE_STANDBY; break; case 0x0306: /* 0x308 or 0x302 for multiple devices */ clp_rescan_pci_devices(); break; case 0x0308: /* Standby -> Reserved */ if (!zdev) break; pci_stop_root_bus(zdev->bus); pci_remove_root_bus(zdev->bus); break; default: break; } }