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 { 36dbf061b2SKan Liang int 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 46dbf061b2SKan Liang return uncore_device_to_die(dev); 47edae1f06SKan Liang } 48edae1f06SKan Liang 49edae1f06SKan Liang #define __node_2_type(cur) \ 50edae1f06SKan Liang rb_entry((cur), struct intel_uncore_discovery_type, node) 51edae1f06SKan Liang 52edae1f06SKan Liang static inline int __type_cmp(const void *key, const struct rb_node *b) 53edae1f06SKan Liang { 54edae1f06SKan Liang struct intel_uncore_discovery_type *type_b = __node_2_type(b); 55edae1f06SKan Liang const u16 *type_id = key; 56edae1f06SKan Liang 57edae1f06SKan Liang if (type_b->type > *type_id) 58edae1f06SKan Liang return -1; 59edae1f06SKan Liang else if (type_b->type < *type_id) 60edae1f06SKan Liang return 1; 61edae1f06SKan Liang 62edae1f06SKan Liang return 0; 63edae1f06SKan Liang } 64edae1f06SKan Liang 65edae1f06SKan Liang static inline struct intel_uncore_discovery_type * 66edae1f06SKan Liang search_uncore_discovery_type(u16 type_id) 67edae1f06SKan Liang { 68edae1f06SKan Liang struct rb_node *node = rb_find(&type_id, &discovery_tables, __type_cmp); 69edae1f06SKan Liang 70edae1f06SKan Liang return (node) ? __node_2_type(node) : NULL; 71edae1f06SKan Liang } 72edae1f06SKan Liang 73edae1f06SKan Liang static inline bool __type_less(struct rb_node *a, const struct rb_node *b) 74edae1f06SKan Liang { 75edae1f06SKan Liang return (__node_2_type(a)->type < __node_2_type(b)->type); 76edae1f06SKan Liang } 77edae1f06SKan Liang 78edae1f06SKan Liang static struct intel_uncore_discovery_type * 79edae1f06SKan Liang add_uncore_discovery_type(struct uncore_unit_discovery *unit) 80edae1f06SKan Liang { 81edae1f06SKan Liang struct intel_uncore_discovery_type *type; 82edae1f06SKan Liang 83edae1f06SKan Liang if (unit->access_type >= UNCORE_ACCESS_MAX) { 84edae1f06SKan Liang pr_warn("Unsupported access type %d\n", unit->access_type); 85edae1f06SKan Liang return NULL; 86edae1f06SKan Liang } 87edae1f06SKan Liang 88edae1f06SKan Liang type = kzalloc(sizeof(struct intel_uncore_discovery_type), GFP_KERNEL); 89edae1f06SKan Liang if (!type) 90edae1f06SKan Liang return NULL; 91edae1f06SKan Liang 92edae1f06SKan Liang type->box_ctrl_die = kcalloc(__uncore_max_dies, sizeof(u64), GFP_KERNEL); 93edae1f06SKan Liang if (!type->box_ctrl_die) 94edae1f06SKan Liang goto free_type; 95edae1f06SKan Liang 96edae1f06SKan Liang type->access_type = unit->access_type; 97edae1f06SKan Liang num_discovered_types[type->access_type]++; 98edae1f06SKan Liang type->type = unit->box_type; 99edae1f06SKan Liang 100edae1f06SKan Liang rb_add(&type->node, &discovery_tables, __type_less); 101edae1f06SKan Liang 102edae1f06SKan Liang return type; 103edae1f06SKan Liang 104edae1f06SKan Liang free_type: 105edae1f06SKan Liang kfree(type); 106edae1f06SKan Liang 107edae1f06SKan Liang return NULL; 108edae1f06SKan Liang 109edae1f06SKan Liang } 110edae1f06SKan Liang 111edae1f06SKan Liang static struct intel_uncore_discovery_type * 112edae1f06SKan Liang get_uncore_discovery_type(struct uncore_unit_discovery *unit) 113edae1f06SKan Liang { 114edae1f06SKan Liang struct intel_uncore_discovery_type *type; 115edae1f06SKan Liang 116edae1f06SKan Liang type = search_uncore_discovery_type(unit->box_type); 117edae1f06SKan Liang if (type) 118edae1f06SKan Liang return type; 119edae1f06SKan Liang 120edae1f06SKan Liang return add_uncore_discovery_type(unit); 121edae1f06SKan Liang } 122edae1f06SKan Liang 123edae1f06SKan Liang static void 124edae1f06SKan Liang uncore_insert_box_info(struct uncore_unit_discovery *unit, 125edae1f06SKan Liang int die, bool parsed) 126edae1f06SKan Liang { 127edae1f06SKan Liang struct intel_uncore_discovery_type *type; 128edae1f06SKan Liang unsigned int *box_offset, *ids; 129edae1f06SKan Liang int i; 130edae1f06SKan Liang 131edae1f06SKan Liang if (WARN_ON_ONCE(!unit->ctl || !unit->ctl_offset || !unit->ctr_offset)) 132edae1f06SKan Liang return; 133edae1f06SKan Liang 134edae1f06SKan Liang if (parsed) { 135edae1f06SKan Liang type = search_uncore_discovery_type(unit->box_type); 136edae1f06SKan Liang if (WARN_ON_ONCE(!type)) 137edae1f06SKan Liang return; 138edae1f06SKan Liang /* Store the first box of each die */ 139edae1f06SKan Liang if (!type->box_ctrl_die[die]) 140edae1f06SKan Liang type->box_ctrl_die[die] = unit->ctl; 141edae1f06SKan Liang return; 142edae1f06SKan Liang } 143edae1f06SKan Liang 144edae1f06SKan Liang type = get_uncore_discovery_type(unit); 145edae1f06SKan Liang if (!type) 146edae1f06SKan Liang return; 147edae1f06SKan Liang 148edae1f06SKan Liang box_offset = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL); 149edae1f06SKan Liang if (!box_offset) 150edae1f06SKan Liang return; 151edae1f06SKan Liang 152edae1f06SKan Liang ids = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL); 153edae1f06SKan Liang if (!ids) 154edae1f06SKan Liang goto free_box_offset; 155edae1f06SKan Liang 156edae1f06SKan Liang /* Store generic information for the first box */ 157edae1f06SKan Liang if (!type->num_boxes) { 158edae1f06SKan Liang type->box_ctrl = unit->ctl; 159edae1f06SKan Liang type->box_ctrl_die[die] = unit->ctl; 160edae1f06SKan Liang type->num_counters = unit->num_regs; 161edae1f06SKan Liang type->counter_width = unit->bit_width; 162edae1f06SKan Liang type->ctl_offset = unit->ctl_offset; 163edae1f06SKan Liang type->ctr_offset = unit->ctr_offset; 164edae1f06SKan Liang *ids = unit->box_id; 165edae1f06SKan Liang goto end; 166edae1f06SKan Liang } 167edae1f06SKan Liang 168edae1f06SKan Liang for (i = 0; i < type->num_boxes; i++) { 169edae1f06SKan Liang ids[i] = type->ids[i]; 170edae1f06SKan Liang box_offset[i] = type->box_offset[i]; 171edae1f06SKan Liang 172edae1f06SKan Liang if (WARN_ON_ONCE(unit->box_id == ids[i])) 173edae1f06SKan Liang goto free_ids; 174edae1f06SKan Liang } 175edae1f06SKan Liang ids[i] = unit->box_id; 176edae1f06SKan Liang box_offset[i] = unit->ctl - type->box_ctrl; 177edae1f06SKan Liang kfree(type->ids); 178edae1f06SKan Liang kfree(type->box_offset); 179edae1f06SKan Liang end: 180edae1f06SKan Liang type->ids = ids; 181edae1f06SKan Liang type->box_offset = box_offset; 182edae1f06SKan Liang type->num_boxes++; 183edae1f06SKan Liang return; 184edae1f06SKan Liang 185edae1f06SKan Liang free_ids: 186edae1f06SKan Liang kfree(ids); 187edae1f06SKan Liang 188edae1f06SKan Liang free_box_offset: 189edae1f06SKan Liang kfree(box_offset); 190edae1f06SKan Liang 191edae1f06SKan Liang } 192edae1f06SKan Liang 193*bd9514a4SKan Liang static bool 194*bd9514a4SKan Liang uncore_ignore_unit(struct uncore_unit_discovery *unit, int *ignore) 195*bd9514a4SKan Liang { 196*bd9514a4SKan Liang int i; 197*bd9514a4SKan Liang 198*bd9514a4SKan Liang if (!ignore) 199*bd9514a4SKan Liang return false; 200*bd9514a4SKan Liang 201*bd9514a4SKan Liang for (i = 0; ignore[i] != UNCORE_IGNORE_END ; i++) { 202*bd9514a4SKan Liang if (unit->box_type == ignore[i]) 203*bd9514a4SKan Liang return true; 204*bd9514a4SKan Liang } 205*bd9514a4SKan Liang 206*bd9514a4SKan Liang return false; 207*bd9514a4SKan Liang } 208*bd9514a4SKan Liang 209edae1f06SKan Liang static int parse_discovery_table(struct pci_dev *dev, int die, 210*bd9514a4SKan Liang u32 bar_offset, bool *parsed, 211*bd9514a4SKan Liang int *ignore) 212edae1f06SKan Liang { 213edae1f06SKan Liang struct uncore_global_discovery global; 214edae1f06SKan Liang struct uncore_unit_discovery unit; 215edae1f06SKan Liang void __iomem *io_addr; 216edae1f06SKan Liang resource_size_t addr; 217edae1f06SKan Liang unsigned long size; 21802a08d78SIngo Molnar u32 val; 219edae1f06SKan Liang int i; 220edae1f06SKan Liang 221edae1f06SKan Liang pci_read_config_dword(dev, bar_offset, &val); 222edae1f06SKan Liang 22371a412edSSteve Wahl if (val & ~PCI_BASE_ADDRESS_MEM_MASK & ~PCI_BASE_ADDRESS_MEM_TYPE_64) 224edae1f06SKan Liang return -EINVAL; 225edae1f06SKan Liang 22671a412edSSteve Wahl addr = (resource_size_t)(val & PCI_BASE_ADDRESS_MEM_MASK); 22771a412edSSteve Wahl #ifdef CONFIG_PHYS_ADDR_T_64BIT 22871a412edSSteve Wahl if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { 22902a08d78SIngo Molnar u32 val2; 23002a08d78SIngo Molnar 23171a412edSSteve Wahl pci_read_config_dword(dev, bar_offset + 4, &val2); 23271a412edSSteve Wahl addr |= ((resource_size_t)val2) << 32; 23371a412edSSteve Wahl } 23471a412edSSteve Wahl #endif 235edae1f06SKan Liang size = UNCORE_DISCOVERY_GLOBAL_MAP_SIZE; 236edae1f06SKan Liang io_addr = ioremap(addr, size); 237edae1f06SKan Liang if (!io_addr) 238edae1f06SKan Liang return -ENOMEM; 239edae1f06SKan Liang 240edae1f06SKan Liang /* Read Global Discovery State */ 241edae1f06SKan Liang memcpy_fromio(&global, io_addr, sizeof(struct uncore_global_discovery)); 242edae1f06SKan Liang if (uncore_discovery_invalid_unit(global)) { 243edae1f06SKan Liang pr_info("Invalid Global Discovery State: 0x%llx 0x%llx 0x%llx\n", 244edae1f06SKan Liang global.table1, global.ctl, global.table3); 245edae1f06SKan Liang iounmap(io_addr); 246edae1f06SKan Liang return -EINVAL; 247edae1f06SKan Liang } 248edae1f06SKan Liang iounmap(io_addr); 249edae1f06SKan Liang 250edae1f06SKan Liang size = (1 + global.max_units) * global.stride * 8; 251edae1f06SKan Liang io_addr = ioremap(addr, size); 252edae1f06SKan Liang if (!io_addr) 253edae1f06SKan Liang return -ENOMEM; 254edae1f06SKan Liang 255edae1f06SKan Liang /* Parsing Unit Discovery State */ 256edae1f06SKan Liang for (i = 0; i < global.max_units; i++) { 257edae1f06SKan Liang memcpy_fromio(&unit, io_addr + (i + 1) * (global.stride * 8), 258edae1f06SKan Liang sizeof(struct uncore_unit_discovery)); 259edae1f06SKan Liang 260edae1f06SKan Liang if (uncore_discovery_invalid_unit(unit)) 261edae1f06SKan Liang continue; 262edae1f06SKan Liang 263edae1f06SKan Liang if (unit.access_type >= UNCORE_ACCESS_MAX) 264edae1f06SKan Liang continue; 265edae1f06SKan Liang 266*bd9514a4SKan Liang if (uncore_ignore_unit(&unit, ignore)) 267*bd9514a4SKan Liang continue; 268*bd9514a4SKan Liang 269edae1f06SKan Liang uncore_insert_box_info(&unit, die, *parsed); 270edae1f06SKan Liang } 271edae1f06SKan Liang 272edae1f06SKan Liang *parsed = true; 273edae1f06SKan Liang iounmap(io_addr); 274edae1f06SKan Liang return 0; 275edae1f06SKan Liang } 276edae1f06SKan Liang 277*bd9514a4SKan Liang bool intel_uncore_has_discovery_tables(int *ignore) 278edae1f06SKan Liang { 279edae1f06SKan Liang u32 device, val, entry_id, bar_offset; 280edae1f06SKan Liang int die, dvsec = 0, ret = true; 281edae1f06SKan Liang struct pci_dev *dev = NULL; 282edae1f06SKan Liang bool parsed = false; 283edae1f06SKan Liang 284edae1f06SKan Liang if (has_generic_discovery_table()) 285edae1f06SKan Liang device = UNCORE_DISCOVERY_TABLE_DEVICE; 286edae1f06SKan Liang else 287edae1f06SKan Liang device = PCI_ANY_ID; 288edae1f06SKan Liang 289edae1f06SKan Liang /* 290edae1f06SKan Liang * Start a new search and iterates through the list of 291edae1f06SKan Liang * the discovery table devices. 292edae1f06SKan Liang */ 293edae1f06SKan Liang while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, dev)) != NULL) { 294edae1f06SKan Liang while ((dvsec = pci_find_next_ext_capability(dev, dvsec, UNCORE_EXT_CAP_ID_DISCOVERY))) { 295edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC_OFFSET, &val); 296edae1f06SKan Liang entry_id = val & UNCORE_DISCOVERY_DVSEC_ID_MASK; 297edae1f06SKan Liang if (entry_id != UNCORE_DISCOVERY_DVSEC_ID_PMON) 298edae1f06SKan Liang continue; 299edae1f06SKan Liang 300edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC2_OFFSET, &val); 301edae1f06SKan Liang 302edae1f06SKan Liang if (val & ~UNCORE_DISCOVERY_DVSEC2_BIR_MASK) { 303edae1f06SKan Liang ret = false; 304edae1f06SKan Liang goto err; 305edae1f06SKan Liang } 306edae1f06SKan Liang bar_offset = UNCORE_DISCOVERY_BIR_BASE + 307edae1f06SKan Liang (val & UNCORE_DISCOVERY_DVSEC2_BIR_MASK) * UNCORE_DISCOVERY_BIR_STEP; 308edae1f06SKan Liang 309edae1f06SKan Liang die = get_device_die_id(dev); 310edae1f06SKan Liang if (die < 0) 311edae1f06SKan Liang continue; 312edae1f06SKan Liang 313*bd9514a4SKan Liang parse_discovery_table(dev, die, bar_offset, &parsed, ignore); 314edae1f06SKan Liang } 315edae1f06SKan Liang } 316edae1f06SKan Liang 317edae1f06SKan Liang /* None of the discovery tables are available */ 318edae1f06SKan Liang if (!parsed) 319edae1f06SKan Liang ret = false; 320edae1f06SKan Liang err: 321edae1f06SKan Liang pci_dev_put(dev); 322edae1f06SKan Liang 323edae1f06SKan Liang return ret; 324edae1f06SKan Liang } 325edae1f06SKan Liang 326edae1f06SKan Liang void intel_uncore_clear_discovery_tables(void) 327edae1f06SKan Liang { 328edae1f06SKan Liang struct intel_uncore_discovery_type *type, *next; 329edae1f06SKan Liang 330edae1f06SKan Liang rbtree_postorder_for_each_entry_safe(type, next, &discovery_tables, node) { 331edae1f06SKan Liang kfree(type->box_ctrl_die); 332edae1f06SKan Liang kfree(type); 333edae1f06SKan Liang } 334edae1f06SKan Liang } 335d6c75413SKan Liang 336d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); 337d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); 338d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); 339d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); 340d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(thresh, thresh, "config:24-31"); 341d6c75413SKan Liang 342d6c75413SKan Liang static struct attribute *generic_uncore_formats_attr[] = { 343d6c75413SKan Liang &format_attr_event.attr, 344d6c75413SKan Liang &format_attr_umask.attr, 345d6c75413SKan Liang &format_attr_edge.attr, 346d6c75413SKan Liang &format_attr_inv.attr, 347d6c75413SKan Liang &format_attr_thresh.attr, 348d6c75413SKan Liang NULL, 349d6c75413SKan Liang }; 350d6c75413SKan Liang 351d6c75413SKan Liang static const struct attribute_group generic_uncore_format_group = { 352d6c75413SKan Liang .name = "format", 353d6c75413SKan Liang .attrs = generic_uncore_formats_attr, 354d6c75413SKan Liang }; 355d6c75413SKan Liang 356949b1138SKan Liang void intel_generic_uncore_msr_init_box(struct intel_uncore_box *box) 357d6c75413SKan Liang { 358d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_INT); 359d6c75413SKan Liang } 360d6c75413SKan Liang 361949b1138SKan Liang void intel_generic_uncore_msr_disable_box(struct intel_uncore_box *box) 362d6c75413SKan Liang { 363d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_FRZ); 364d6c75413SKan Liang } 365d6c75413SKan Liang 366949b1138SKan Liang void intel_generic_uncore_msr_enable_box(struct intel_uncore_box *box) 367d6c75413SKan Liang { 368d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), 0); 369d6c75413SKan Liang } 370d6c75413SKan Liang 371d6c75413SKan Liang static void intel_generic_uncore_msr_enable_event(struct intel_uncore_box *box, 372d6c75413SKan Liang struct perf_event *event) 373d6c75413SKan Liang { 374d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 375d6c75413SKan Liang 376d6c75413SKan Liang wrmsrl(hwc->config_base, hwc->config); 377d6c75413SKan Liang } 378d6c75413SKan Liang 379d6c75413SKan Liang static void intel_generic_uncore_msr_disable_event(struct intel_uncore_box *box, 380d6c75413SKan Liang struct perf_event *event) 381d6c75413SKan Liang { 382d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 383d6c75413SKan Liang 384d6c75413SKan Liang wrmsrl(hwc->config_base, 0); 385d6c75413SKan Liang } 386d6c75413SKan Liang 387d6c75413SKan Liang static struct intel_uncore_ops generic_uncore_msr_ops = { 388d6c75413SKan Liang .init_box = intel_generic_uncore_msr_init_box, 389d6c75413SKan Liang .disable_box = intel_generic_uncore_msr_disable_box, 390d6c75413SKan Liang .enable_box = intel_generic_uncore_msr_enable_box, 391d6c75413SKan Liang .disable_event = intel_generic_uncore_msr_disable_event, 392d6c75413SKan Liang .enable_event = intel_generic_uncore_msr_enable_event, 393d6c75413SKan Liang .read_counter = uncore_msr_read_counter, 394d6c75413SKan Liang }; 395d6c75413SKan Liang 396f57191edSKan Liang void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box) 39742839ef4SKan Liang { 39842839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 39942839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 40042839ef4SKan Liang 40142839ef4SKan Liang __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags); 40242839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT); 40342839ef4SKan Liang } 40442839ef4SKan Liang 405f57191edSKan Liang void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box) 40642839ef4SKan Liang { 40742839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 40842839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 40942839ef4SKan Liang 41042839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ); 41142839ef4SKan Liang } 41242839ef4SKan Liang 413f57191edSKan Liang void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box) 41442839ef4SKan Liang { 41542839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 41642839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 41742839ef4SKan Liang 41842839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, 0); 41942839ef4SKan Liang } 42042839ef4SKan Liang 42142839ef4SKan Liang static void intel_generic_uncore_pci_enable_event(struct intel_uncore_box *box, 42242839ef4SKan Liang struct perf_event *event) 42342839ef4SKan Liang { 42442839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 42542839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 42642839ef4SKan Liang 42742839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, hwc->config); 42842839ef4SKan Liang } 42942839ef4SKan Liang 430f57191edSKan Liang void intel_generic_uncore_pci_disable_event(struct intel_uncore_box *box, 43142839ef4SKan Liang struct perf_event *event) 43242839ef4SKan Liang { 43342839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 43442839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 43542839ef4SKan Liang 43642839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, 0); 43742839ef4SKan Liang } 43842839ef4SKan Liang 439f57191edSKan Liang u64 intel_generic_uncore_pci_read_counter(struct intel_uncore_box *box, 44042839ef4SKan Liang struct perf_event *event) 44142839ef4SKan Liang { 44242839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 44342839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 44442839ef4SKan Liang u64 count = 0; 44542839ef4SKan Liang 44642839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); 44742839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); 44842839ef4SKan Liang 44942839ef4SKan Liang return count; 45042839ef4SKan Liang } 45142839ef4SKan Liang 45242839ef4SKan Liang static struct intel_uncore_ops generic_uncore_pci_ops = { 45342839ef4SKan Liang .init_box = intel_generic_uncore_pci_init_box, 45442839ef4SKan Liang .disable_box = intel_generic_uncore_pci_disable_box, 45542839ef4SKan Liang .enable_box = intel_generic_uncore_pci_enable_box, 45642839ef4SKan Liang .disable_event = intel_generic_uncore_pci_disable_event, 45742839ef4SKan Liang .enable_event = intel_generic_uncore_pci_enable_event, 45842839ef4SKan Liang .read_counter = intel_generic_uncore_pci_read_counter, 45942839ef4SKan Liang }; 46042839ef4SKan Liang 461c4c55e36SKan Liang #define UNCORE_GENERIC_MMIO_SIZE 0x4000 462c4c55e36SKan Liang 46371a412edSSteve Wahl static u64 generic_uncore_mmio_box_ctl(struct intel_uncore_box *box) 464c4c55e36SKan Liang { 465c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 466c4c55e36SKan Liang 467c4c55e36SKan Liang if (!type->box_ctls || !type->box_ctls[box->dieid] || !type->mmio_offsets) 468c4c55e36SKan Liang return 0; 469c4c55e36SKan Liang 470c4c55e36SKan Liang return type->box_ctls[box->dieid] + type->mmio_offsets[box->pmu->pmu_idx]; 471c4c55e36SKan Liang } 472c4c55e36SKan Liang 47385f2e30fSKan Liang void intel_generic_uncore_mmio_init_box(struct intel_uncore_box *box) 474c4c55e36SKan Liang { 47571a412edSSteve Wahl u64 box_ctl = generic_uncore_mmio_box_ctl(box); 476c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 477c4c55e36SKan Liang resource_size_t addr; 478c4c55e36SKan Liang 479c4c55e36SKan Liang if (!box_ctl) { 480c4c55e36SKan Liang pr_warn("Uncore type %d box %d: Invalid box control address.\n", 481c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx]); 482c4c55e36SKan Liang return; 483c4c55e36SKan Liang } 484c4c55e36SKan Liang 485c4c55e36SKan Liang addr = box_ctl; 486c4c55e36SKan Liang box->io_addr = ioremap(addr, UNCORE_GENERIC_MMIO_SIZE); 487c4c55e36SKan Liang if (!box->io_addr) { 488c4c55e36SKan Liang pr_warn("Uncore type %d box %d: ioremap error for 0x%llx.\n", 489c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx], 490c4c55e36SKan Liang (unsigned long long)addr); 491c4c55e36SKan Liang return; 492c4c55e36SKan Liang } 493c4c55e36SKan Liang 494c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_INT, box->io_addr); 495c4c55e36SKan Liang } 496c4c55e36SKan Liang 49785f2e30fSKan Liang void intel_generic_uncore_mmio_disable_box(struct intel_uncore_box *box) 498c4c55e36SKan Liang { 499c4c55e36SKan Liang if (!box->io_addr) 500c4c55e36SKan Liang return; 501c4c55e36SKan Liang 502c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_FRZ, box->io_addr); 503c4c55e36SKan Liang } 504c4c55e36SKan Liang 50585f2e30fSKan Liang void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box) 506c4c55e36SKan Liang { 507c4c55e36SKan Liang if (!box->io_addr) 508c4c55e36SKan Liang return; 509c4c55e36SKan Liang 510c4c55e36SKan Liang writel(0, box->io_addr); 511c4c55e36SKan Liang } 512c4c55e36SKan Liang 5135a4487f9SKan Liang void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box, 514c4c55e36SKan Liang struct perf_event *event) 515c4c55e36SKan Liang { 516c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 517c4c55e36SKan Liang 518c4c55e36SKan Liang if (!box->io_addr) 519c4c55e36SKan Liang return; 520c4c55e36SKan Liang 521c4c55e36SKan Liang writel(hwc->config, box->io_addr + hwc->config_base); 522c4c55e36SKan Liang } 523c4c55e36SKan Liang 52485f2e30fSKan Liang void intel_generic_uncore_mmio_disable_event(struct intel_uncore_box *box, 525c4c55e36SKan Liang struct perf_event *event) 526c4c55e36SKan Liang { 527c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 528c4c55e36SKan Liang 529c4c55e36SKan Liang if (!box->io_addr) 530c4c55e36SKan Liang return; 531c4c55e36SKan Liang 532c4c55e36SKan Liang writel(0, box->io_addr + hwc->config_base); 533c4c55e36SKan Liang } 534c4c55e36SKan Liang 535c4c55e36SKan Liang static struct intel_uncore_ops generic_uncore_mmio_ops = { 536c4c55e36SKan Liang .init_box = intel_generic_uncore_mmio_init_box, 537c4c55e36SKan Liang .exit_box = uncore_mmio_exit_box, 538c4c55e36SKan Liang .disable_box = intel_generic_uncore_mmio_disable_box, 539c4c55e36SKan Liang .enable_box = intel_generic_uncore_mmio_enable_box, 540c4c55e36SKan Liang .disable_event = intel_generic_uncore_mmio_disable_event, 541c4c55e36SKan Liang .enable_event = intel_generic_uncore_mmio_enable_event, 542c4c55e36SKan Liang .read_counter = uncore_mmio_read_counter, 543c4c55e36SKan Liang }; 544c4c55e36SKan Liang 545d6c75413SKan Liang static bool uncore_update_uncore_type(enum uncore_access_type type_id, 546d6c75413SKan Liang struct intel_uncore_type *uncore, 547d6c75413SKan Liang struct intel_uncore_discovery_type *type) 548d6c75413SKan Liang { 549d6c75413SKan Liang uncore->type_id = type->type; 550d6c75413SKan Liang uncore->num_boxes = type->num_boxes; 551d6c75413SKan Liang uncore->num_counters = type->num_counters; 552d6c75413SKan Liang uncore->perf_ctr_bits = type->counter_width; 553d6c75413SKan Liang uncore->box_ids = type->ids; 554d6c75413SKan Liang 555d6c75413SKan Liang switch (type_id) { 556d6c75413SKan Liang case UNCORE_ACCESS_MSR: 557d6c75413SKan Liang uncore->ops = &generic_uncore_msr_ops; 558d6c75413SKan Liang uncore->perf_ctr = (unsigned int)type->box_ctrl + type->ctr_offset; 559d6c75413SKan Liang uncore->event_ctl = (unsigned int)type->box_ctrl + type->ctl_offset; 560d6c75413SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 561d6c75413SKan Liang uncore->msr_offsets = type->box_offset; 562d6c75413SKan Liang break; 56342839ef4SKan Liang case UNCORE_ACCESS_PCI: 56442839ef4SKan Liang uncore->ops = &generic_uncore_pci_ops; 56542839ef4SKan Liang uncore->perf_ctr = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctr_offset; 56642839ef4SKan Liang uncore->event_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctl_offset; 56742839ef4SKan Liang uncore->box_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl); 56842839ef4SKan Liang uncore->box_ctls = type->box_ctrl_die; 56942839ef4SKan Liang uncore->pci_offsets = type->box_offset; 57042839ef4SKan Liang break; 571c4c55e36SKan Liang case UNCORE_ACCESS_MMIO: 572c4c55e36SKan Liang uncore->ops = &generic_uncore_mmio_ops; 573c4c55e36SKan Liang uncore->perf_ctr = (unsigned int)type->ctr_offset; 574c4c55e36SKan Liang uncore->event_ctl = (unsigned int)type->ctl_offset; 575c4c55e36SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 576c4c55e36SKan Liang uncore->box_ctls = type->box_ctrl_die; 577c4c55e36SKan Liang uncore->mmio_offsets = type->box_offset; 578c4c55e36SKan Liang uncore->mmio_map_size = UNCORE_GENERIC_MMIO_SIZE; 579c4c55e36SKan Liang break; 580d6c75413SKan Liang default: 581d6c75413SKan Liang return false; 582d6c75413SKan Liang } 583d6c75413SKan Liang 584d6c75413SKan Liang return true; 585d6c75413SKan Liang } 586d6c75413SKan Liang 587c54c53d9SKan Liang struct intel_uncore_type ** 5880378c93aSKan Liang intel_uncore_generic_init_uncores(enum uncore_access_type type_id, int num_extra) 589d6c75413SKan Liang { 590d6c75413SKan Liang struct intel_uncore_discovery_type *type; 591d6c75413SKan Liang struct intel_uncore_type **uncores; 592d6c75413SKan Liang struct intel_uncore_type *uncore; 593d6c75413SKan Liang struct rb_node *node; 594d6c75413SKan Liang int i = 0; 595d6c75413SKan Liang 5960378c93aSKan Liang uncores = kcalloc(num_discovered_types[type_id] + num_extra + 1, 597d6c75413SKan Liang sizeof(struct intel_uncore_type *), GFP_KERNEL); 598d6c75413SKan Liang if (!uncores) 599d6c75413SKan Liang return empty_uncore; 600d6c75413SKan Liang 601d6c75413SKan Liang for (node = rb_first(&discovery_tables); node; node = rb_next(node)) { 602d6c75413SKan Liang type = rb_entry(node, struct intel_uncore_discovery_type, node); 603d6c75413SKan Liang if (type->access_type != type_id) 604d6c75413SKan Liang continue; 605d6c75413SKan Liang 606d6c75413SKan Liang uncore = kzalloc(sizeof(struct intel_uncore_type), GFP_KERNEL); 607d6c75413SKan Liang if (!uncore) 608d6c75413SKan Liang break; 609d6c75413SKan Liang 610d6c75413SKan Liang uncore->event_mask = GENERIC_PMON_RAW_EVENT_MASK; 611d6c75413SKan Liang uncore->format_group = &generic_uncore_format_group; 612d6c75413SKan Liang 613d6c75413SKan Liang if (!uncore_update_uncore_type(type_id, uncore, type)) { 614d6c75413SKan Liang kfree(uncore); 615d6c75413SKan Liang continue; 616d6c75413SKan Liang } 617d6c75413SKan Liang uncores[i++] = uncore; 618d6c75413SKan Liang } 619d6c75413SKan Liang 620d6c75413SKan Liang return uncores; 621d6c75413SKan Liang } 622d6c75413SKan Liang 623d6c75413SKan Liang void intel_uncore_generic_uncore_cpu_init(void) 624d6c75413SKan Liang { 6250378c93aSKan Liang uncore_msr_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MSR, 0); 626d6c75413SKan Liang } 62742839ef4SKan Liang 62842839ef4SKan Liang int intel_uncore_generic_uncore_pci_init(void) 62942839ef4SKan Liang { 6300378c93aSKan Liang uncore_pci_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_PCI, 0); 63142839ef4SKan Liang 63242839ef4SKan Liang return 0; 63342839ef4SKan Liang } 634c4c55e36SKan Liang 635c4c55e36SKan Liang void intel_uncore_generic_uncore_mmio_init(void) 636c4c55e36SKan Liang { 6370378c93aSKan Liang uncore_mmio_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MMIO, 0); 638c4c55e36SKan Liang } 639