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 { 36*dbf061b2SKan 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 46*dbf061b2SKan 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 193edae1f06SKan Liang static int parse_discovery_table(struct pci_dev *dev, int die, 194edae1f06SKan Liang u32 bar_offset, bool *parsed) 195edae1f06SKan Liang { 196edae1f06SKan Liang struct uncore_global_discovery global; 197edae1f06SKan Liang struct uncore_unit_discovery unit; 198edae1f06SKan Liang void __iomem *io_addr; 199edae1f06SKan Liang resource_size_t addr; 200edae1f06SKan Liang unsigned long size; 20102a08d78SIngo Molnar u32 val; 202edae1f06SKan Liang int i; 203edae1f06SKan Liang 204edae1f06SKan Liang pci_read_config_dword(dev, bar_offset, &val); 205edae1f06SKan Liang 20671a412edSSteve Wahl if (val & ~PCI_BASE_ADDRESS_MEM_MASK & ~PCI_BASE_ADDRESS_MEM_TYPE_64) 207edae1f06SKan Liang return -EINVAL; 208edae1f06SKan Liang 20971a412edSSteve Wahl addr = (resource_size_t)(val & PCI_BASE_ADDRESS_MEM_MASK); 21071a412edSSteve Wahl #ifdef CONFIG_PHYS_ADDR_T_64BIT 21171a412edSSteve Wahl if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { 21202a08d78SIngo Molnar u32 val2; 21302a08d78SIngo Molnar 21471a412edSSteve Wahl pci_read_config_dword(dev, bar_offset + 4, &val2); 21571a412edSSteve Wahl addr |= ((resource_size_t)val2) << 32; 21671a412edSSteve Wahl } 21771a412edSSteve Wahl #endif 218edae1f06SKan Liang size = UNCORE_DISCOVERY_GLOBAL_MAP_SIZE; 219edae1f06SKan Liang io_addr = ioremap(addr, size); 220edae1f06SKan Liang if (!io_addr) 221edae1f06SKan Liang return -ENOMEM; 222edae1f06SKan Liang 223edae1f06SKan Liang /* Read Global Discovery State */ 224edae1f06SKan Liang memcpy_fromio(&global, io_addr, sizeof(struct uncore_global_discovery)); 225edae1f06SKan Liang if (uncore_discovery_invalid_unit(global)) { 226edae1f06SKan Liang pr_info("Invalid Global Discovery State: 0x%llx 0x%llx 0x%llx\n", 227edae1f06SKan Liang global.table1, global.ctl, global.table3); 228edae1f06SKan Liang iounmap(io_addr); 229edae1f06SKan Liang return -EINVAL; 230edae1f06SKan Liang } 231edae1f06SKan Liang iounmap(io_addr); 232edae1f06SKan Liang 233edae1f06SKan Liang size = (1 + global.max_units) * global.stride * 8; 234edae1f06SKan Liang io_addr = ioremap(addr, size); 235edae1f06SKan Liang if (!io_addr) 236edae1f06SKan Liang return -ENOMEM; 237edae1f06SKan Liang 238edae1f06SKan Liang /* Parsing Unit Discovery State */ 239edae1f06SKan Liang for (i = 0; i < global.max_units; i++) { 240edae1f06SKan Liang memcpy_fromio(&unit, io_addr + (i + 1) * (global.stride * 8), 241edae1f06SKan Liang sizeof(struct uncore_unit_discovery)); 242edae1f06SKan Liang 243edae1f06SKan Liang if (uncore_discovery_invalid_unit(unit)) 244edae1f06SKan Liang continue; 245edae1f06SKan Liang 246edae1f06SKan Liang if (unit.access_type >= UNCORE_ACCESS_MAX) 247edae1f06SKan Liang continue; 248edae1f06SKan Liang 249edae1f06SKan Liang uncore_insert_box_info(&unit, die, *parsed); 250edae1f06SKan Liang } 251edae1f06SKan Liang 252edae1f06SKan Liang *parsed = true; 253edae1f06SKan Liang iounmap(io_addr); 254edae1f06SKan Liang return 0; 255edae1f06SKan Liang } 256edae1f06SKan Liang 257edae1f06SKan Liang bool intel_uncore_has_discovery_tables(void) 258edae1f06SKan Liang { 259edae1f06SKan Liang u32 device, val, entry_id, bar_offset; 260edae1f06SKan Liang int die, dvsec = 0, ret = true; 261edae1f06SKan Liang struct pci_dev *dev = NULL; 262edae1f06SKan Liang bool parsed = false; 263edae1f06SKan Liang 264edae1f06SKan Liang if (has_generic_discovery_table()) 265edae1f06SKan Liang device = UNCORE_DISCOVERY_TABLE_DEVICE; 266edae1f06SKan Liang else 267edae1f06SKan Liang device = PCI_ANY_ID; 268edae1f06SKan Liang 269edae1f06SKan Liang /* 270edae1f06SKan Liang * Start a new search and iterates through the list of 271edae1f06SKan Liang * the discovery table devices. 272edae1f06SKan Liang */ 273edae1f06SKan Liang while ((dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, dev)) != NULL) { 274edae1f06SKan Liang while ((dvsec = pci_find_next_ext_capability(dev, dvsec, UNCORE_EXT_CAP_ID_DISCOVERY))) { 275edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC_OFFSET, &val); 276edae1f06SKan Liang entry_id = val & UNCORE_DISCOVERY_DVSEC_ID_MASK; 277edae1f06SKan Liang if (entry_id != UNCORE_DISCOVERY_DVSEC_ID_PMON) 278edae1f06SKan Liang continue; 279edae1f06SKan Liang 280edae1f06SKan Liang pci_read_config_dword(dev, dvsec + UNCORE_DISCOVERY_DVSEC2_OFFSET, &val); 281edae1f06SKan Liang 282edae1f06SKan Liang if (val & ~UNCORE_DISCOVERY_DVSEC2_BIR_MASK) { 283edae1f06SKan Liang ret = false; 284edae1f06SKan Liang goto err; 285edae1f06SKan Liang } 286edae1f06SKan Liang bar_offset = UNCORE_DISCOVERY_BIR_BASE + 287edae1f06SKan Liang (val & UNCORE_DISCOVERY_DVSEC2_BIR_MASK) * UNCORE_DISCOVERY_BIR_STEP; 288edae1f06SKan Liang 289edae1f06SKan Liang die = get_device_die_id(dev); 290edae1f06SKan Liang if (die < 0) 291edae1f06SKan Liang continue; 292edae1f06SKan Liang 293edae1f06SKan Liang parse_discovery_table(dev, die, bar_offset, &parsed); 294edae1f06SKan Liang } 295edae1f06SKan Liang } 296edae1f06SKan Liang 297edae1f06SKan Liang /* None of the discovery tables are available */ 298edae1f06SKan Liang if (!parsed) 299edae1f06SKan Liang ret = false; 300edae1f06SKan Liang err: 301edae1f06SKan Liang pci_dev_put(dev); 302edae1f06SKan Liang 303edae1f06SKan Liang return ret; 304edae1f06SKan Liang } 305edae1f06SKan Liang 306edae1f06SKan Liang void intel_uncore_clear_discovery_tables(void) 307edae1f06SKan Liang { 308edae1f06SKan Liang struct intel_uncore_discovery_type *type, *next; 309edae1f06SKan Liang 310edae1f06SKan Liang rbtree_postorder_for_each_entry_safe(type, next, &discovery_tables, node) { 311edae1f06SKan Liang kfree(type->box_ctrl_die); 312edae1f06SKan Liang kfree(type); 313edae1f06SKan Liang } 314edae1f06SKan Liang } 315d6c75413SKan Liang 316d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7"); 317d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15"); 318d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18"); 319d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23"); 320d6c75413SKan Liang DEFINE_UNCORE_FORMAT_ATTR(thresh, thresh, "config:24-31"); 321d6c75413SKan Liang 322d6c75413SKan Liang static struct attribute *generic_uncore_formats_attr[] = { 323d6c75413SKan Liang &format_attr_event.attr, 324d6c75413SKan Liang &format_attr_umask.attr, 325d6c75413SKan Liang &format_attr_edge.attr, 326d6c75413SKan Liang &format_attr_inv.attr, 327d6c75413SKan Liang &format_attr_thresh.attr, 328d6c75413SKan Liang NULL, 329d6c75413SKan Liang }; 330d6c75413SKan Liang 331d6c75413SKan Liang static const struct attribute_group generic_uncore_format_group = { 332d6c75413SKan Liang .name = "format", 333d6c75413SKan Liang .attrs = generic_uncore_formats_attr, 334d6c75413SKan Liang }; 335d6c75413SKan Liang 336949b1138SKan Liang void intel_generic_uncore_msr_init_box(struct intel_uncore_box *box) 337d6c75413SKan Liang { 338d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_INT); 339d6c75413SKan Liang } 340d6c75413SKan Liang 341949b1138SKan Liang void intel_generic_uncore_msr_disable_box(struct intel_uncore_box *box) 342d6c75413SKan Liang { 343d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), GENERIC_PMON_BOX_CTL_FRZ); 344d6c75413SKan Liang } 345d6c75413SKan Liang 346949b1138SKan Liang void intel_generic_uncore_msr_enable_box(struct intel_uncore_box *box) 347d6c75413SKan Liang { 348d6c75413SKan Liang wrmsrl(uncore_msr_box_ctl(box), 0); 349d6c75413SKan Liang } 350d6c75413SKan Liang 351d6c75413SKan Liang static void intel_generic_uncore_msr_enable_event(struct intel_uncore_box *box, 352d6c75413SKan Liang struct perf_event *event) 353d6c75413SKan Liang { 354d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 355d6c75413SKan Liang 356d6c75413SKan Liang wrmsrl(hwc->config_base, hwc->config); 357d6c75413SKan Liang } 358d6c75413SKan Liang 359d6c75413SKan Liang static void intel_generic_uncore_msr_disable_event(struct intel_uncore_box *box, 360d6c75413SKan Liang struct perf_event *event) 361d6c75413SKan Liang { 362d6c75413SKan Liang struct hw_perf_event *hwc = &event->hw; 363d6c75413SKan Liang 364d6c75413SKan Liang wrmsrl(hwc->config_base, 0); 365d6c75413SKan Liang } 366d6c75413SKan Liang 367d6c75413SKan Liang static struct intel_uncore_ops generic_uncore_msr_ops = { 368d6c75413SKan Liang .init_box = intel_generic_uncore_msr_init_box, 369d6c75413SKan Liang .disable_box = intel_generic_uncore_msr_disable_box, 370d6c75413SKan Liang .enable_box = intel_generic_uncore_msr_enable_box, 371d6c75413SKan Liang .disable_event = intel_generic_uncore_msr_disable_event, 372d6c75413SKan Liang .enable_event = intel_generic_uncore_msr_enable_event, 373d6c75413SKan Liang .read_counter = uncore_msr_read_counter, 374d6c75413SKan Liang }; 375d6c75413SKan Liang 376f57191edSKan Liang void intel_generic_uncore_pci_init_box(struct intel_uncore_box *box) 37742839ef4SKan Liang { 37842839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 37942839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 38042839ef4SKan Liang 38142839ef4SKan Liang __set_bit(UNCORE_BOX_FLAG_CTL_OFFS8, &box->flags); 38242839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_INT); 38342839ef4SKan Liang } 38442839ef4SKan Liang 385f57191edSKan Liang void intel_generic_uncore_pci_disable_box(struct intel_uncore_box *box) 38642839ef4SKan Liang { 38742839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 38842839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 38942839ef4SKan Liang 39042839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, GENERIC_PMON_BOX_CTL_FRZ); 39142839ef4SKan Liang } 39242839ef4SKan Liang 393f57191edSKan Liang void intel_generic_uncore_pci_enable_box(struct intel_uncore_box *box) 39442839ef4SKan Liang { 39542839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 39642839ef4SKan Liang int box_ctl = uncore_pci_box_ctl(box); 39742839ef4SKan Liang 39842839ef4SKan Liang pci_write_config_dword(pdev, box_ctl, 0); 39942839ef4SKan Liang } 40042839ef4SKan Liang 40142839ef4SKan Liang static void intel_generic_uncore_pci_enable_event(struct intel_uncore_box *box, 40242839ef4SKan Liang struct perf_event *event) 40342839ef4SKan Liang { 40442839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 40542839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 40642839ef4SKan Liang 40742839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, hwc->config); 40842839ef4SKan Liang } 40942839ef4SKan Liang 410f57191edSKan Liang void intel_generic_uncore_pci_disable_event(struct intel_uncore_box *box, 41142839ef4SKan Liang struct perf_event *event) 41242839ef4SKan Liang { 41342839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 41442839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 41542839ef4SKan Liang 41642839ef4SKan Liang pci_write_config_dword(pdev, hwc->config_base, 0); 41742839ef4SKan Liang } 41842839ef4SKan Liang 419f57191edSKan Liang u64 intel_generic_uncore_pci_read_counter(struct intel_uncore_box *box, 42042839ef4SKan Liang struct perf_event *event) 42142839ef4SKan Liang { 42242839ef4SKan Liang struct pci_dev *pdev = box->pci_dev; 42342839ef4SKan Liang struct hw_perf_event *hwc = &event->hw; 42442839ef4SKan Liang u64 count = 0; 42542839ef4SKan Liang 42642839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base, (u32 *)&count); 42742839ef4SKan Liang pci_read_config_dword(pdev, hwc->event_base + 4, (u32 *)&count + 1); 42842839ef4SKan Liang 42942839ef4SKan Liang return count; 43042839ef4SKan Liang } 43142839ef4SKan Liang 43242839ef4SKan Liang static struct intel_uncore_ops generic_uncore_pci_ops = { 43342839ef4SKan Liang .init_box = intel_generic_uncore_pci_init_box, 43442839ef4SKan Liang .disable_box = intel_generic_uncore_pci_disable_box, 43542839ef4SKan Liang .enable_box = intel_generic_uncore_pci_enable_box, 43642839ef4SKan Liang .disable_event = intel_generic_uncore_pci_disable_event, 43742839ef4SKan Liang .enable_event = intel_generic_uncore_pci_enable_event, 43842839ef4SKan Liang .read_counter = intel_generic_uncore_pci_read_counter, 43942839ef4SKan Liang }; 44042839ef4SKan Liang 441c4c55e36SKan Liang #define UNCORE_GENERIC_MMIO_SIZE 0x4000 442c4c55e36SKan Liang 44371a412edSSteve Wahl static u64 generic_uncore_mmio_box_ctl(struct intel_uncore_box *box) 444c4c55e36SKan Liang { 445c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 446c4c55e36SKan Liang 447c4c55e36SKan Liang if (!type->box_ctls || !type->box_ctls[box->dieid] || !type->mmio_offsets) 448c4c55e36SKan Liang return 0; 449c4c55e36SKan Liang 450c4c55e36SKan Liang return type->box_ctls[box->dieid] + type->mmio_offsets[box->pmu->pmu_idx]; 451c4c55e36SKan Liang } 452c4c55e36SKan Liang 45385f2e30fSKan Liang void intel_generic_uncore_mmio_init_box(struct intel_uncore_box *box) 454c4c55e36SKan Liang { 45571a412edSSteve Wahl u64 box_ctl = generic_uncore_mmio_box_ctl(box); 456c4c55e36SKan Liang struct intel_uncore_type *type = box->pmu->type; 457c4c55e36SKan Liang resource_size_t addr; 458c4c55e36SKan Liang 459c4c55e36SKan Liang if (!box_ctl) { 460c4c55e36SKan Liang pr_warn("Uncore type %d box %d: Invalid box control address.\n", 461c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx]); 462c4c55e36SKan Liang return; 463c4c55e36SKan Liang } 464c4c55e36SKan Liang 465c4c55e36SKan Liang addr = box_ctl; 466c4c55e36SKan Liang box->io_addr = ioremap(addr, UNCORE_GENERIC_MMIO_SIZE); 467c4c55e36SKan Liang if (!box->io_addr) { 468c4c55e36SKan Liang pr_warn("Uncore type %d box %d: ioremap error for 0x%llx.\n", 469c4c55e36SKan Liang type->type_id, type->box_ids[box->pmu->pmu_idx], 470c4c55e36SKan Liang (unsigned long long)addr); 471c4c55e36SKan Liang return; 472c4c55e36SKan Liang } 473c4c55e36SKan Liang 474c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_INT, box->io_addr); 475c4c55e36SKan Liang } 476c4c55e36SKan Liang 47785f2e30fSKan Liang void intel_generic_uncore_mmio_disable_box(struct intel_uncore_box *box) 478c4c55e36SKan Liang { 479c4c55e36SKan Liang if (!box->io_addr) 480c4c55e36SKan Liang return; 481c4c55e36SKan Liang 482c4c55e36SKan Liang writel(GENERIC_PMON_BOX_CTL_FRZ, box->io_addr); 483c4c55e36SKan Liang } 484c4c55e36SKan Liang 48585f2e30fSKan Liang void intel_generic_uncore_mmio_enable_box(struct intel_uncore_box *box) 486c4c55e36SKan Liang { 487c4c55e36SKan Liang if (!box->io_addr) 488c4c55e36SKan Liang return; 489c4c55e36SKan Liang 490c4c55e36SKan Liang writel(0, box->io_addr); 491c4c55e36SKan Liang } 492c4c55e36SKan Liang 4935a4487f9SKan Liang void intel_generic_uncore_mmio_enable_event(struct intel_uncore_box *box, 494c4c55e36SKan Liang struct perf_event *event) 495c4c55e36SKan Liang { 496c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 497c4c55e36SKan Liang 498c4c55e36SKan Liang if (!box->io_addr) 499c4c55e36SKan Liang return; 500c4c55e36SKan Liang 501c4c55e36SKan Liang writel(hwc->config, box->io_addr + hwc->config_base); 502c4c55e36SKan Liang } 503c4c55e36SKan Liang 50485f2e30fSKan Liang void intel_generic_uncore_mmio_disable_event(struct intel_uncore_box *box, 505c4c55e36SKan Liang struct perf_event *event) 506c4c55e36SKan Liang { 507c4c55e36SKan Liang struct hw_perf_event *hwc = &event->hw; 508c4c55e36SKan Liang 509c4c55e36SKan Liang if (!box->io_addr) 510c4c55e36SKan Liang return; 511c4c55e36SKan Liang 512c4c55e36SKan Liang writel(0, box->io_addr + hwc->config_base); 513c4c55e36SKan Liang } 514c4c55e36SKan Liang 515c4c55e36SKan Liang static struct intel_uncore_ops generic_uncore_mmio_ops = { 516c4c55e36SKan Liang .init_box = intel_generic_uncore_mmio_init_box, 517c4c55e36SKan Liang .exit_box = uncore_mmio_exit_box, 518c4c55e36SKan Liang .disable_box = intel_generic_uncore_mmio_disable_box, 519c4c55e36SKan Liang .enable_box = intel_generic_uncore_mmio_enable_box, 520c4c55e36SKan Liang .disable_event = intel_generic_uncore_mmio_disable_event, 521c4c55e36SKan Liang .enable_event = intel_generic_uncore_mmio_enable_event, 522c4c55e36SKan Liang .read_counter = uncore_mmio_read_counter, 523c4c55e36SKan Liang }; 524c4c55e36SKan Liang 525d6c75413SKan Liang static bool uncore_update_uncore_type(enum uncore_access_type type_id, 526d6c75413SKan Liang struct intel_uncore_type *uncore, 527d6c75413SKan Liang struct intel_uncore_discovery_type *type) 528d6c75413SKan Liang { 529d6c75413SKan Liang uncore->type_id = type->type; 530d6c75413SKan Liang uncore->num_boxes = type->num_boxes; 531d6c75413SKan Liang uncore->num_counters = type->num_counters; 532d6c75413SKan Liang uncore->perf_ctr_bits = type->counter_width; 533d6c75413SKan Liang uncore->box_ids = type->ids; 534d6c75413SKan Liang 535d6c75413SKan Liang switch (type_id) { 536d6c75413SKan Liang case UNCORE_ACCESS_MSR: 537d6c75413SKan Liang uncore->ops = &generic_uncore_msr_ops; 538d6c75413SKan Liang uncore->perf_ctr = (unsigned int)type->box_ctrl + type->ctr_offset; 539d6c75413SKan Liang uncore->event_ctl = (unsigned int)type->box_ctrl + type->ctl_offset; 540d6c75413SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 541d6c75413SKan Liang uncore->msr_offsets = type->box_offset; 542d6c75413SKan Liang break; 54342839ef4SKan Liang case UNCORE_ACCESS_PCI: 54442839ef4SKan Liang uncore->ops = &generic_uncore_pci_ops; 54542839ef4SKan Liang uncore->perf_ctr = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctr_offset; 54642839ef4SKan Liang uncore->event_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl) + type->ctl_offset; 54742839ef4SKan Liang uncore->box_ctl = (unsigned int)UNCORE_DISCOVERY_PCI_BOX_CTRL(type->box_ctrl); 54842839ef4SKan Liang uncore->box_ctls = type->box_ctrl_die; 54942839ef4SKan Liang uncore->pci_offsets = type->box_offset; 55042839ef4SKan Liang break; 551c4c55e36SKan Liang case UNCORE_ACCESS_MMIO: 552c4c55e36SKan Liang uncore->ops = &generic_uncore_mmio_ops; 553c4c55e36SKan Liang uncore->perf_ctr = (unsigned int)type->ctr_offset; 554c4c55e36SKan Liang uncore->event_ctl = (unsigned int)type->ctl_offset; 555c4c55e36SKan Liang uncore->box_ctl = (unsigned int)type->box_ctrl; 556c4c55e36SKan Liang uncore->box_ctls = type->box_ctrl_die; 557c4c55e36SKan Liang uncore->mmio_offsets = type->box_offset; 558c4c55e36SKan Liang uncore->mmio_map_size = UNCORE_GENERIC_MMIO_SIZE; 559c4c55e36SKan Liang break; 560d6c75413SKan Liang default: 561d6c75413SKan Liang return false; 562d6c75413SKan Liang } 563d6c75413SKan Liang 564d6c75413SKan Liang return true; 565d6c75413SKan Liang } 566d6c75413SKan Liang 567c54c53d9SKan Liang struct intel_uncore_type ** 5680378c93aSKan Liang intel_uncore_generic_init_uncores(enum uncore_access_type type_id, int num_extra) 569d6c75413SKan Liang { 570d6c75413SKan Liang struct intel_uncore_discovery_type *type; 571d6c75413SKan Liang struct intel_uncore_type **uncores; 572d6c75413SKan Liang struct intel_uncore_type *uncore; 573d6c75413SKan Liang struct rb_node *node; 574d6c75413SKan Liang int i = 0; 575d6c75413SKan Liang 5760378c93aSKan Liang uncores = kcalloc(num_discovered_types[type_id] + num_extra + 1, 577d6c75413SKan Liang sizeof(struct intel_uncore_type *), GFP_KERNEL); 578d6c75413SKan Liang if (!uncores) 579d6c75413SKan Liang return empty_uncore; 580d6c75413SKan Liang 581d6c75413SKan Liang for (node = rb_first(&discovery_tables); node; node = rb_next(node)) { 582d6c75413SKan Liang type = rb_entry(node, struct intel_uncore_discovery_type, node); 583d6c75413SKan Liang if (type->access_type != type_id) 584d6c75413SKan Liang continue; 585d6c75413SKan Liang 586d6c75413SKan Liang uncore = kzalloc(sizeof(struct intel_uncore_type), GFP_KERNEL); 587d6c75413SKan Liang if (!uncore) 588d6c75413SKan Liang break; 589d6c75413SKan Liang 590d6c75413SKan Liang uncore->event_mask = GENERIC_PMON_RAW_EVENT_MASK; 591d6c75413SKan Liang uncore->format_group = &generic_uncore_format_group; 592d6c75413SKan Liang 593d6c75413SKan Liang if (!uncore_update_uncore_type(type_id, uncore, type)) { 594d6c75413SKan Liang kfree(uncore); 595d6c75413SKan Liang continue; 596d6c75413SKan Liang } 597d6c75413SKan Liang uncores[i++] = uncore; 598d6c75413SKan Liang } 599d6c75413SKan Liang 600d6c75413SKan Liang return uncores; 601d6c75413SKan Liang } 602d6c75413SKan Liang 603d6c75413SKan Liang void intel_uncore_generic_uncore_cpu_init(void) 604d6c75413SKan Liang { 6050378c93aSKan Liang uncore_msr_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MSR, 0); 606d6c75413SKan Liang } 60742839ef4SKan Liang 60842839ef4SKan Liang int intel_uncore_generic_uncore_pci_init(void) 60942839ef4SKan Liang { 6100378c93aSKan Liang uncore_pci_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_PCI, 0); 61142839ef4SKan Liang 61242839ef4SKan Liang return 0; 61342839ef4SKan Liang } 614c4c55e36SKan Liang 615c4c55e36SKan Liang void intel_uncore_generic_uncore_mmio_init(void) 616c4c55e36SKan Liang { 6170378c93aSKan Liang uncore_mmio_uncores = intel_uncore_generic_init_uncores(UNCORE_ACCESS_MMIO, 0); 618c4c55e36SKan Liang } 619