static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct uv_irq_2_mmr_pnode *chip_data; struct irq_alloc_info *info = arg; struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq); int ret; if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_UV) return -EINVAL; chip_data = kmalloc_node(sizeof(*chip_data), GFP_KERNEL, irq_data_get_node(irq_data)); if (!chip_data) return -ENOMEM; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); if (ret >= 0) { if (info->uv_limit == UV_AFFINITY_CPU) irq_set_status_flags(virq, IRQ_NO_BALANCING); else irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); chip_data->pnode = uv_blade_to_pnode(info->uv_blade); chip_data->offset = info->uv_offset; irq_domain_set_info(domain, virq, virq, &uv_irq_chip, chip_data, handle_percpu_irq, NULL, info->uv_name); } else { kfree(chip_data); } return ret; }
static int xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq) { int ret; #if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address), mq->order, &mq->mmr_offset); if (ret < 0) { dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", ret); return -EBUSY; } #elif defined CONFIG_X86_64 ret = uv_bios_mq_watchlist_alloc(uv_gpa(mq->address), mq->order, &mq->mmr_offset); if (ret < 0) { dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " "ret=%d\n", ret); return ret; } #else #error not a supported configuration #endif mq->watchlist_num = ret; return 0; }
static int xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name) { int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); #if defined CONFIG_X86_64 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset, UV_AFFINITY_CPU); if (mq->irq < 0) return mq->irq; mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset); #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0) mq->irq = SGI_XPC_ACTIVATE; else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0) mq->irq = SGI_XPC_NOTIFY; else return -EINVAL; mq->mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq; uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mq->mmr_value); #else #error not a supported configuration #endif return 0; }
static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade) { struct rb_node **link = &uv_irq_root.rb_node; struct rb_node *parent = NULL; struct uv_irq_2_mmr_pnode *n; struct uv_irq_2_mmr_pnode *e; unsigned long irqflags; n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL, uv_blade_to_memory_nid(blade)); if (!n) return -ENOMEM; n->irq = irq; n->offset = offset; n->pnode = uv_blade_to_pnode(blade); spin_lock_irqsave(&uv_irq_lock, irqflags); while (*link) { parent = *link; e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list); if (unlikely(irq == e->irq)) { e->pnode = uv_blade_to_pnode(blade); e->offset = offset; spin_unlock_irqrestore(&uv_irq_lock, irqflags); kfree(n); return 0; } if (irq < e->irq) link = &(*link)->rb_left; else link = &(*link)->rb_right; } rb_link_node(&n->list, parent, link); rb_insert_color(&n->list, &uv_irq_root); spin_unlock_irqrestore(&uv_irq_lock, irqflags); return 0; }
static void xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq) { int ret; int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); #if defined CONFIG_X86_64 ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num); BUG_ON(ret != BIOS_STATUS_SUCCESS); #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num); BUG_ON(ret != SALRET_OK); #else #error not a supported configuration #endif }
static void xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq) { #if defined CONFIG_X86_64 uv_teardown_irq(mq->irq); #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV int mmr_pnode; unsigned long mmr_value; mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); mmr_value = 1UL << 16; uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value); #else #error not a supported configuration #endif }
static int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, unsigned long mmr_offset, int limit) { const struct cpumask *eligible_cpu = cpumask_of(cpu); struct irq_cfg *cfg = irq_get_chip_data(irq); unsigned long mmr_value; struct uv_IO_APIC_route_entry *entry; int mmr_pnode, err; BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); err = assign_irq_vector(irq, cfg, eligible_cpu); if (err != 0) return err; if (limit == UV_AFFINITY_CPU) irq_set_status_flags(irq, IRQ_NO_BALANCING); else irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); irq_set_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq, irq_name); mmr_value = 0; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->vector = cfg->vector; entry->delivery_mode = apic->irq_delivery_mode; entry->dest_mode = apic->irq_dest_mode; entry->polarity = 0; entry->trigger = 0; entry->mask = 0; entry->dest = apic->cpu_mask_to_apicid(eligible_cpu); mmr_pnode = uv_blade_to_pnode(mmr_blade); uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value); if (cfg->move_in_progress) send_cleanup_vector(cfg); return irq; }