summaryrefslogtreecommitdiff
path: root/arch/s390/pci/pci.c
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /arch/s390/pci/pci.c
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'arch/s390/pci/pci.c')
-rw-r--r--arch/s390/pci/pci.c280
1 files changed, 122 insertions, 158 deletions
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index bf7c73d..f17a834 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -120,17 +120,26 @@ 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 = {0};
+ 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;
+ 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;
- return zpci_mod_fc(req, &fib);
+ rc = zpci_mod_fc(req, fib);
+ pr_debug("%s mpcifc returned noi: %d\n", __func__, fib->noi);
+
+ free_page((unsigned long) fib);
+ return rc;
}
struct mod_pci_args {
@@ -143,14 +152,22 @@ 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 = {0};
+ 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;
- 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;
- return zpci_mod_fc(req, &fib);
+ rc = zpci_mod_fc(req, fib);
+ free_page((unsigned long) fib);
+ return rc;
}
/* Modify PCI: Register I/O address translation parameters */
@@ -407,6 +424,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
struct msi_msg msg;
int rc;
+ pr_debug("%s: requesting %d MSI-X interrupts...", __func__, nvec);
if (type != PCI_CAP_ID_MSIX && type != PCI_CAP_ID_MSI)
return -EINVAL;
msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX);
@@ -471,6 +489,7 @@ 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;
}
@@ -480,10 +499,14 @@ 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)
+ if (rc) {
+ dev_err(&pdev->dev, "deregister MSI failed with: %d\n", rc);
return;
+ }
/* Release MSI interrupts */
list_for_each_entry(msi, &pdev->msi_list, list) {
@@ -530,6 +553,20 @@ 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);
@@ -565,6 +602,34 @@ 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;
@@ -588,82 +653,6 @@ 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);
@@ -719,46 +708,51 @@ void pcibios_disable_device(struct pci_dev *pdev)
zdev->pdev = NULL;
}
-#ifdef CONFIG_HIBERNATE_CALLBACKS
-static int zpci_restore(struct device *dev)
+static int zpci_scan_bus(struct zpci_dev *zdev)
{
- struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
- int ret = 0;
+ struct resource *res;
+ LIST_HEAD(resources);
+ int i;
- if (zdev->state != ZPCI_FN_STATE_ONLINE)
- goto out;
+ /* allocate mapping entry for each used bar */
+ for (i = 0; i < PCI_BAR_COUNT; i++) {
+ unsigned long addr, size, flags;
+ int entry;
- ret = clp_enable_fh(zdev, ZPCI_NR_DMA_SPACES);
- if (ret)
- goto out;
+ if (!zdev->bars[i].size)
+ continue;
+ entry = zpci_alloc_iomap(zdev);
+ if (entry < 0)
+ return entry;
+ zdev->bars[i].map_idx = entry;
- 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);
+ /* 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;
-out:
- return ret;
-}
+ addr = ZPCI_IOMAP_ADDR_BASE + ((u64) entry << 48);
-static int zpci_freeze(struct device *dev)
-{
- struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
+ size = 1UL << zdev->bars[i].size;
- if (zdev->state != ZPCI_FN_STATE_ONLINE)
- return 0;
+ 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);
+ }
- zpci_unregister_ioat(zdev, 0);
- return clp_disable_fh(zdev);
-}
+ zdev->bus = pci_scan_root_bus(NULL, ZPCI_BUS_NR, &pci_root_ops,
+ zdev, &resources);
+ if (!zdev->bus)
+ return -EIO;
-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 */
+ zdev->bus->max_bus_speed = zdev->max_bus_speed;
+ return 0;
+}
static int zpci_alloc_domain(struct zpci_dev *zdev)
{
@@ -780,41 +774,6 @@ 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;
@@ -822,6 +781,7 @@ 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)
@@ -941,6 +901,10 @@ 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;