diff options
Diffstat (limited to 'arch/s390/pci')
| -rw-r--r-- | arch/s390/pci/pci.c | 377 | ||||
| -rw-r--r-- | arch/s390/pci/pci_clp.c | 51 | ||||
| -rw-r--r-- | arch/s390/pci/pci_debug.c | 2 | ||||
| -rw-r--r-- | arch/s390/pci/pci_dma.c | 39 | ||||
| -rw-r--r-- | arch/s390/pci/pci_event.c | 99 | ||||
| -rw-r--r-- | arch/s390/pci/pci_sysfs.c | 147 | 
6 files changed, 381 insertions, 334 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index f17a8343e36..30de42730b2 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -48,13 +48,10 @@  static LIST_HEAD(zpci_list);  static DEFINE_SPINLOCK(zpci_list_lock); -static void zpci_enable_irq(struct irq_data *data); -static void zpci_disable_irq(struct irq_data *data); -  static struct irq_chip zpci_irq_chip = {  	.name = "zPCI", -	.irq_unmask = zpci_enable_irq, -	.irq_mask = zpci_disable_irq, +	.irq_unmask = unmask_msi_irq, +	.irq_mask = mask_msi_irq,  };  static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES); @@ -120,26 +117,17 @@ EXPORT_SYMBOL_GPL(pci_proc_domain);  static int zpci_set_airq(struct zpci_dev *zdev)  {  	u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT); -	struct zpci_fib *fib; -	int rc; - -	fib = (void *) get_zeroed_page(GFP_KERNEL); -	if (!fib) -		return -ENOMEM; - -	fib->isc = PCI_ISC; -	fib->sum = 1;		/* enable summary notifications */ -	fib->noi = airq_iv_end(zdev->aibv); -	fib->aibv = (unsigned long) zdev->aibv->vector; -	fib->aibvo = 0;		/* each zdev has its own interrupt vector */ -	fib->aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8; -	fib->aisbo = zdev->aisb & 63; +	struct zpci_fib fib = {0}; -	rc = zpci_mod_fc(req, fib); -	pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi); +	fib.isc = PCI_ISC; +	fib.sum = 1;		/* enable summary notifications */ +	fib.noi = airq_iv_end(zdev->aibv); +	fib.aibv = (unsigned long) zdev->aibv->vector; +	fib.aibvo = 0;		/* each zdev has its own interrupt vector */ +	fib.aisb = (unsigned long) zpci_aisb_iv->vector + (zdev->aisb/64)*8; +	fib.aisbo = zdev->aisb & 63; -	free_page((unsigned long) fib); -	return rc; +	return zpci_mod_fc(req, &fib);  }  struct mod_pci_args { @@ -152,22 +140,14 @@ struct mod_pci_args {  static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args)  {  	u64 req = ZPCI_CREATE_REQ(zdev->fh, dmaas, fn); -	struct zpci_fib *fib; -	int rc; - -	/* The FIB must be available even if it's not used */ -	fib = (void *) get_zeroed_page(GFP_KERNEL); -	if (!fib) -		return -ENOMEM; +	struct zpci_fib fib = {0}; -	fib->pba = args->base; -	fib->pal = args->limit; -	fib->iota = args->iota; -	fib->fmb_addr = args->fmb_addr; +	fib.pba = args->base; +	fib.pal = args->limit; +	fib.iota = args->iota; +	fib.fmb_addr = args->fmb_addr; -	rc = zpci_mod_fc(req, fib); -	free_page((unsigned long) fib); -	return rc; +	return zpci_mod_fc(req, &fib);  }  /* Modify PCI: Register I/O address translation parameters */ @@ -261,43 +241,6 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len)  	return rc;  } -static int zpci_msi_set_mask_bits(struct msi_desc *msi, u32 mask, u32 flag) -{ -	int offset, pos; -	u32 mask_bits; - -	if (msi->msi_attrib.is_msix) { -		offset = msi->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + -			PCI_MSIX_ENTRY_VECTOR_CTRL; -		msi->masked = readl(msi->mask_base + offset); -		writel(flag, msi->mask_base + offset); -	} else if (msi->msi_attrib.maskbit) { -		pos = (long) msi->mask_base; -		pci_read_config_dword(msi->dev, pos, &mask_bits); -		mask_bits &= ~(mask); -		mask_bits |= flag & mask; -		pci_write_config_dword(msi->dev, pos, mask_bits); -	} else -		return 0; - -	msi->msi_attrib.maskbit = !!flag; -	return 1; -} - -static void zpci_enable_irq(struct irq_data *data) -{ -	struct msi_desc *msi = irq_get_msi_desc(data->irq); - -	zpci_msi_set_mask_bits(msi, 1, 0); -} - -static void zpci_disable_irq(struct irq_data *data) -{ -	struct msi_desc *msi = irq_get_msi_desc(data->irq); - -	zpci_msi_set_mask_bits(msi, 1, 1); -} -  void pcibios_fixup_bus(struct pci_bus *bus)  {  } @@ -418,15 +361,14 @@ static void zpci_irq_handler(struct airq_struct *airq)  int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)  {  	struct zpci_dev *zdev = get_zdev(pdev); -	unsigned int hwirq, irq, msi_vecs; +	unsigned int hwirq, msi_vecs;  	unsigned long aisb;  	struct msi_desc *msi;  	struct msi_msg msg; -	int rc; +	int rc, irq; -	pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec); -	if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI) -		return -EINVAL; +	if (type == PCI_CAP_ID_MSI && nvec > 1) +		return 1;  	msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX);  	msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI); @@ -451,7 +393,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)  	list_for_each_entry(msi, &pdev->msi_list, list) {  		rc = -EIO;  		irq = irq_alloc_desc(0);	/* Alloc irq on node 0 */ -		if (irq == NO_IRQ) +		if (irq < 0)  			goto out_msi;  		rc = irq_set_msi_desc(irq, msi);  		if (rc) @@ -489,7 +431,6 @@ out_msi:  out_si:  	airq_iv_free_bit(zpci_aisb_iv, aisb);  out: -	dev_err(&pdev->dev, "register MSI failed with: %d\n", rc);  	return rc;  } @@ -499,18 +440,17 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)  	struct msi_desc *msi;  	int rc; -	pr_info("%s: on pdev: %p\n", __func__, pdev); -  	/* Disable adapter interrupts */  	rc = zpci_clear_airq(zdev); -	if (rc) { -		dev_err(&pdev->dev, "deregister MSI failed with: %d\n", rc); +	if (rc)  		return; -	}  	/* Release MSI interrupts */  	list_for_each_entry(msi, &pdev->msi_list, list) { -		zpci_msi_set_mask_bits(msi, 1, 1); +		if (msi->msi_attrib.is_msix) +			default_msix_mask_irq(msi, 1); +		else +			default_msi_mask_irq(msi, 1, 1);  		irq_set_msi_desc(msi->irq, NULL);  		irq_free_desc(msi->irq);  		msi->msg.address_lo = 0; @@ -553,25 +493,6 @@ static void zpci_unmap_resources(struct zpci_dev *zdev)  	}  } -struct zpci_dev *zpci_alloc_device(void) -{ -	struct zpci_dev *zdev; - -	/* Alloc memory for our private pci device data */ -	zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); -	return zdev ? : ERR_PTR(-ENOMEM); -} - -void zpci_free_device(struct zpci_dev *zdev) -{ -	kfree(zdev); -} - -int pcibios_add_platform_entries(struct pci_dev *pdev) -{ -	return zpci_sysfs_add_device(&pdev->dev); -} -  static int __init zpci_irq_init(void)  {  	int rc; @@ -602,34 +523,6 @@ static void zpci_irq_exit(void)  	unregister_adapter_interrupt(&zpci_airq);  } -static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size, -						unsigned long flags, int domain) -{ -	struct resource *r; -	char *name; -	int rc; - -	r = kzalloc(sizeof(*r), GFP_KERNEL); -	if (!r) -		return ERR_PTR(-ENOMEM); -	r->start = start; -	r->end = r->start + size - 1; -	r->flags = flags; -	r->parent = &iomem_resource; -	name = kmalloc(18, GFP_KERNEL); -	if (!name) { -		kfree(r); -		return ERR_PTR(-ENOMEM); -	} -	sprintf(name, "PCI Bus: %04x:%02x", domain, ZPCI_BUS_NR); -	r->name = name; - -	rc = request_resource(&iomem_resource, r); -	if (rc) -		pr_debug("request resource %pR failed\n", r); -	return r; -} -  static int zpci_alloc_iomap(struct zpci_dev *zdev)  {  	int entry; @@ -653,6 +546,82 @@ static void zpci_free_iomap(struct zpci_dev *zdev, int entry)  	spin_unlock(&zpci_iomap_lock);  } +static struct resource *__alloc_res(struct zpci_dev *zdev, unsigned long start, +				    unsigned long size, unsigned long flags) +{ +	struct resource *r; + +	r = kzalloc(sizeof(*r), GFP_KERNEL); +	if (!r) +		return NULL; + +	r->start = start; +	r->end = r->start + size - 1; +	r->flags = flags; +	r->name = zdev->res_name; + +	if (request_resource(&iomem_resource, r)) { +		kfree(r); +		return NULL; +	} +	return r; +} + +static int zpci_setup_bus_resources(struct zpci_dev *zdev, +				    struct list_head *resources) +{ +	unsigned long addr, size, flags; +	struct resource *res; +	int i, entry; + +	snprintf(zdev->res_name, sizeof(zdev->res_name), +		 "PCI Bus %04x:%02x", zdev->domain, ZPCI_BUS_NR); + +	for (i = 0; i < PCI_BAR_COUNT; i++) { +		if (!zdev->bars[i].size) +			continue; +		entry = zpci_alloc_iomap(zdev); +		if (entry < 0) +			return entry; +		zdev->bars[i].map_idx = entry; + +		/* only MMIO is supported */ +		flags = IORESOURCE_MEM; +		if (zdev->bars[i].val & 8) +			flags |= IORESOURCE_PREFETCH; +		if (zdev->bars[i].val & 4) +			flags |= IORESOURCE_MEM_64; + +		addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); + +		size = 1UL << zdev->bars[i].size; + +		res = __alloc_res(zdev, addr, size, flags); +		if (!res) { +			zpci_free_iomap(zdev, entry); +			return -ENOMEM; +		} +		zdev->bars[i].res = res; +		pci_add_resource(resources, res); +	} + +	return 0; +} + +static void zpci_cleanup_bus_resources(struct zpci_dev *zdev) +{ +	int i; + +	for (i = 0; i < PCI_BAR_COUNT; i++) { +		if (!zdev->bars[i].size) +			continue; + +		zpci_free_iomap(zdev, zdev->bars[i].map_idx); +		release_resource(zdev->bars[i].res); +		kfree(zdev->bars[i].res); +	} +} +  int pcibios_add_device(struct pci_dev *pdev)  {  	struct zpci_dev *zdev = get_zdev(pdev); @@ -660,6 +629,7 @@ int pcibios_add_device(struct pci_dev *pdev)  	int i;  	zdev->pdev = pdev; +	pdev->dev.groups = zpci_attr_groups;  	zpci_map_resources(zdev);  	for (i = 0; i < PCI_BAR_COUNT; i++) { @@ -675,27 +645,13 @@ int pcibios_add_device(struct pci_dev *pdev)  int pcibios_enable_device(struct pci_dev *pdev, int mask)  {  	struct zpci_dev *zdev = get_zdev(pdev); -	struct resource *res; -	u16 cmd; -	int i;  	zdev->pdev = pdev;  	zpci_debug_init_device(zdev);  	zpci_fmb_enable_device(zdev);  	zpci_map_resources(zdev); -	pci_read_config_word(pdev, PCI_COMMAND, &cmd); -	for (i = 0; i < PCI_BAR_COUNT; i++) { -		res = &pdev->resource[i]; - -		if (res->flags & IORESOURCE_IO) -			return -EINVAL; - -		if (res->flags & IORESOURCE_MEM) -			cmd |= PCI_COMMAND_MEMORY; -	} -	pci_write_config_word(pdev, PCI_COMMAND, cmd); -	return 0; +	return pci_enable_resources(pdev, mask);  }  void pcibios_disable_device(struct pci_dev *pdev) @@ -708,52 +664,47 @@ void pcibios_disable_device(struct pci_dev *pdev)  	zdev->pdev = NULL;  } -static int zpci_scan_bus(struct zpci_dev *zdev) +#ifdef CONFIG_HIBERNATE_CALLBACKS +static int zpci_restore(struct device *dev)  { -	struct resource *res; -	LIST_HEAD(resources); -	int i; +	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); +	int ret = 0; -	/* allocate mapping entry for each used bar */ -	for (i = 0; i < PCI_BAR_COUNT; i++) { -		unsigned long addr, size, flags; -		int entry; - -		if (!zdev->bars[i].size) -			continue; -		entry = zpci_alloc_iomap(zdev); -		if (entry < 0) -			return entry; -		zdev->bars[i].map_idx = entry; +	if (zdev->state != ZPCI_FN_STATE_ONLINE) +		goto out; -		/* only MMIO is supported */ -		flags = IORESOURCE_MEM; -		if (zdev->bars[i].val & 8) -			flags |= IORESOURCE_PREFETCH; -		if (zdev->bars[i].val & 4) -			flags |= IORESOURCE_MEM_64; +	ret = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES); +	if (ret) +		goto out; -		addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48); +	zpci_map_resources(zdev); +	zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET, +			   zdev->start_dma + zdev->iommu_size - 1, +			   (u64) zdev->dma_table); -		size = 1UL << zdev->bars[i].size; +out: +	return ret; +} -		res = zpci_alloc_bus_resource(addr, size, flags, zdev->domain); -		if (IS_ERR(res)) { -			zpci_free_iomap(zdev, entry); -			return PTR_ERR(res); -		} -		pci_add_resource(&resources, res); -	} +static int zpci_freeze(struct device *dev) +{ +	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); -	zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, -				      zdev, &resources); -	if (!zdev->bus) -		return -EIO; +	if (zdev->state != ZPCI_FN_STATE_ONLINE) +		return 0; -	zdev->bus->max_bus_speed = zdev->max_bus_speed; -	return 0; +	zpci_unregister_ioat(zdev, 0); +	return clp_disable_fh(zdev);  } +struct dev_pm_ops pcibios_pm_ops = { +	.thaw_noirq = zpci_restore, +	.freeze_noirq = zpci_freeze, +	.restore_noirq = zpci_restore, +	.poweroff_noirq = zpci_freeze, +}; +#endif /* CONFIG_HIBERNATE_CALLBACKS */ +  static int zpci_alloc_domain(struct zpci_dev *zdev)  {  	spin_lock(&zpci_domain_lock); @@ -774,6 +725,41 @@ static void zpci_free_domain(struct zpci_dev *zdev)  	spin_unlock(&zpci_domain_lock);  } +void pcibios_remove_bus(struct pci_bus *bus) +{ +	struct zpci_dev *zdev = get_zdev_by_bus(bus); + +	zpci_exit_slot(zdev); +	zpci_cleanup_bus_resources(zdev); +	zpci_free_domain(zdev); + +	spin_lock(&zpci_list_lock); +	list_del(&zdev->entry); +	spin_unlock(&zpci_list_lock); + +	kfree(zdev); +} + +static int zpci_scan_bus(struct zpci_dev *zdev) +{ +	LIST_HEAD(resources); +	int ret; + +	ret = zpci_setup_bus_resources(zdev, &resources); +	if (ret) +		return ret; + +	zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops, +				      zdev, &resources); +	if (!zdev->bus) { +		zpci_cleanup_bus_resources(zdev); +		return -EIO; +	} + +	zdev->bus->max_bus_speed = zdev->max_bus_speed; +	return 0; +} +  int zpci_enable_device(struct zpci_dev *zdev)  {  	int rc; @@ -781,7 +767,6 @@ int zpci_enable_device(struct zpci_dev *zdev)  	rc = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES);  	if (rc)  		goto out; -	pr_info("Enabled fh: 0x%x fid: 0x%x\n", zdev->fh, zdev->fid);  	rc = zpci_dma_init_device(zdev);  	if (rc) @@ -879,17 +864,23 @@ static void zpci_mem_exit(void)  	kmem_cache_destroy(zdev_fmb_cache);  } -static unsigned int s390_pci_probe; +static unsigned int s390_pci_probe = 1; +static unsigned int s390_pci_initialized;  char * __init pcibios_setup(char *str)  { -	if (!strcmp(str, "on")) { -		s390_pci_probe = 1; +	if (!strcmp(str, "off")) { +		s390_pci_probe = 0;  		return NULL;  	}  	return str;  } +bool zpci_is_enabled(void) +{ +	return s390_pci_initialized; +} +  static int __init pci_base_init(void)  {  	int rc; @@ -901,10 +892,6 @@ static int __init pci_base_init(void)  	    || !test_facility(71) || !test_facility(72))  		return 0; -	pr_info("Probing PCI hardware: PCI:%d  SID:%d  AEN:%d\n", -		test_facility(69), test_facility(70), -		test_facility(71)); -  	rc = zpci_debug_init();  	if (rc)  		goto out; @@ -925,6 +912,7 @@ static int __init pci_base_init(void)  	if (rc)  		goto out_find; +	s390_pci_initialized = 1;  	return 0;  out_find: @@ -942,5 +930,6 @@ subsys_initcall_sync(pci_base_init);  void zpci_rescan(void)  { -	clp_rescan_pci_devices_simple(); +	if (zpci_is_enabled()) +		clp_rescan_pci_devices_simple();  } diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 475563c3d1e..96545d7659f 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -16,6 +16,16 @@  #include <asm/pci_debug.h>  #include <asm/pci_clp.h> +static inline void zpci_err_clp(unsigned int rsp, int rc) +{ +	struct { +		unsigned int rsp; +		int rc; +	} __packed data = {rsp, rc}; + +	zpci_err_hex(&data, sizeof(data)); +} +  /*   * Call Logical Processor   * Retry logic is handled by the caller. @@ -54,7 +64,6 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,  	zdev->msi_addr = response->msia;  	zdev->fmb_update = response->mui; -	pr_debug("Supported number of MSI vectors: %u\n", response->noi);  	switch (response->version) {  	case 1:  		zdev->max_bus_speed = PCIE_SPEED_5_0GT; @@ -84,8 +93,8 @@ static int clp_query_pci_fngrp(struct zpci_dev *zdev, u8 pfgid)  	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)  		clp_store_query_pci_fngrp(zdev, &rrb->response);  	else { -		pr_err("Query PCI FNGRP failed with response: %x  cc: %d\n", -			rrb->response.hdr.rsp, rc); +		zpci_err("Q PCI FGRP:\n"); +		zpci_err_clp(rrb->response.hdr.rsp, rc);  		rc = -EIO;  	}  	clp_free_block(rrb); @@ -105,6 +114,16 @@ static int clp_store_query_pci_fn(struct zpci_dev *zdev,  	zdev->end_dma = response->edma;  	zdev->pchid = response->pchid;  	zdev->pfgid = response->pfgid; +	zdev->pft = response->pft; +	zdev->vfn = response->vfn; +	zdev->uid = response->uid; + +	memcpy(zdev->pfip, response->pfip, sizeof(zdev->pfip)); +	if (response->util_str_avail) { +		memcpy(zdev->util_str, response->util_str, +		       sizeof(zdev->util_str)); +	} +  	return 0;  } @@ -131,8 +150,8 @@ static int clp_query_pci_fn(struct zpci_dev *zdev, u32 fh)  		if (rrb->response.pfgid)  			rc = clp_query_pci_fngrp(zdev, rrb->response.pfgid);  	} else { -		pr_err("Query PCI failed with response: %x  cc: %d\n", -			 rrb->response.hdr.rsp, rc); +		zpci_err("Q PCI FN:\n"); +		zpci_err_clp(rrb->response.hdr.rsp, rc);  		rc = -EIO;  	}  out: @@ -146,9 +165,9 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)  	int rc;  	zpci_dbg(3, "add fid:%x, fh:%x, c:%d\n", fid, fh, configured); -	zdev = zpci_alloc_device(); -	if (IS_ERR(zdev)) -		return PTR_ERR(zdev); +	zdev = kzalloc(sizeof(*zdev), GFP_KERNEL); +	if (!zdev) +		return -ENOMEM;  	zdev->fh = fh;  	zdev->fid = fid; @@ -169,7 +188,7 @@ int clp_add_pci_device(u32 fid, u32 fh, int configured)  	return 0;  error: -	zpci_free_device(zdev); +	kfree(zdev);  	return rc;  } @@ -206,8 +225,8 @@ static int clp_set_pci_fn(u32 *fh, u8 nr_dma_as, u8 command)  	if (!rc && rrb->response.hdr.rsp == CLP_RC_OK)  		*fh = rrb->response.fh;  	else { -		zpci_dbg(0, "SPF fh:%x, cc:%d, resp:%x\n", *fh, rc, -			 rrb->response.hdr.rsp); +		zpci_err("Set PCI FN:\n"); +		zpci_err_clp(rrb->response.hdr.rsp, rc);  		rc = -EIO;  	}  	clp_free_block(rrb); @@ -262,8 +281,8 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb,  		/* Get PCI function handle list */  		rc = clp_instr(rrb);  		if (rc || rrb->response.hdr.rsp != CLP_RC_OK) { -			pr_err("List PCI failed with response: 0x%x  cc: %d\n", -				rrb->response.hdr.rsp, rc); +			zpci_err("List PCI FN:\n"); +			zpci_err_clp(rrb->response.hdr.rsp, rc);  			rc = -EIO;  			goto out;  		} @@ -273,17 +292,11 @@ static int clp_list_pci(struct clp_req_rsp_list_pci *rrb,  		entries = (rrb->response.hdr.len - LIST_PCI_HDR_LEN) /  			rrb->response.entry_size; -		pr_info("Detected number of PCI functions: %u\n", entries); -		/* Store the returned resume token as input for the next call */  		resume_token = rrb->response.resume_token; -  		for (i = 0; i < entries; i++)  			cb(&rrb->response.fh_list[i]);  	} while (resume_token); - -	pr_debug("Maximum number of supported PCI functions: %u\n", -		rrb->response.max_fn);  out:  	return rc;  } diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index 75c69b402e0..c5c66840ac0 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c @@ -139,7 +139,7 @@ void zpci_debug_exit_device(struct zpci_dev *zdev)  int __init zpci_debug_init(void)  {  	/* event trace buffer */ -	pci_debug_msg_id = debug_register("pci_msg", 16, 1, 16 * sizeof(long)); +	pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long));  	if (!pci_debug_msg_id)  		return -EINVAL;  	debug_register_view(pci_debug_msg_id, &debug_sprintf_view); diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 7e5573acb06..f91c0311980 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -145,10 +145,8 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,  		return -EINVAL;  	spin_lock_irqsave(&zdev->dma_table_lock, irq_flags); -	if (!zdev->dma_table) { -		dev_err(&zdev->pdev->dev, "Missing DMA table\n"); +	if (!zdev->dma_table)  		goto no_refresh; -	}  	for (i = 0; i < nr_pages; i++) {  		dma_update_cpu_trans(zdev, page_addr, dma_addr, flags); @@ -208,11 +206,13 @@ static void dma_cleanup_tables(struct zpci_dev *zdev)  	zdev->dma_table = NULL;  } -static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start, -				   int size) +static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, +				       unsigned long start, int size)  { -	unsigned long boundary_size = 0x1000000; +	unsigned long boundary_size; +	boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1, +			      PAGE_SIZE) >> PAGE_SHIFT;  	return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,  				start, size, 0, boundary_size, 0);  } @@ -280,24 +280,22 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,  	size = nr_pages * PAGE_SIZE;  	dma_addr = zdev->start_dma + iommu_page_index * PAGE_SIZE; -	if (dma_addr + size > zdev->end_dma) { -		dev_err(dev, "(dma_addr: 0x%16.16LX + size: 0x%16.16lx) > end_dma: 0x%16.16Lx\n", -			 dma_addr, size, zdev->end_dma); +	if (dma_addr + size > zdev->end_dma)  		goto out_free; -	}  	if (direction == DMA_NONE || direction == DMA_TO_DEVICE)  		flags |= ZPCI_TABLE_PROTECTED;  	if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) { -		atomic64_add(nr_pages, (atomic64_t *) &zdev->fmb->mapped_pages); +		atomic64_add(nr_pages, &zdev->fmb->mapped_pages);  		return dma_addr + (offset & ~PAGE_MASK);  	}  out_free:  	dma_free_iommu(zdev, iommu_page_index, nr_pages);  out_err: -	dev_err(dev, "Failed to map addr: %lx\n", pa); +	zpci_err("map error:\n"); +	zpci_err_hex(&pa, sizeof(pa));  	return DMA_ERROR_CODE;  } @@ -312,10 +310,12 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,  	npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);  	dma_addr = dma_addr & PAGE_MASK;  	if (dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE, -			     ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) -		dev_err(dev, "Failed to unmap addr: %Lx\n", dma_addr); +			     ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) { +		zpci_err("unmap error:\n"); +		zpci_err_hex(&dma_addr, sizeof(dma_addr)); +	} -	atomic64_add(npages, (atomic64_t *) &zdev->fmb->unmapped_pages); +	atomic64_add(npages, &zdev->fmb->unmapped_pages);  	iommu_page_index = (dma_addr - zdev->start_dma) >> PAGE_SHIFT;  	dma_free_iommu(zdev, iommu_page_index, npages);  } @@ -334,7 +334,6 @@ static void *s390_dma_alloc(struct device *dev, size_t size,  	if (!page)  		return NULL; -	atomic64_add(size / PAGE_SIZE, (atomic64_t *) &zdev->fmb->allocated_pages);  	pa = page_to_phys(page);  	memset((void *) pa, 0, size); @@ -345,6 +344,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,  		return NULL;  	} +	atomic64_add(size / PAGE_SIZE, &zdev->fmb->allocated_pages);  	if (dma_handle)  		*dma_handle = map;  	return (void *) pa; @@ -354,8 +354,11 @@ static void s390_dma_free(struct device *dev, size_t size,  			  void *pa, dma_addr_t dma_handle,  			  struct dma_attrs *attrs)  { -	s390_dma_unmap_pages(dev, dma_handle, PAGE_ALIGN(size), -			     DMA_BIDIRECTIONAL, NULL); +	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); + +	size = PAGE_ALIGN(size); +	atomic64_sub(size / PAGE_SIZE, &zdev->fmb->allocated_pages); +	s390_dma_unmap_pages(dev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);  	free_pages((unsigned long) pa, get_order(size));  } diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index 0aecaf95484..6d7f5a3016c 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -10,6 +10,8 @@  #include <linux/kernel.h>  #include <linux/pci.h> +#include <asm/pci_debug.h> +#include <asm/sclp.h>  /* Content Code Description for PCI Function Error */  struct zpci_ccdf_err { @@ -41,55 +43,94 @@ struct zpci_ccdf_avail {  	u16 pec;			/* PCI event code */  } __packed; -static void zpci_event_log_err(struct zpci_ccdf_err *ccdf) +static void __zpci_event_error(struct zpci_ccdf_err *ccdf)  {  	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid); -	zpci_err("SEI error CCD:\n"); +	zpci_err("error CCDF:\n");  	zpci_err_hex(ccdf, sizeof(*ccdf)); -	dev_err(&zdev->pdev->dev, "event code: 0x%x\n", ccdf->pec); + +	if (!zdev) +		return; + +	pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n", +	       pci_name(zdev->pdev), ccdf->pec, ccdf->fid);  } -static void zpci_event_log_avail(struct zpci_ccdf_avail *ccdf) +void zpci_event_error(void *data) +{ +	if (zpci_is_enabled()) +		__zpci_event_error(data); +} + +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_err("%s%s: availability event: fh: 0x%x  fid: 0x%x  event code: 0x%x  reason:", -		(zdev) ? dev_driver_string(&zdev->pdev->dev) : "?", -		(zdev) ? dev_name(&zdev->pdev->dev) : "?", -		ccdf->fh, ccdf->fid, ccdf->pec); -	print_hex_dump(KERN_CONT, "ccdf", DUMP_PREFIX_OFFSET, -		       16, 1, ccdf, sizeof(*ccdf), false); +	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: -		zpci_enable_device(zdev); +	case 0x0301: /* Standby -> Configured */ +		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 0x0302: -		clp_add_pci_device(ccdf->fid, ccdf->fh, 0); +	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: +	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;  	}  } -void zpci_event_error(void *data) -{ -	struct zpci_ccdf_err *ccdf = data; -	struct zpci_dev *zdev; - -	zpci_event_log_err(ccdf); -	zdev = get_zdev_by_fid(ccdf->fid); -	if (!zdev) { -		pr_err("Error event for unknown fid: %x", ccdf->fid); -		return; -	} -} -  void zpci_event_availability(void *data)  { -	zpci_event_log_avail(data); +	if (zpci_is_enabled()) +		__zpci_event_availability(data);  } diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c index cf8a12ff733..9190214b870 100644 --- a/arch/s390/pci/pci_sysfs.c +++ b/arch/s390/pci/pci_sysfs.c @@ -12,98 +12,99 @@  #include <linux/stat.h>  #include <linux/pci.h> -static ssize_t show_fid(struct device *dev, struct device_attribute *attr, -			char *buf) -{ -	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - -	return sprintf(buf, "0x%08x\n", zdev->fid); -} -static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL); - -static ssize_t show_fh(struct device *dev, struct device_attribute *attr, -		       char *buf) -{ -	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - -	return sprintf(buf, "0x%08x\n", zdev->fh); -} -static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL); - -static ssize_t show_pchid(struct device *dev, struct device_attribute *attr, -			  char *buf) -{ -	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - -	return sprintf(buf, "0x%04x\n", zdev->pchid); -} -static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL); - -static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr, -			  char *buf) -{ -	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); - -	return sprintf(buf, "0x%02x\n", zdev->pfgid); -} -static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); - -static void recover_callback(struct device *dev) +#define zpci_attr(name, fmt, member)					\ +static ssize_t name##_show(struct device *dev,				\ +			   struct device_attribute *attr, char *buf)	\ +{									\ +	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));		\ +									\ +	return sprintf(buf, fmt, zdev->member);				\ +}									\ +static DEVICE_ATTR_RO(name) + +zpci_attr(function_id, "0x%08x\n", fid); +zpci_attr(function_handle, "0x%08x\n", fh); +zpci_attr(pchid, "0x%04x\n", pchid); +zpci_attr(pfgid, "0x%02x\n", pfgid); +zpci_attr(vfn, "0x%04x\n", vfn); +zpci_attr(pft, "0x%02x\n", pft); +zpci_attr(uid, "0x%x\n", uid); +zpci_attr(segment0, "0x%02x\n", pfip[0]); +zpci_attr(segment1, "0x%02x\n", pfip[1]); +zpci_attr(segment2, "0x%02x\n", pfip[2]); +zpci_attr(segment3, "0x%02x\n", pfip[3]); + +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 = get_zdev(pdev);  	int ret; +	if (!device_remove_file_self(dev, attr)) +		return count; +  	pci_stop_and_remove_bus_device(pdev);  	ret = zpci_disable_device(zdev);  	if (ret) -		return; +		return ret;  	ret = zpci_enable_device(zdev);  	if (ret) -		return; +		return ret;  	pci_rescan_bus(zdev->bus); +	return count;  } +static DEVICE_ATTR_WO(recover); -static ssize_t store_recover(struct device *dev, struct device_attribute *attr, -			     const char *buf, size_t count) +static ssize_t util_string_read(struct file *filp, struct kobject *kobj, +				struct bin_attribute *attr, char *buf, +				loff_t off, size_t count)  { -	int rc = device_schedule_callback(dev, recover_callback); -	return rc ? rc : count; -} -static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover); +	struct device *dev = kobj_to_dev(kobj); +	struct pci_dev *pdev = to_pci_dev(dev); +	struct zpci_dev *zdev = get_zdev(pdev); -static struct device_attribute *zpci_dev_attrs[] = { -	&dev_attr_function_id, -	&dev_attr_function_handle, -	&dev_attr_pchid, -	&dev_attr_pfgid, -	&dev_attr_recover, +	return memory_read_from_buffer(buf, count, &off, zdev->util_str, +				       sizeof(zdev->util_str)); +} +static BIN_ATTR_RO(util_string, CLP_UTIL_STR_LEN); +static struct bin_attribute *zpci_bin_attrs[] = { +	&bin_attr_util_string,  	NULL,  }; -int zpci_sysfs_add_device(struct device *dev) -{ -	int i, rc = 0; - -	for (i = 0; zpci_dev_attrs[i]; i++) { -		rc = device_create_file(dev, zpci_dev_attrs[i]); -		if (rc) -			goto error; -	} -	return 0; - -error: -	while (--i >= 0) -		device_remove_file(dev, zpci_dev_attrs[i]); -	return rc; -} +static struct attribute *zpci_dev_attrs[] = { +	&dev_attr_function_id.attr, +	&dev_attr_function_handle.attr, +	&dev_attr_pchid.attr, +	&dev_attr_pfgid.attr, +	&dev_attr_pft.attr, +	&dev_attr_vfn.attr, +	&dev_attr_uid.attr, +	&dev_attr_recover.attr, +	NULL, +}; +static struct attribute_group zpci_attr_group = { +	.attrs = zpci_dev_attrs, +	.bin_attrs = zpci_bin_attrs, +}; -void zpci_sysfs_remove_device(struct device *dev) -{ -	int i; +static struct attribute *pfip_attrs[] = { +	&dev_attr_segment0.attr, +	&dev_attr_segment1.attr, +	&dev_attr_segment2.attr, +	&dev_attr_segment3.attr, +	NULL, +}; +static struct attribute_group pfip_attr_group = { +	.name = "pfip", +	.attrs = pfip_attrs, +}; -	for (i = 0; zpci_dev_attrs[i]; i++) -		device_remove_file(dev, zpci_dev_attrs[i]); -} +const struct attribute_group *zpci_attr_groups[] = { +	&zpci_attr_group, +	&pfip_attr_group, +	NULL, +};  | 
