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 340949b1138SKan Liang 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 345949b1138SKan Liang 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 350949b1138SKan Liang 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 380f57191edSKan Liang void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box) 38142839ef4SKan Liang { 38242839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 38342839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 38442839ef4SKan Liang 38542839ef4SKan Liang __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags); 38642839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT); 38742839ef4SKan Liang } 38842839ef4SKan Liang 389f57191edSKan Liang void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box) 39042839ef4SKan Liang { 39142839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 39242839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 39342839ef4SKan Liang 39442839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ); 39542839ef4SKan Liang } 39642839ef4SKan Liang 397f57191edSKan Liang void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box) 39842839ef4SKan Liang { 39942839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 40042839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 40142839ef4SKan Liang 40242839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, 0); 40342839ef4SKan Liang } 40442839ef4SKan Liang 40542839ef4SKan Liang static void intel_generic_uncore_pci_enable_event(struct intel_uncore_box *box, 40642839ef4SKan Liang struct perf_event *event) 40742839ef4SKan Liang { 40842839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 40942839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 41042839ef4SKan Liang 41142839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, hwc->config); 41242839ef4SKan Liang } 41342839ef4SKan Liang 414f57191edSKan Liang void intel_generic_uncore_pci_disable_event(struct intel_uncore_box *box, 41542839ef4SKan Liang struct perf_event *event) 41642839ef4SKan Liang { 41742839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 41842839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 41942839ef4SKan Liang 42042839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, 0); 42142839ef4SKan Liang } 42242839ef4SKan Liang 423f57191edSKan Liang u64 intel_generic_uncore_pci_read_counter(struct intel_uncore_box *box, 42442839ef4SKan Liang struct perf_event *event) 42542839ef4SKan Liang { 42642839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 42742839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 42842839ef4SKan Liang u64 count = 0; 42942839ef4SKan Liang 43042839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); 43142839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); 43242839ef4SKan Liang 43342839ef4SKan Liang return count; 43442839ef4SKan Liang } 43542839ef4SKan Liang 43642839ef4SKan Liang static struct intel_uncore_ops generic_uncore_pci_ops = { 43742839ef4SKan Liang .init_box = intel_generic_uncore_pci_init_box, 43842839ef4SKan Liang .disable_box = intel_generic_uncore_pci_disable_box, 43942839ef4SKan Liang .enable_box = intel_generic_uncore_pci_enable_box, 44042839ef4SKan Liang .disable_event = intel_generic_uncore_pci_disable_event, 44142839ef4SKan Liang .enable_event = intel_generic_uncore_pci_enable_event, 44242839ef4SKan Liang .read_counter = intel_generic_uncore_pci_read_counter, 44342839ef4SKan Liang }; 44442839ef4SKan Liang 445c4c55e36SKan Liang #define UNCORE_GENERIC_MMIO_SIZE 0x4000 446c4c55e36SKan Liang 447c4c55e36SKan Liang static unsigned int generic_uncore_mmio_box_ctl(struct intel_uncore_box *box) 448c4c55e36SKan Liang { 449c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 450c4c55e36SKan Liang 451c4c55e36SKan Liang if (!type->box_ctls || !type->box_ctls[box->dieid] || !type->mmio_offsets) 452c4c55e36SKan Liang return 0; 453c4c55e36SKan Liang 454c4c55e36SKan Liang return type->box_ctls[box->dieid] + type->mmio_offsets[box->pmu->pmu_idx]; 455c4c55e36SKan Liang } 456c4c55e36SKan Liang 45785f2e30fSKan Liang void intel_generic_uncore_mmio_init_box(struct intel_uncore_box *box) 458c4c55e36SKan Liang { 459c4c55e36SKan Liang unsigned int box_ctl = generic_uncore_mmio_box_ctl(box); 460c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 461c4c55e36SKan Liang resource_size_t addr; 462c4c55e36SKan Liang 463c4c55e36SKan Liang if (!box_ctl) { 464c4c55e36SKan Liang pr_warn("Uncore type %d box %d: Invalid box control address.\n", 465c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx]); 466c4c55e36SKan Liang return; 467c4c55e36SKan Liang } 468c4c55e36SKan Liang 469c4c55e36SKan Liang addr = box_ctl; 470c4c55e36SKan Liang box->io_addr = ioremap(addr, UNCORE_GENERIC_MMIO_SIZE); 471c4c55e36SKan Liang if (!box->io_addr) { 472c4c55e36SKan Liang pr_warn("Uncore type %d box %d: ioremap error for 0x%llx.\n", 473c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx], 474c4c55e36SKan Liang (unsigned long long)addr); 475c4c55e36SKan Liang return; 476c4c55e36SKan Liang } 477c4c55e36SKan Liang 478c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_INT, box->io_addr); 479c4c55e36SKan Liang } 480c4c55e36SKan Liang 48185f2e30fSKan Liang void intel_generic_uncore_mmio_disable_box(struct intel_uncore_box *box) 482c4c55e36SKan Liang { 483c4c55e36SKan Liang if (!box->io_addr) 484c4c55e36SKan Liang return; 485c4c55e36SKan Liang 486c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_FRZ, box->io_addr); 487c4c55e36SKan Liang } 488c4c55e36SKan Liang 48985f2e30fSKan Liang void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box) 490c4c55e36SKan Liang { 491c4c55e36SKan Liang if (!box->io_addr) 492c4c55e36SKan Liang return; 493c4c55e36SKan Liang 494c4c55e36SKan Liang writel(0, box->io_addr); 495c4c55e36SKan Liang } 496c4c55e36SKan Liang 497*5a4487f9SKan Liang void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box, 498c4c55e36SKan Liang struct perf_event *event) 499c4c55e36SKan Liang { 500c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 501c4c55e36SKan Liang 502c4c55e36SKan Liang if (!box->io_addr) 503c4c55e36SKan Liang return; 504c4c55e36SKan Liang 505c4c55e36SKan Liang writel(hwc->config, box->io_addr + hwc->config_base); 506c4c55e36SKan Liang } 507c4c55e36SKan Liang 50885f2e30fSKan Liang void intel_generic_uncore_mmio_disable_event(struct intel_uncore_box *box, 509c4c55e36SKan Liang struct perf_event *event) 510c4c55e36SKan Liang { 511c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 512c4c55e36SKan Liang 513c4c55e36SKan Liang if (!box->io_addr) 514c4c55e36SKan Liang return; 515c4c55e36SKan Liang 516c4c55e36SKan Liang writel(0, box->io_addr + hwc->config_base); 517c4c55e36SKan Liang } 518c4c55e36SKan Liang 519c4c55e36SKan Liang static struct intel_uncore_ops generic_uncore_mmio_ops = { 520c4c55e36SKan Liang .init_box = intel_generic_uncore_mmio_init_box, 521c4c55e36SKan Liang .exit_box = uncore_mmio_exit_box, 522c4c55e36SKan Liang .disable_box = intel_generic_uncore_mmio_disable_box, 523c4c55e36SKan Liang .enable_box = intel_generic_uncore_mmio_enable_box, 524c4c55e36SKan Liang .disable_event = intel_generic_uncore_mmio_disable_event, 525c4c55e36SKan Liang .enable_event = intel_generic_uncore_mmio_enable_event, 526c4c55e36SKan Liang .read_counter = uncore_mmio_read_counter, 527c4c55e36SKan Liang }; 528c4c55e36SKan Liang 529d6c75413SKan Liang static bool uncore_update_uncore_type(enum uncore_access_type type_id, 530d6c75413SKan Liang struct intel_uncore_type *uncore, 531d6c75413SKan Liang struct intel_uncore_discovery_type *type) 532d6c75413SKan Liang { 533d6c75413SKan Liang uncore->type_id = type->type; 534d6c75413SKan Liang uncore->num_boxes = type->num_boxes; 535d6c75413SKan Liang uncore->num_counters = type->num_counters; 536d6c75413SKan Liang uncore->perf_ctr_bits = type->counter_width; 537d6c75413SKan Liang uncore->box_ids = type->ids; 538d6c75413SKan Liang 539d6c75413SKan Liang switch (type_id) { 540d6c75413SKan Liang case UNCORE_ACCESS_MSR: 541d6c75413SKan Liang uncore->ops = &generic_uncore_msr_ops; 542d6c75413SKan Liang uncore->perf_ctr = (unsigned int)type->box_ctrl + type->ctr_offset; 543d6c75413SKan Liang uncore->event_ctl = (unsigned int)type->box_ctrl + type->ctl_offset; 544d6c75413SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 545d6c75413SKan Liang uncore->msr_offsets = type->box_offset; 546d6c75413SKan Liang break; 54742839ef4SKan Liang case UNCORE_ACCESS_PCI: 54842839ef4SKan Liang uncore->ops = &generic_uncore_pci_ops; 54942839ef4SKan Liang uncore->perf_ctr = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctr_offset; 55042839ef4SKan Liang uncore->event_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctl_offset; 55142839ef4SKan Liang uncore->box_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl); 55242839ef4SKan Liang uncore->box_ctls = type->box_ctrl_die; 55342839ef4SKan Liang uncore->pci_offsets = type->box_offset; 55442839ef4SKan Liang break; 555c4c55e36SKan Liang case UNCORE_ACCESS_MMIO: 556c4c55e36SKan Liang uncore->ops = &generic_uncore_mmio_ops; 557c4c55e36SKan Liang uncore->perf_ctr = (unsigned int)type->ctr_offset; 558c4c55e36SKan Liang uncore->event_ctl = (unsigned int)type->ctl_offset; 559c4c55e36SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 560c4c55e36SKan Liang uncore->box_ctls = type->box_ctrl_die; 561c4c55e36SKan Liang uncore->mmio_offsets = type->box_offset; 562c4c55e36SKan Liang uncore->mmio_map_size = UNCORE_GENERIC_MMIO_SIZE; 563c4c55e36SKan Liang break; 564d6c75413SKan Liang default: 565d6c75413SKan Liang return false; 566d6c75413SKan Liang } 567d6c75413SKan Liang 568d6c75413SKan Liang return true; 569d6c75413SKan Liang } 570d6c75413SKan Liang 571c54c53d9SKan Liang struct intel_uncore_type ** 5720378c93aSKan Liang intel_uncore_generic_init_uncores(enum uncore_access_type type_id, int num_extra) 573d6c75413SKan Liang { 574d6c75413SKan Liang struct intel_uncore_discovery_type *type; 575d6c75413SKan Liang struct intel_uncore_type **uncores; 576d6c75413SKan Liang struct intel_uncore_type *uncore; 577d6c75413SKan Liang struct rb_node *node; 578d6c75413SKan Liang int i = 0; 579d6c75413SKan Liang 5800378c93aSKan Liang uncores = kcalloc(num_discovered_types[type_id] + num_extra + 1, 581d6c75413SKan Liang sizeof(struct intel_uncore_type *), GFP_KERNEL); 582d6c75413SKan Liang if (!uncores) 583d6c75413SKan Liang return empty_uncore; 584d6c75413SKan Liang 585d6c75413SKan Liang for (node = rb_first(&discovery_tables); node; node = rb_next(node)) { 586d6c75413SKan Liang type = rb_entry(node, struct intel_uncore_discovery_type, node); 587d6c75413SKan Liang if (type->access_type != type_id) 588d6c75413SKan Liang continue; 589d6c75413SKan Liang 590d6c75413SKan Liang uncore = kzalloc(sizeof(struct intel_uncore_type), GFP_KERNEL); 591d6c75413SKan Liang if (!uncore) 592d6c75413SKan Liang break; 593d6c75413SKan Liang 594d6c75413SKan Liang uncore->event_mask = GENERIC_PMON_RAW_EVENT_MASK; 595d6c75413SKan Liang uncore->format_group = &generic_uncore_format_group; 596d6c75413SKan Liang 597d6c75413SKan Liang if (!uncore_update_uncore_type(type_id, uncore, type)) { 598d6c75413SKan Liang kfree(uncore); 599d6c75413SKan Liang continue; 600d6c75413SKan Liang } 601d6c75413SKan Liang uncores[i++] = uncore; 602d6c75413SKan Liang } 603d6c75413SKan Liang 604d6c75413SKan Liang return uncores; 605d6c75413SKan Liang } 606d6c75413SKan Liang 607d6c75413SKan Liang void intel_uncore_generic_uncore_cpu_init(void) 608d6c75413SKan Liang { 6090378c93aSKan Liang uncore_msr_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MSR, 0); 610d6c75413SKan Liang } 61142839ef4SKan Liang 61242839ef4SKan Liang int intel_uncore_generic_uncore_pci_init(void) 61342839ef4SKan Liang { 6140378c93aSKan Liang uncore_pci_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_PCI, 0); 61542839ef4SKan Liang 61642839ef4SKan Liang return 0; 61742839ef4SKan Liang } 618c4c55e36SKan Liang 619c4c55e36SKan Liang void intel_uncore_generic_uncore_mmio_init(void) 620c4c55e36SKan Liang { 6210378c93aSKan Liang uncore_mmio_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MMIO, 0); 622c4c55e36SKan Liang } 623