|
@@ -98,6 +98,10 @@ EXPORT_SYMBOL_GPL(zpci_iomap_start);
|
|
|
static int __read_mostly aisb_max;
|
|
|
|
|
|
static struct kmem_cache *zdev_irq_cache;
|
|
|
+static struct kmem_cache *zdev_fmb_cache;
|
|
|
+
|
|
|
+debug_info_t *pci_debug_msg_id;
|
|
|
+debug_info_t *pci_debug_err_id;
|
|
|
|
|
|
static inline int irq_to_msi_nr(unsigned int irq)
|
|
|
{
|
|
@@ -216,6 +220,7 @@ struct mod_pci_args {
|
|
|
u64 base;
|
|
|
u64 limit;
|
|
|
u64 iota;
|
|
|
+ u64 fmb_addr;
|
|
|
};
|
|
|
|
|
|
static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args *args)
|
|
@@ -232,6 +237,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
|
|
|
fib->pba = args->base;
|
|
|
fib->pal = args->limit;
|
|
|
fib->iota = args->iota;
|
|
|
+ fib->fmb_addr = args->fmb_addr;
|
|
|
|
|
|
rc = mpcifc_instr(req, fib);
|
|
|
free_page((unsigned long) fib);
|
|
@@ -242,7 +248,7 @@ static int mod_pci(struct zpci_dev *zdev, int fn, u8 dmaas, struct mod_pci_args
|
|
|
int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
|
|
|
u64 base, u64 limit, u64 iota)
|
|
|
{
|
|
|
- struct mod_pci_args args = { base, limit, iota };
|
|
|
+ struct mod_pci_args args = { base, limit, iota, 0 };
|
|
|
|
|
|
WARN_ON_ONCE(iota & 0x3fff);
|
|
|
args.iota |= ZPCI_IOTA_RTTO_FLAG;
|
|
@@ -252,7 +258,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas,
|
|
|
/* Modify PCI: Unregister I/O address translation parameters */
|
|
|
int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
|
|
|
{
|
|
|
- struct mod_pci_args args = { 0, 0, 0 };
|
|
|
+ struct mod_pci_args args = { 0, 0, 0, 0 };
|
|
|
|
|
|
return mod_pci(zdev, ZPCI_MOD_FC_DEREG_IOAT, dmaas, &args);
|
|
|
}
|
|
@@ -260,11 +266,46 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas)
|
|
|
/* Modify PCI: Unregister adapter interruptions */
|
|
|
static int zpci_unregister_airq(struct zpci_dev *zdev)
|
|
|
{
|
|
|
- struct mod_pci_args args = { 0, 0, 0 };
|
|
|
+ struct mod_pci_args args = { 0, 0, 0, 0 };
|
|
|
|
|
|
return mod_pci(zdev, ZPCI_MOD_FC_DEREG_INT, 0, &args);
|
|
|
}
|
|
|
|
|
|
+/* Modify PCI: Set PCI function measurement parameters */
|
|
|
+int zpci_fmb_enable_device(struct zpci_dev *zdev)
|
|
|
+{
|
|
|
+ struct mod_pci_args args = { 0, 0, 0, 0 };
|
|
|
+
|
|
|
+ if (zdev->fmb)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ zdev->fmb = kmem_cache_alloc(zdev_fmb_cache, GFP_KERNEL);
|
|
|
+ if (!zdev->fmb)
|
|
|
+ return -ENOMEM;
|
|
|
+ memset(zdev->fmb, 0, sizeof(*zdev->fmb));
|
|
|
+ WARN_ON((u64) zdev->fmb & 0xf);
|
|
|
+
|
|
|
+ args.fmb_addr = virt_to_phys(zdev->fmb);
|
|
|
+ return mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
|
|
|
+}
|
|
|
+
|
|
|
+/* Modify PCI: Disable PCI function measurement */
|
|
|
+int zpci_fmb_disable_device(struct zpci_dev *zdev)
|
|
|
+{
|
|
|
+ struct mod_pci_args args = { 0, 0, 0, 0 };
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ if (!zdev->fmb)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /* Function measurement is disabled if fmb address is zero */
|
|
|
+ rc = mod_pci(zdev, ZPCI_MOD_FC_SET_MEASURE, 0, &args);
|
|
|
+
|
|
|
+ kmem_cache_free(zdev_fmb_cache, zdev->fmb);
|
|
|
+ zdev->fmb = NULL;
|
|
|
+ return rc;
|
|
|
+}
|
|
|
+
|
|
|
#define ZPCI_PCIAS_CFGSPC 15
|
|
|
|
|
|
static int zpci_cfg_load(struct zpci_dev *zdev, int offset, u32 *val, u8 len)
|
|
@@ -633,6 +674,7 @@ static void zpci_remove_device(struct pci_dev *pdev)
|
|
|
dev_info(&pdev->dev, "Removing device %u\n", zdev->domain);
|
|
|
zdev->state = ZPCI_FN_STATE_CONFIGURED;
|
|
|
zpci_dma_exit_device(zdev);
|
|
|
+ zpci_fmb_disable_device(zdev);
|
|
|
zpci_sysfs_remove_device(&pdev->dev);
|
|
|
zpci_unmap_resources(pdev);
|
|
|
list_del(&zdev->entry); /* can be called from init */
|
|
@@ -799,6 +841,16 @@ static void zpci_irq_exit(void)
|
|
|
kfree(bucket);
|
|
|
}
|
|
|
|
|
|
+void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m)
|
|
|
+{
|
|
|
+ if (!zdev)
|
|
|
+ return;
|
|
|
+
|
|
|
+ seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries));
|
|
|
+ seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n",
|
|
|
+ get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb);
|
|
|
+}
|
|
|
+
|
|
|
static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
|
|
|
unsigned long flags, int domain)
|
|
|
{
|
|
@@ -994,6 +1046,8 @@ int zpci_scan_device(struct zpci_dev *zdev)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ zpci_debug_init_device(zdev);
|
|
|
+ zpci_fmb_enable_device(zdev);
|
|
|
zpci_map_resources(zdev);
|
|
|
pci_bus_add_devices(zdev->bus);
|
|
|
|
|
@@ -1020,6 +1074,11 @@ static int zpci_mem_init(void)
|
|
|
if (!zdev_irq_cache)
|
|
|
goto error_zdev;
|
|
|
|
|
|
+ zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
|
|
|
+ 16, 0, NULL);
|
|
|
+ if (!zdev_fmb_cache)
|
|
|
+ goto error_fmb;
|
|
|
+
|
|
|
/* TODO: use realloc */
|
|
|
zpci_iomap_start = kzalloc(ZPCI_IOMAP_MAX_ENTRIES * sizeof(*zpci_iomap_start),
|
|
|
GFP_KERNEL);
|
|
@@ -1028,6 +1087,8 @@ static int zpci_mem_init(void)
|
|
|
return 0;
|
|
|
|
|
|
error_iomap:
|
|
|
+ kmem_cache_destroy(zdev_fmb_cache);
|
|
|
+error_fmb:
|
|
|
kmem_cache_destroy(zdev_irq_cache);
|
|
|
error_zdev:
|
|
|
return -ENOMEM;
|
|
@@ -1037,6 +1098,7 @@ static void zpci_mem_exit(void)
|
|
|
{
|
|
|
kfree(zpci_iomap_start);
|
|
|
kmem_cache_destroy(zdev_irq_cache);
|
|
|
+ kmem_cache_destroy(zdev_fmb_cache);
|
|
|
}
|
|
|
|
|
|
unsigned int pci_probe = 1;
|
|
@@ -1066,6 +1128,10 @@ static int __init pci_base_init(void)
|
|
|
test_facility(69), test_facility(70),
|
|
|
test_facility(71));
|
|
|
|
|
|
+ rc = zpci_debug_init();
|
|
|
+ if (rc)
|
|
|
+ return rc;
|
|
|
+
|
|
|
rc = zpci_mem_init();
|
|
|
if (rc)
|
|
|
goto out_mem;
|
|
@@ -1098,6 +1164,7 @@ out_irq:
|
|
|
out_hash:
|
|
|
zpci_mem_exit();
|
|
|
out_mem:
|
|
|
+ zpci_debug_exit();
|
|
|
return rc;
|
|
|
}
|
|
|
subsys_initcall(pci_base_init);
|