Skip to content

Commit

Permalink
s390/pci: performance statistics and debug infrastructure
Browse files Browse the repository at this point in the history
Add support for reading the PCI function measurement block counters
provided by the hypervisor. Add two s390 debug features, one for
critical errors and one for tracing and provide wrappers to log data.

Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Jan Glauber authored and Martin Schwidefsky committed Dec 14, 2012
1 parent 7313264 commit d0b0885
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 5 deletions.
39 changes: 39 additions & 0 deletions arch/s390/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <asm-generic/pci.h>
#include <asm-generic/pci-dma-compat.h>
#include <asm/pci_clp.h>
#include <asm/pci_debug.h>

#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0x10000000
Expand All @@ -33,6 +34,25 @@ int pci_proc_domain(struct pci_bus *);
#define ZPCI_FC_BLOCKED 0x20
#define ZPCI_FC_DMA_ENABLED 0x10

struct zpci_fmb {
u32 format : 8;
u32 dma_valid : 1;
u32 : 23;
u32 samples;
u64 last_update;
/* hardware counters */
u64 ld_ops;
u64 st_ops;
u64 stb_ops;
u64 rpcit_ops;
u64 dma_rbytes;
u64 dma_wbytes;
/* software counters */
atomic64_t allocated_pages;
atomic64_t mapped_pages;
atomic64_t unmapped_pages;
} __packed __aligned(16);

struct msi_map {
unsigned long irq;
struct msi_desc *msi;
Expand Down Expand Up @@ -92,7 +112,15 @@ struct zpci_dev {
u64 end_dma; /* End of available DMA addresses */
u64 dma_mask; /* DMA address space mask */

/* Function measurement block */
struct zpci_fmb *fmb;
u16 fmb_update; /* update interval */

enum pci_bus_speed max_bus_speed;

struct dentry *debugfs_dev;
struct dentry *debugfs_perf;
struct dentry *debugfs_debug;
};

struct pci_hp_callback_ops {
Expand Down Expand Up @@ -155,4 +183,15 @@ extern struct list_head zpci_list;
extern struct pci_hp_callback_ops hotplug_ops;
extern unsigned int pci_probe;

/* FMB */
int zpci_fmb_enable_device(struct zpci_dev *);
int zpci_fmb_disable_device(struct zpci_dev *);

/* Debug */
int zpci_debug_init(void);
void zpci_debug_exit(void);
void zpci_debug_init_device(struct zpci_dev *);
void zpci_debug_exit_device(struct zpci_dev *);
void zpci_debug_info(struct zpci_dev *, struct seq_file *);

#endif
36 changes: 36 additions & 0 deletions arch/s390/include/asm/pci_debug.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef _S390_ASM_PCI_DEBUG_H
#define _S390_ASM_PCI_DEBUG_H

#include <asm/debug.h>

extern debug_info_t *pci_debug_msg_id;
extern debug_info_t *pci_debug_err_id;

#ifdef CONFIG_PCI_DEBUG
#define zpci_dbg(fmt, args...) \
do { \
if (pci_debug_msg_id->level >= 2) \
debug_sprintf_event(pci_debug_msg_id, 2, fmt , ## args);\
} while (0)

#else /* !CONFIG_PCI_DEBUG */
#define zpci_dbg(fmt, args...) do { } while (0)
#endif

#define zpci_err(text...) \
do { \
char debug_buffer[16]; \
snprintf(debug_buffer, 16, text); \
debug_text_event(pci_debug_err_id, 0, debug_buffer); \
} while (0)

static inline void zpci_err_hex(void *addr, int len)
{
while (len > 0) {
debug_event(pci_debug_err_id, 0, (void *) addr, len);
len -= pci_debug_err_id->buf_size;
addr += pci_debug_err_id->buf_size;
}
}

#endif
2 changes: 1 addition & 1 deletion arch/s390/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
#

obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_msi.o \
pci_sysfs.o pci_event.o
pci_sysfs.o pci_event.o pci_debug.o
73 changes: 70 additions & 3 deletions arch/s390/pci/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -252,19 +258,54 @@ 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);
}

/* 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)
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1098,6 +1164,7 @@ static int __init pci_base_init(void)
out_hash:
zpci_mem_exit();
out_mem:
zpci_debug_exit();
return rc;
}
subsys_initcall(pci_base_init);
1 change: 1 addition & 0 deletions arch/s390/pci/pci_clp.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev,
zdev->tlb_refresh = response->refresh;
zdev->dma_mask = response->dasm;
zdev->msi_addr = response->msia;
zdev->fmb_update = response->mui;

pr_debug("Supported number of MSI vectors: %u\n", response->noi);
switch (response->version) {
Expand Down
Loading

0 comments on commit d0b0885

Please sign in to comment.