示例#1
0
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;
    }
}
示例#2
0
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;
}
示例#6
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;
}
示例#7
0
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);

}
示例#8
0
文件: remove.c 项目: 383530895/linux
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();
}
示例#9
0
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;
	}
}