1edae1f06SKan Liang /* SPDX-License-Identifier: GPL-2.0-only */ 2edae1f06SKan Liang /* 3edae1f06SKan Liang * Support Intel uncore PerfMon discovery mechanism. 4edae1f06SKan Liang * Copyright(c) 2021 Intel Corporation. 5edae1f06SKan Liang */ 6edae1f06SKan Liang #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7edae1f06SKan Liang 8edae1f06SKan Liang #include "uncore.h" 9edae1f06SKan Liang #include "uncore_discovery.h" 10edae1f06SKan Liang 11edae1f06SKan Liang static struct rb_root discovery_tables = RB_ROOT; 12edae1f06SKan Liang static int num_discovered_types[UNCORE_ACCESS_MAX]; 13edae1f06SKan Liang 14edae1f06SKan Liang static bool has_generic_discovery_table(void) 15edae1f06SKan Liang { 16edae1f06SKan Liang struct pci_dev *dev; 17edae1f06SKan Liang int dvsec; 18edae1f06SKan Liang 19edae1f06SKan Liang dev = pci_get_device(PCI_VENDOR_ID_INTEL, UNCORE_DISCOVERY_TABLE_DEVICE, NULL); 20edae1f06SKan Liang if (!dev) 21edae1f06SKan Liang return false; 22edae1f06SKan Liang 23edae1f06SKan Liang /* A discovery table device has the unique capability ID. */ 24edae1f06SKan Liang dvsec = pci_find_next_ext_capability(dev, 0, UNCORE_EXT_CAP_ID_DISCOVERY); 25edae1f06SKan Liang pci_dev_put(dev); 26edae1f06SKan Liang if (dvsec) 27edae1f06SKan Liang return true; 28edae1f06SKan Liang 29edae1f06SKan Liang return false; 30edae1f06SKan Liang } 31edae1f06SKan Liang 32edae1f06SKan Liang static int logical_die_id; 33edae1f06SKan Liang 34edae1f06SKan Liang static int get_device_die_id(struct pci_dev *dev) 35edae1f06SKan Liang { 36edae1f06SKan Liang int cpu, node = pcibus_to_node(dev->bus); 37edae1f06SKan Liang 38edae1f06SKan Liang /* 39edae1f06SKan Liang * If the NUMA info is not available, assume that the logical die id is 40edae1f06SKan Liang * continuous in the order in which the discovery table devices are 41edae1f06SKan Liang * detected. 42edae1f06SKan Liang */ 43edae1f06SKan Liang if (node < 0) 44edae1f06SKan Liang return logical_die_id++; 45edae1f06SKan Liang 46edae1f06SKan Liang for_each_cpu(cpu, cpumask_of_node(node)) { 47edae1f06SKan Liang struct cpuinfo_x86 *c = &cpu_data(cpu); 48edae1f06SKan Liang 49edae1f06SKan Liang if (c->initialized && cpu_to_node(cpu) == node) 50edae1f06SKan Liang return c->logical_die_id; 51edae1f06SKan Liang } 52edae1f06SKan Liang 53edae1f06SKan Liang /* 54edae1f06SKan Liang * All CPUs of a node may be offlined. For this case, 55edae1f06SKan Liang * the PCI and MMIO type of uncore blocks which are 56edae1f06SKan Liang * enumerated by the device will be unavailable. 57edae1f06SKan Liang */ 58edae1f06SKan Liang return -1; 59edae1f06SKan Liang } 60edae1f06SKan Liang 61edae1f06SKan Liang #define __node_2_type(cur) \ 62edae1f06SKan Liang rb_entry((cur), struct intel_uncore_discovery_type, node) 63edae1f06SKan Liang 64edae1f06SKan Liang static inline int __type_cmp(const void *key, const struct rb_node *b) 65edae1f06SKan Liang { 66edae1f06SKan Liang struct intel_uncore_discovery_type *type_b = __node_2_type(b); 67edae1f06SKan Liang const u16 *type_id = key; 68edae1f06SKan Liang 69edae1f06SKan Liang if (type_b->type > *type_id) 70edae1f06SKan Liang return -1; 71edae1f06SKan Liang else if (type_b->type < *type_id) 72edae1f06SKan Liang return 1; 73edae1f06SKan Liang 74edae1f06SKan Liang return 0; 75edae1f06SKan Liang } 76edae1f06SKan Liang 77edae1f06SKan Liang static inline struct intel_uncore_discovery_type * 78edae1f06SKan Liang search_uncore_discovery_type(u16 type_id) 79edae1f06SKan Liang { 80edae1f06SKan Liang struct rb_node *node = rb_find(&type_id, &discovery_tables, __type_cmp); 81edae1f06SKan Liang 82edae1f06SKan Liang return (node) ? __node_2_type(node) : NULL; 83edae1f06SKan Liang } 84edae1f06SKan Liang 85edae1f06SKan Liang static inline bool __type_less(struct rb_node *a, const struct rb_node *b) 86edae1f06SKan Liang { 87edae1f06SKan Liang return (__node_2_type(a)->type < __node_2_type(b)->type); 88edae1f06SKan Liang } 89edae1f06SKan Liang 90edae1f06SKan Liang static struct intel_uncore_discovery_type * 91edae1f06SKan Liang add_uncore_discovery_type(struct uncore_unit_discovery *unit) 92edae1f06SKan Liang { 93edae1f06SKan Liang struct intel_uncore_discovery_type *type; 94edae1f06SKan Liang 95edae1f06SKan Liang if (unit->access_type >= UNCORE_ACCESS_MAX) { 96edae1f06SKan Liang pr_warn("Unsupported access type %d\n", unit->access_type); 97edae1f06SKan Liang return NULL; 98edae1f06SKan Liang } 99edae1f06SKan Liang 100edae1f06SKan Liang type = kzalloc(sizeof(struct intel_uncore_discovery_type), GFP_KERNEL); 101edae1f06SKan Liang if (!type) 102edae1f06SKan Liang return NULL; 103edae1f06SKan Liang 104edae1f06SKan Liang type->box_ctrl_die = kcalloc(__uncore_max_dies, sizeof(u64), GFP_KERNEL); 105edae1f06SKan Liang if (!type->box_ctrl_die) 106edae1f06SKan Liang goto free_type; 107edae1f06SKan Liang 108edae1f06SKan Liang type->access_type = unit->access_type; 109edae1f06SKan Liang num_discovered_types[type->access_type]++; 110edae1f06SKan Liang type->type = unit->box_type; 111edae1f06SKan Liang 112edae1f06SKan Liang rb_add(&type->node, &discovery_tables, __type_less); 113edae1f06SKan Liang 114edae1f06SKan Liang return type; 115edae1f06SKan Liang 116edae1f06SKan Liang free_type: 117edae1f06SKan Liang kfree(type); 118edae1f06SKan Liang 119edae1f06SKan Liang return NULL; 120edae1f06SKan Liang 121edae1f06SKan Liang } 122edae1f06SKan Liang 123edae1f06SKan Liang static struct intel_uncore_discovery_type * 124edae1f06SKan Liang get_uncore_discovery_type(struct uncore_unit_discovery *unit) 125edae1f06SKan Liang { 126edae1f06SKan Liang struct intel_uncore_discovery_type *type; 127edae1f06SKan Liang 128edae1f06SKan Liang type = search_uncore_discovery_type(unit->box_type); 129edae1f06SKan Liang if (type) 130edae1f06SKan Liang return type; 131edae1f06SKan Liang 132edae1f06SKan Liang return add_uncore_discovery_type(unit); 133edae1f06SKan Liang } 134edae1f06SKan Liang 135edae1f06SKan Liang static void 136edae1f06SKan Liang uncore_insert_box_info(struct uncore_unit_discovery *unit, 137edae1f06SKan Liang int die, bool parsed) 138edae1f06SKan Liang { 139edae1f06SKan Liang struct intel_uncore_discovery_type *type; 140edae1f06SKan Liang unsigned int *box_offset, *ids; 141edae1f06SKan Liang int i; 142edae1f06SKan Liang 143edae1f06SKan Liang if (WARN_ON_ONCE(!unit->ctl || !unit->ctl_offset || !unit->ctr_offset)) 144edae1f06SKan Liang return; 145edae1f06SKan Liang 146edae1f06SKan Liang if (parsed) { 147edae1f06SKan Liang type = search_uncore_discovery_type(unit->box_type); 148edae1f06SKan Liang if (WARN_ON_ONCE(!type)) 149edae1f06SKan Liang return; 150edae1f06SKan Liang /* Store the first box of each die */ 151edae1f06SKan Liang if (!type->box_ctrl_die[die]) 152edae1f06SKan Liang type->box_ctrl_die[die] = unit->ctl; 153edae1f06SKan Liang return; 154edae1f06SKan Liang } 155edae1f06SKan Liang 156edae1f06SKan Liang type = get_uncore_discovery_type(unit); 157edae1f06SKan Liang if (!type) 158edae1f06SKan Liang return; 159edae1f06SKan Liang 160edae1f06SKan Liang box_offset = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL); 161edae1f06SKan Liang if (!box_offset) 162edae1f06SKan Liang return; 163edae1f06SKan Liang 164edae1f06SKan Liang ids = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL); 165edae1f06SKan Liang if (!ids) 166edae1f06SKan Liang goto free_box_offset; 167edae1f06SKan Liang 168edae1f06SKan Liang /* Store generic information for the first box */ 169edae1f06SKan Liang if (!type->num_boxes) { 170edae1f06SKan Liang type->box_ctrl = unit->ctl; 171edae1f06SKan Liang type->box_ctrl_die[die] = unit->ctl; 172edae1f06SKan Liang type->num_counters = unit->num_regs; 173edae1f06SKan Liang type->counter_width = unit->bit_width; 174edae1f06SKan Liang type->ctl_offset = unit->ctl_offset; 175edae1f06SKan Liang type->ctr_offset = unit->ctr_offset; 176edae1f06SKan Liang *ids = unit->box_id; 177edae1f06SKan Liang goto end; 178edae1f06SKan Liang } 179edae1f06SKan Liang 180edae1f06SKan Liang for (i = 0; i < type->num_boxes; i++) { 181edae1f06SKan Liang ids[i] = type->ids[i]; 182edae1f06SKan Liang box_offset[i] = type->box_offset[i]; 183edae1f06SKan Liang 184edae1f06SKan Liang if (WARN_ON_ONCE(unit->box_id == ids[i])) 185edae1f06SKan Liang goto free_ids; 186edae1f06SKan Liang } 187edae1f06SKan Liang ids[i] = unit->box_id; 188edae1f06SKan Liang box_offset[i] = unit->ctl - type->box_ctrl; 189edae1f06SKan Liang kfree(type->ids); 190edae1f06SKan Liang kfree(type->box_offset); 191edae1f06SKan Liang end: 192edae1f06SKan Liang type->ids = ids; 193edae1f06SKan Liang type->box_offset = box_offset; 194edae1f06SKan Liang type->num_boxes++; 195edae1f06SKan Liang return; 196edae1f06SKan Liang 197edae1f06SKan Liang free_ids: 198edae1f06SKan Liang kfree(ids); 199edae1f06SKan Liang 200edae1f06SKan Liang free_box_offset: 201edae1f06SKan Liang kfree(box_offset); 202edae1f06SKan Liang 203edae1f06SKan Liang } 204edae1f06SKan Liang 205edae1f06SKan Liang static int parse_discovery_table(struct pci_dev *dev, int die, 206edae1f06SKan Liang u32 bar_offset, bool *parsed) 207edae1f06SKan Liang { 208edae1f06SKan Liang struct uncore_global_discovery global; 209edae1f06SKan Liang struct uncore_unit_discovery unit; 210edae1f06SKan Liang void __iomem *io_addr; 211edae1f06SKan Liang resource_size_t addr; 212edae1f06SKan Liang unsigned long size; 213edae1f06SKan Liang u32 val; 214edae1f06SKan Liang int i; 215edae1f06SKan Liang 216edae1f06SKan Liang pci_read_config_dword(dev, bar_offset, &val); 217edae1f06SKan Liang 218edae1f06SKan Liang if (val & UNCORE_DISCOVERY_MASK) 219edae1f06SKan Liang return -EINVAL; 220edae1f06SKan Liang 221edae1f06SKan Liang addr = (resource_size_t)(val & ~UNCORE_DISCOVERY_MASK); 222edae1f06SKan Liang size = UNCORE_DISCOVERY_GLOBAL_MAP_SIZE; 223edae1f06SKan Liang io_addr = ioremap(addr, size); 224edae1f06SKan Liang if (!io_addr) 225edae1f06SKan Liang return -ENOMEM; 226edae1f06SKan Liang 227edae1f06SKan Liang /* Read Global Discovery State */ 228edae1f06SKan Liang memcpy_fromio(&global, io_addr, sizeof(struct uncore_global_discovery)); 229edae1f06SKan Liang if (uncore_discovery_invalid_unit(global)) { 230edae1f06SKan Liang pr_info("Invalid Global Discovery State: 0x%llx 0x%llx 0x%llx\n", 231edae1f06SKan Liang global.table1, global.ctl, global.table3); 232edae1f06SKan Liang iounmap(io_addr); 233edae1f06SKan Liang return -EINVAL; 234edae1f06SKan Liang } 235edae1f06SKan Liang iounmap(io_addr); 236edae1f06SKan Liang 237edae1f06SKan Liang size = (1 + global.max_units) * global.stride * 8; 238edae1f06SKan Liang io_addr = ioremap(addr, size); 239edae1f06SKan Liang if (!io_addr) 240edae1f06SKan Liang return -ENOMEM; 241edae1f06SKan Liang 242edae1f06SKan Liang /* Parsing Unit Discovery State */ 243edae1f06SKan Liang for (i = 0; i < global.max_units; i++) { 244edae1f06SKan Liang memcpy_fromio(&unit, io_addr + (i + 1) * (global.stride * 8), 245edae1f06SKan Liang sizeof(struct uncore_unit_discovery)); 246edae1f06SKan Liang 247edae1f06SKan Liang if (uncore_discovery_invalid_unit(unit)) 248edae1f06SKan Liang continue; 249edae1f06SKan Liang 250edae1f06SKan Liang if (unit.access_type >= UNCORE_ACCESS_MAX) 251edae1f06SKan Liang continue; 252edae1f06SKan Liang 253edae1f06SKan Liang uncore_insert_box_info(&unit, die, *parsed); 254edae1f06SKan Liang } 255edae1f06SKan Liang 256edae1f06SKan Liang *parsed = true; 257edae1f06SKan Liang iounmap(io_addr); 258edae1f06SKan Liang return 0; 259edae1f06SKan Liang } 260edae1f06SKan Liang 261edae1f06SKan Liang bool intel_uncore_has_discovery_tables(void) 262edae1f06SKan Liang { 263edae1f06SKan Liang u32 device, val, entry_id, bar_offset; 264edae1f06SKan Liang int die, dvsec = 0, ret = true; 265edae1f06SKan Liang struct pci_dev *dev = NULL; 266edae1f06SKan Liang bool parsed = false; 267edae1f06SKan Liang 268edae1f06SKan Liang if (has_generic_discovery_table()) 269edae1f06SKan Liang device = UNCORE_DISCOVERY_TABLE_DEVICE; 270edae1f06SKan Liang else 271edae1f06SKan Liang device = PCI_ANY_ID; 272edae1f06SKan Liang 273edae1f06SKan Liang /* 274edae1f06SKan Liang * Start a new search and iterates through the list of 275edae1f06SKan Liang * the discovery table devices. 276edae1f06SKan Liang */ 277edae1f06SKan Liang while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, dev)) != NULL) { 278edae1f06SKan Liang while ((dvsec = pci_find_next_ext_capability(dev, dvsec, UNCORE_EXT_CAP_ID_DISCOVERY))) { 279edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC_OFFSET, &val); 280edae1f06SKan Liang entry_id = val & UNCORE_DISCOVERY_DVSEC_ID_MASK; 281edae1f06SKan Liang if (entry_id != UNCORE_DISCOVERY_DVSEC_ID_PMON) 282edae1f06SKan Liang continue; 283edae1f06SKan Liang 284edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC2_OFFSET, &val); 285edae1f06SKan Liang 286edae1f06SKan Liang if (val & ~UNCORE_DISCOVERY_DVSEC2_BIR_MASK) { 287edae1f06SKan Liang ret = false; 288edae1f06SKan Liang goto err; 289edae1f06SKan Liang } 290edae1f06SKan Liang bar_offset = UNCORE_DISCOVERY_BIR_BASE + 291edae1f06SKan Liang (val & UNCORE_DISCOVERY_DVSEC2_BIR_MASK) * UNCORE_DISCOVERY_BIR_STEP; 292edae1f06SKan Liang 293edae1f06SKan Liang die = get_device_die_id(dev); 294edae1f06SKan Liang if (die < 0) 295edae1f06SKan Liang continue; 296edae1f06SKan Liang 297edae1f06SKan Liang parse_discovery_table(dev, die, bar_offset, &parsed); 298edae1f06SKan Liang } 299edae1f06SKan Liang } 300edae1f06SKan Liang 301edae1f06SKan Liang /* None of the discovery tables are available */ 302edae1f06SKan Liang if (!parsed) 303edae1f06SKan Liang ret = false; 304edae1f06SKan Liang err: 305edae1f06SKan Liang pci_dev_put(dev); 306edae1f06SKan Liang 307edae1f06SKan Liang return ret; 308edae1f06SKan Liang } 309edae1f06SKan Liang 310edae1f06SKan Liang void intel_uncore_clear_discovery_tables(void) 311edae1f06SKan Liang { 312edae1f06SKan Liang struct intel_uncore_discovery_type *type, *next; 313edae1f06SKan Liang 314edae1f06SKan Liang rbtree_postorder_for_each_entry_safe(type, next, &discovery_tables, node) { 315edae1f06SKan Liang kfree(type->box_ctrl_die); 316edae1f06SKan Liang kfree(type); 317edae1f06SKan Liang } 318edae1f06SKan Liang } 319d6c75413SKan Liang 320d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); 321d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); 322d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); 323d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); 324d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(thresh, thresh, "config:24-31"); 325d6c75413SKan Liang 326d6c75413SKan Liang static struct attribute *generic_uncore_formats_attr[] = { 327d6c75413SKan Liang &format_attr_event.attr, 328d6c75413SKan Liang &format_attr_umask.attr, 329d6c75413SKan Liang &format_attr_edge.attr, 330d6c75413SKan Liang &format_attr_inv.attr, 331d6c75413SKan Liang &format_attr_thresh.attr, 332d6c75413SKan Liang NULL, 333d6c75413SKan Liang }; 334d6c75413SKan Liang 335d6c75413SKan Liang static const struct attribute_group generic_uncore_format_group = { 336d6c75413SKan Liang .name = "format", 337d6c75413SKan Liang .attrs = generic_uncore_formats_attr, 338d6c75413SKan Liang }; 339d6c75413SKan Liang 340d6c75413SKan Liang static void intel_generic_uncore_msr_init_box(struct intel_uncore_box *box) 341d6c75413SKan Liang { 342d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_INT); 343d6c75413SKan Liang } 344d6c75413SKan Liang 345d6c75413SKan Liang static void intel_generic_uncore_msr_disable_box(struct intel_uncore_box *box) 346d6c75413SKan Liang { 347d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_FRZ); 348d6c75413SKan Liang } 349d6c75413SKan Liang 350d6c75413SKan Liang static void intel_generic_uncore_msr_enable_box(struct intel_uncore_box *box) 351d6c75413SKan Liang { 352d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), 0); 353d6c75413SKan Liang } 354d6c75413SKan Liang 355d6c75413SKan Liang static void intel_generic_uncore_msr_enable_event(struct intel_uncore_box *box, 356d6c75413SKan Liang struct perf_event *event) 357d6c75413SKan Liang { 358d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 359d6c75413SKan Liang 360d6c75413SKan Liang wrmsrl(hwc->config_base, hwc->config); 361d6c75413SKan Liang } 362d6c75413SKan Liang 363d6c75413SKan Liang static void intel_generic_uncore_msr_disable_event(struct intel_uncore_box *box, 364d6c75413SKan Liang struct perf_event *event) 365d6c75413SKan Liang { 366d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 367d6c75413SKan Liang 368d6c75413SKan Liang wrmsrl(hwc->config_base, 0); 369d6c75413SKan Liang } 370d6c75413SKan Liang 371d6c75413SKan Liang static struct intel_uncore_ops generic_uncore_msr_ops = { 372d6c75413SKan Liang .init_box = intel_generic_uncore_msr_init_box, 373d6c75413SKan Liang .disable_box = intel_generic_uncore_msr_disable_box, 374d6c75413SKan Liang .enable_box = intel_generic_uncore_msr_enable_box, 375d6c75413SKan Liang .disable_event = intel_generic_uncore_msr_disable_event, 376d6c75413SKan Liang .enable_event = intel_generic_uncore_msr_enable_event, 377d6c75413SKan Liang .read_counter = uncore_msr_read_counter, 378d6c75413SKan Liang }; 379d6c75413SKan Liang 380*42839ef4SKan Liang static void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box) 381*42839ef4SKan Liang { 382*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 383*42839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 384*42839ef4SKan Liang 385*42839ef4SKan Liang __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags); 386*42839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT); 387*42839ef4SKan Liang } 388*42839ef4SKan Liang 389*42839ef4SKan Liang static void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box) 390*42839ef4SKan Liang { 391*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 392*42839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 393*42839ef4SKan Liang 394*42839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ); 395*42839ef4SKan Liang } 396*42839ef4SKan Liang 397*42839ef4SKan Liang static void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box) 398*42839ef4SKan Liang { 399*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 400*42839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 401*42839ef4SKan Liang 402*42839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, 0); 403*42839ef4SKan Liang } 404*42839ef4SKan Liang 405*42839ef4SKan Liang static void intel_generic_uncore_pci_enable_event(struct intel_uncore_box *box, 406*42839ef4SKan Liang struct perf_event *event) 407*42839ef4SKan Liang { 408*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 409*42839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 410*42839ef4SKan Liang 411*42839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, hwc->config); 412*42839ef4SKan Liang } 413*42839ef4SKan Liang 414*42839ef4SKan Liang static void intel_generic_uncore_pci_disable_event(struct intel_uncore_box *box, 415*42839ef4SKan Liang struct perf_event *event) 416*42839ef4SKan Liang { 417*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 418*42839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 419*42839ef4SKan Liang 420*42839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, 0); 421*42839ef4SKan Liang } 422*42839ef4SKan Liang 423*42839ef4SKan Liang static u64 intel_generic_uncore_pci_read_counter(struct intel_uncore_box *box, 424*42839ef4SKan Liang struct perf_event *event) 425*42839ef4SKan Liang { 426*42839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 427*42839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 428*42839ef4SKan Liang u64 count = 0; 429*42839ef4SKan Liang 430*42839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); 431*42839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); 432*42839ef4SKan Liang 433*42839ef4SKan Liang return count; 434*42839ef4SKan Liang } 435*42839ef4SKan Liang 436*42839ef4SKan Liang static struct intel_uncore_ops generic_uncore_pci_ops = { 437*42839ef4SKan Liang .init_box = intel_generic_uncore_pci_init_box, 438*42839ef4SKan Liang .disable_box = intel_generic_uncore_pci_disable_box, 439*42839ef4SKan Liang .enable_box = intel_generic_uncore_pci_enable_box, 440*42839ef4SKan Liang .disable_event = intel_generic_uncore_pci_disable_event, 441*42839ef4SKan Liang .enable_event = intel_generic_uncore_pci_enable_event, 442*42839ef4SKan Liang .read_counter = intel_generic_uncore_pci_read_counter, 443*42839ef4SKan Liang }; 444*42839ef4SKan Liang 445d6c75413SKan Liang static bool uncore_update_uncore_type(enum uncore_access_type type_id, 446d6c75413SKan Liang struct intel_uncore_type *uncore, 447d6c75413SKan Liang struct intel_uncore_discovery_type *type) 448d6c75413SKan Liang { 449d6c75413SKan Liang uncore->type_id = type->type; 450d6c75413SKan Liang uncore->num_boxes = type->num_boxes; 451d6c75413SKan Liang uncore->num_counters = type->num_counters; 452d6c75413SKan Liang uncore->perf_ctr_bits = type->counter_width; 453d6c75413SKan Liang uncore->box_ids = type->ids; 454d6c75413SKan Liang 455d6c75413SKan Liang switch (type_id) { 456d6c75413SKan Liang case UNCORE_ACCESS_MSR: 457d6c75413SKan Liang uncore->ops = &generic_uncore_msr_ops; 458d6c75413SKan Liang uncore->perf_ctr = (unsigned int)type->box_ctrl + type->ctr_offset; 459d6c75413SKan Liang uncore->event_ctl = (unsigned int)type->box_ctrl + type->ctl_offset; 460d6c75413SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 461d6c75413SKan Liang uncore->msr_offsets = type->box_offset; 462d6c75413SKan Liang break; 463*42839ef4SKan Liang case UNCORE_ACCESS_PCI: 464*42839ef4SKan Liang uncore->ops = &generic_uncore_pci_ops; 465*42839ef4SKan Liang uncore->perf_ctr = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctr_offset; 466*42839ef4SKan Liang uncore->event_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctl_offset; 467*42839ef4SKan Liang uncore->box_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl); 468*42839ef4SKan Liang uncore->box_ctls = type->box_ctrl_die; 469*42839ef4SKan Liang uncore->pci_offsets = type->box_offset; 470*42839ef4SKan Liang break; 471d6c75413SKan Liang default: 472d6c75413SKan Liang return false; 473d6c75413SKan Liang } 474d6c75413SKan Liang 475d6c75413SKan Liang return true; 476d6c75413SKan Liang } 477d6c75413SKan Liang 478d6c75413SKan Liang static struct intel_uncore_type ** 479d6c75413SKan Liang intel_uncore_generic_init_uncores(enum uncore_access_type type_id) 480d6c75413SKan Liang { 481d6c75413SKan Liang struct intel_uncore_discovery_type *type; 482d6c75413SKan Liang struct intel_uncore_type **uncores; 483d6c75413SKan Liang struct intel_uncore_type *uncore; 484d6c75413SKan Liang struct rb_node *node; 485d6c75413SKan Liang int i = 0; 486d6c75413SKan Liang 487d6c75413SKan Liang uncores = kcalloc(num_discovered_types[type_id] + 1, 488d6c75413SKan Liang sizeof(struct intel_uncore_type *), GFP_KERNEL); 489d6c75413SKan Liang if (!uncores) 490d6c75413SKan Liang return empty_uncore; 491d6c75413SKan Liang 492d6c75413SKan Liang for (node = rb_first(&discovery_tables); node; node = rb_next(node)) { 493d6c75413SKan Liang type = rb_entry(node, struct intel_uncore_discovery_type, node); 494d6c75413SKan Liang if (type->access_type != type_id) 495d6c75413SKan Liang continue; 496d6c75413SKan Liang 497d6c75413SKan Liang uncore = kzalloc(sizeof(struct intel_uncore_type), GFP_KERNEL); 498d6c75413SKan Liang if (!uncore) 499d6c75413SKan Liang break; 500d6c75413SKan Liang 501d6c75413SKan Liang uncore->event_mask = GENERIC_PMON_RAW_EVENT_MASK; 502d6c75413SKan Liang uncore->format_group = &generic_uncore_format_group; 503d6c75413SKan Liang 504d6c75413SKan Liang if (!uncore_update_uncore_type(type_id, uncore, type)) { 505d6c75413SKan Liang kfree(uncore); 506d6c75413SKan Liang continue; 507d6c75413SKan Liang } 508d6c75413SKan Liang uncores[i++] = uncore; 509d6c75413SKan Liang } 510d6c75413SKan Liang 511d6c75413SKan Liang return uncores; 512d6c75413SKan Liang } 513d6c75413SKan Liang 514d6c75413SKan Liang void intel_uncore_generic_uncore_cpu_init(void) 515d6c75413SKan Liang { 516d6c75413SKan Liang uncore_msr_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MSR); 517d6c75413SKan Liang } 518*42839ef4SKan Liang 519*42839ef4SKan Liang int intel_uncore_generic_uncore_pci_init(void) 520*42839ef4SKan Liang { 521*42839ef4SKan Liang uncore_pci_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_PCI); 522*42839ef4SKan Liang 523*42839ef4SKan Liang return 0; 524*42839ef4SKan Liang } 525