0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <linux/device.h>
0020 #include <linux/hardirq.h>
0021 #include <linux/slab.h>
0022 #include "xpc.h"
0023 #include <asm/uv/uv_hub.h>
0024
0025
0026 int xpc_exiting;
0027
0028
0029 struct xpc_rsvd_page *xpc_rsvd_page;
0030 static unsigned long *xpc_part_nasids;
0031 unsigned long *xpc_mach_nasids;
0032
0033 static int xpc_nasid_mask_nbytes;
0034 int xpc_nasid_mask_nlongs;
0035
0036 struct xpc_partition *xpc_partitions;
0037
0038
0039
0040
0041 void *
0042 xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
0043 {
0044
0045 *base = kmalloc(size, flags);
0046 if (*base == NULL)
0047 return NULL;
0048
0049 if ((u64)*base == L1_CACHE_ALIGN((u64)*base))
0050 return *base;
0051
0052 kfree(*base);
0053
0054
0055 *base = kmalloc(size + L1_CACHE_BYTES, flags);
0056 if (*base == NULL)
0057 return NULL;
0058
0059 return (void *)L1_CACHE_ALIGN((u64)*base);
0060 }
0061
0062
0063
0064
0065
0066 static unsigned long
0067 xpc_get_rsvd_page_pa(int nasid)
0068 {
0069 enum xp_retval ret;
0070 u64 cookie = 0;
0071 unsigned long rp_pa = nasid;
0072 size_t len = 0;
0073 size_t buf_len = 0;
0074 void *buf = NULL;
0075 void *buf_base = NULL;
0076 enum xp_retval (*get_partition_rsvd_page_pa)
0077 (void *, u64 *, unsigned long *, size_t *) =
0078 xpc_arch_ops.get_partition_rsvd_page_pa;
0079
0080 while (1) {
0081
0082
0083
0084
0085
0086
0087
0088 ret = get_partition_rsvd_page_pa(buf, &cookie, &rp_pa, &len);
0089
0090 dev_dbg(xpc_part, "SAL returned with ret=%d, cookie=0x%016lx, "
0091 "address=0x%016lx, len=0x%016lx\n", ret,
0092 (unsigned long)cookie, rp_pa, len);
0093
0094 if (ret != xpNeedMoreInfo)
0095 break;
0096
0097 if (len > buf_len) {
0098 kfree(buf_base);
0099 buf_len = L1_CACHE_ALIGN(len);
0100 buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL,
0101 &buf_base);
0102 if (buf_base == NULL) {
0103 dev_err(xpc_part, "unable to kmalloc "
0104 "len=0x%016lx\n", buf_len);
0105 ret = xpNoMemory;
0106 break;
0107 }
0108 }
0109
0110 ret = xp_remote_memcpy(xp_pa(buf), rp_pa, len);
0111 if (ret != xpSuccess) {
0112 dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret);
0113 break;
0114 }
0115 }
0116
0117 kfree(buf_base);
0118
0119 if (ret != xpSuccess)
0120 rp_pa = 0;
0121
0122 dev_dbg(xpc_part, "reserved page at phys address 0x%016lx\n", rp_pa);
0123 return rp_pa;
0124 }
0125
0126
0127
0128
0129
0130
0131 int
0132 xpc_setup_rsvd_page(void)
0133 {
0134 int ret;
0135 struct xpc_rsvd_page *rp;
0136 unsigned long rp_pa;
0137 unsigned long new_ts_jiffies;
0138
0139
0140
0141 preempt_disable();
0142 rp_pa = xpc_get_rsvd_page_pa(xp_cpu_to_nasid(smp_processor_id()));
0143 preempt_enable();
0144 if (rp_pa == 0) {
0145 dev_err(xpc_part, "SAL failed to locate the reserved page\n");
0146 return -ESRCH;
0147 }
0148 rp = (struct xpc_rsvd_page *)__va(xp_socket_pa(rp_pa));
0149
0150 if (rp->SAL_version < 3) {
0151
0152 rp->SAL_partid &= 0xff;
0153 }
0154 BUG_ON(rp->SAL_partid != xp_partition_id);
0155
0156 if (rp->SAL_partid < 0 || rp->SAL_partid >= xp_max_npartitions) {
0157 dev_err(xpc_part, "the reserved page's partid of %d is outside "
0158 "supported range (< 0 || >= %d)\n", rp->SAL_partid,
0159 xp_max_npartitions);
0160 return -EINVAL;
0161 }
0162
0163 rp->version = XPC_RP_VERSION;
0164 rp->max_npartitions = xp_max_npartitions;
0165
0166
0167 if (rp->SAL_version == 1) {
0168
0169 rp->SAL_nasids_size = 128;
0170 }
0171 xpc_nasid_mask_nbytes = rp->SAL_nasids_size;
0172 xpc_nasid_mask_nlongs = BITS_TO_LONGS(rp->SAL_nasids_size *
0173 BITS_PER_BYTE);
0174
0175
0176 xpc_part_nasids = XPC_RP_PART_NASIDS(rp);
0177 xpc_mach_nasids = XPC_RP_MACH_NASIDS(rp);
0178
0179 ret = xpc_arch_ops.setup_rsvd_page(rp);
0180 if (ret != 0)
0181 return ret;
0182
0183
0184
0185
0186
0187
0188 new_ts_jiffies = jiffies;
0189 if (new_ts_jiffies == 0 || new_ts_jiffies == rp->ts_jiffies)
0190 new_ts_jiffies++;
0191 rp->ts_jiffies = new_ts_jiffies;
0192
0193 xpc_rsvd_page = rp;
0194 return 0;
0195 }
0196
0197 void
0198 xpc_teardown_rsvd_page(void)
0199 {
0200
0201 xpc_rsvd_page->ts_jiffies = 0;
0202 }
0203
0204
0205
0206
0207
0208
0209
0210
0211 enum xp_retval
0212 xpc_get_remote_rp(int nasid, unsigned long *discovered_nasids,
0213 struct xpc_rsvd_page *remote_rp, unsigned long *remote_rp_pa)
0214 {
0215 int l;
0216 enum xp_retval ret;
0217
0218
0219
0220 *remote_rp_pa = xpc_get_rsvd_page_pa(nasid);
0221 if (*remote_rp_pa == 0)
0222 return xpNoRsvdPageAddr;
0223
0224
0225 ret = xp_remote_memcpy(xp_pa(remote_rp), *remote_rp_pa,
0226 XPC_RP_HEADER_SIZE + xpc_nasid_mask_nbytes);
0227 if (ret != xpSuccess)
0228 return ret;
0229
0230 if (discovered_nasids != NULL) {
0231 unsigned long *remote_part_nasids =
0232 XPC_RP_PART_NASIDS(remote_rp);
0233
0234 for (l = 0; l < xpc_nasid_mask_nlongs; l++)
0235 discovered_nasids[l] |= remote_part_nasids[l];
0236 }
0237
0238
0239 if (remote_rp->ts_jiffies == 0)
0240 return xpRsvdPageNotSet;
0241
0242 if (XPC_VERSION_MAJOR(remote_rp->version) !=
0243 XPC_VERSION_MAJOR(XPC_RP_VERSION)) {
0244 return xpBadVersion;
0245 }
0246
0247
0248 if (remote_rp->SAL_partid < 0 ||
0249 remote_rp->SAL_partid >= xp_max_npartitions ||
0250 remote_rp->max_npartitions <= xp_partition_id) {
0251 return xpInvalidPartid;
0252 }
0253
0254 if (remote_rp->SAL_partid == xp_partition_id)
0255 return xpLocalPartid;
0256
0257 return xpSuccess;
0258 }
0259
0260
0261
0262
0263
0264
0265 static int __xpc_partition_disengaged(struct xpc_partition *part,
0266 bool from_timer)
0267 {
0268 short partid = XPC_PARTID(part);
0269 int disengaged;
0270
0271 disengaged = !xpc_arch_ops.partition_engaged(partid);
0272 if (part->disengage_timeout) {
0273 if (!disengaged) {
0274 if (time_is_after_jiffies(part->disengage_timeout)) {
0275
0276 return 0;
0277 }
0278
0279
0280
0281
0282
0283
0284 dev_info(xpc_part, "deactivate request to remote "
0285 "partition %d timed out\n", partid);
0286 xpc_disengage_timedout = 1;
0287 xpc_arch_ops.assume_partition_disengaged(partid);
0288 disengaged = 1;
0289 }
0290 part->disengage_timeout = 0;
0291
0292
0293 if (!from_timer)
0294 del_timer_sync(&part->disengage_timer);
0295
0296 DBUG_ON(part->act_state != XPC_P_AS_DEACTIVATING &&
0297 part->act_state != XPC_P_AS_INACTIVE);
0298 if (part->act_state != XPC_P_AS_INACTIVE)
0299 xpc_wakeup_channel_mgr(part);
0300
0301 xpc_arch_ops.cancel_partition_deactivation_request(part);
0302 }
0303 return disengaged;
0304 }
0305
0306 int xpc_partition_disengaged(struct xpc_partition *part)
0307 {
0308 return __xpc_partition_disengaged(part, false);
0309 }
0310
0311 int xpc_partition_disengaged_from_timer(struct xpc_partition *part)
0312 {
0313 return __xpc_partition_disengaged(part, true);
0314 }
0315
0316
0317
0318
0319 enum xp_retval
0320 xpc_mark_partition_active(struct xpc_partition *part)
0321 {
0322 unsigned long irq_flags;
0323 enum xp_retval ret;
0324
0325 dev_dbg(xpc_part, "setting partition %d to ACTIVE\n", XPC_PARTID(part));
0326
0327 spin_lock_irqsave(&part->act_lock, irq_flags);
0328 if (part->act_state == XPC_P_AS_ACTIVATING) {
0329 part->act_state = XPC_P_AS_ACTIVE;
0330 ret = xpSuccess;
0331 } else {
0332 DBUG_ON(part->reason == xpSuccess);
0333 ret = part->reason;
0334 }
0335 spin_unlock_irqrestore(&part->act_lock, irq_flags);
0336
0337 return ret;
0338 }
0339
0340
0341
0342
0343 void
0344 xpc_deactivate_partition(const int line, struct xpc_partition *part,
0345 enum xp_retval reason)
0346 {
0347 unsigned long irq_flags;
0348
0349 spin_lock_irqsave(&part->act_lock, irq_flags);
0350
0351 if (part->act_state == XPC_P_AS_INACTIVE) {
0352 XPC_SET_REASON(part, reason, line);
0353 spin_unlock_irqrestore(&part->act_lock, irq_flags);
0354 if (reason == xpReactivating) {
0355
0356 xpc_arch_ops.request_partition_reactivation(part);
0357 }
0358 return;
0359 }
0360 if (part->act_state == XPC_P_AS_DEACTIVATING) {
0361 if ((part->reason == xpUnloading && reason != xpUnloading) ||
0362 reason == xpReactivating) {
0363 XPC_SET_REASON(part, reason, line);
0364 }
0365 spin_unlock_irqrestore(&part->act_lock, irq_flags);
0366 return;
0367 }
0368
0369 part->act_state = XPC_P_AS_DEACTIVATING;
0370 XPC_SET_REASON(part, reason, line);
0371
0372 spin_unlock_irqrestore(&part->act_lock, irq_flags);
0373
0374
0375 xpc_arch_ops.request_partition_deactivation(part);
0376
0377
0378 part->disengage_timeout = jiffies + (xpc_disengage_timelimit * HZ);
0379 part->disengage_timer.expires = part->disengage_timeout;
0380 add_timer(&part->disengage_timer);
0381
0382 dev_dbg(xpc_part, "bringing partition %d down, reason = %d\n",
0383 XPC_PARTID(part), reason);
0384
0385 xpc_partition_going_down(part, reason);
0386 }
0387
0388
0389
0390
0391 void
0392 xpc_mark_partition_inactive(struct xpc_partition *part)
0393 {
0394 unsigned long irq_flags;
0395
0396 dev_dbg(xpc_part, "setting partition %d to INACTIVE\n",
0397 XPC_PARTID(part));
0398
0399 spin_lock_irqsave(&part->act_lock, irq_flags);
0400 part->act_state = XPC_P_AS_INACTIVE;
0401 spin_unlock_irqrestore(&part->act_lock, irq_flags);
0402 part->remote_rp_pa = 0;
0403 }
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414 void
0415 xpc_discovery(void)
0416 {
0417 void *remote_rp_base;
0418 struct xpc_rsvd_page *remote_rp;
0419 unsigned long remote_rp_pa;
0420 int region;
0421 int region_size;
0422 int max_regions;
0423 int nasid;
0424 unsigned long *discovered_nasids;
0425 enum xp_retval ret;
0426
0427 remote_rp = xpc_kmalloc_cacheline_aligned(XPC_RP_HEADER_SIZE +
0428 xpc_nasid_mask_nbytes,
0429 GFP_KERNEL, &remote_rp_base);
0430 if (remote_rp == NULL)
0431 return;
0432
0433 discovered_nasids = kcalloc(xpc_nasid_mask_nlongs, sizeof(long),
0434 GFP_KERNEL);
0435 if (discovered_nasids == NULL) {
0436 kfree(remote_rp_base);
0437 return;
0438 }
0439
0440
0441
0442
0443
0444
0445 region_size = xp_region_size;
0446
0447 if (is_uv_system())
0448 max_regions = 256;
0449 else {
0450 max_regions = 64;
0451
0452 switch (region_size) {
0453 case 128:
0454 max_regions *= 2;
0455 fallthrough;
0456 case 64:
0457 max_regions *= 2;
0458 fallthrough;
0459 case 32:
0460 max_regions *= 2;
0461 region_size = 16;
0462 }
0463 }
0464
0465 for (region = 0; region < max_regions; region++) {
0466
0467 if (xpc_exiting)
0468 break;
0469
0470 dev_dbg(xpc_part, "searching region %d\n", region);
0471
0472 for (nasid = (region * region_size * 2);
0473 nasid < ((region + 1) * region_size * 2); nasid += 2) {
0474
0475 if (xpc_exiting)
0476 break;
0477
0478 dev_dbg(xpc_part, "checking nasid %d\n", nasid);
0479
0480 if (test_bit(nasid / 2, xpc_part_nasids)) {
0481 dev_dbg(xpc_part, "PROM indicates Nasid %d is "
0482 "part of the local partition; skipping "
0483 "region\n", nasid);
0484 break;
0485 }
0486
0487 if (!(test_bit(nasid / 2, xpc_mach_nasids))) {
0488 dev_dbg(xpc_part, "PROM indicates Nasid %d was "
0489 "not on Numa-Link network at reset\n",
0490 nasid);
0491 continue;
0492 }
0493
0494 if (test_bit(nasid / 2, discovered_nasids)) {
0495 dev_dbg(xpc_part, "Nasid %d is part of a "
0496 "partition which was previously "
0497 "discovered\n", nasid);
0498 continue;
0499 }
0500
0501
0502
0503 ret = xpc_get_remote_rp(nasid, discovered_nasids,
0504 remote_rp, &remote_rp_pa);
0505 if (ret != xpSuccess) {
0506 dev_dbg(xpc_part, "unable to get reserved page "
0507 "from nasid %d, reason=%d\n", nasid,
0508 ret);
0509
0510 if (ret == xpLocalPartid)
0511 break;
0512
0513 continue;
0514 }
0515
0516 xpc_arch_ops.request_partition_activation(remote_rp,
0517 remote_rp_pa, nasid);
0518 }
0519 }
0520
0521 kfree(discovered_nasids);
0522 kfree(remote_rp_base);
0523 }
0524
0525
0526
0527
0528
0529 enum xp_retval
0530 xpc_initiate_partid_to_nasids(short partid, void *nasid_mask)
0531 {
0532 struct xpc_partition *part;
0533 unsigned long part_nasid_pa;
0534
0535 part = &xpc_partitions[partid];
0536 if (part->remote_rp_pa == 0)
0537 return xpPartitionDown;
0538
0539 memset(nasid_mask, 0, xpc_nasid_mask_nbytes);
0540
0541 part_nasid_pa = (unsigned long)XPC_RP_PART_NASIDS(part->remote_rp_pa);
0542
0543 return xp_remote_memcpy(xp_pa(nasid_mask), part_nasid_pa,
0544 xpc_nasid_mask_nbytes);
0545 }