aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/sgi-gru/grukservices.c
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2009-06-17 19:28:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:04:00 -0400
commit836ce679c0b5b5040164171afc33753396864b30 (patch)
tree786be786c29fa6821d8ee95668393cd43193a278 /drivers/misc/sgi-gru/grukservices.c
parent6e9100741ca430eeef8022794f8b62a23a5916af (diff)
gru: change resource assignment for kernel threads
Change the way GRU resources are assigned for kernel threads. GRU contexts for kernel threads are now allocated on demand and can be stolen by user processes when idle. This allows MPI jobs to use ALL of the GRU resources when the kernel is not using them. Signed-off-by: Jack Steiner <steiner@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc/sgi-gru/grukservices.c')
-rw-r--r--drivers/misc/sgi-gru/grukservices.c201
1 files changed, 120 insertions, 81 deletions
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index 900f7aad2286..50b4dd8b0c9f 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -31,6 +31,7 @@
31#include <linux/proc_fs.h> 31#include <linux/proc_fs.h>
32#include <linux/interrupt.h> 32#include <linux/interrupt.h>
33#include <linux/uaccess.h> 33#include <linux/uaccess.h>
34#include <linux/delay.h>
34#include "gru.h" 35#include "gru.h"
35#include "grulib.h" 36#include "grulib.h"
36#include "grutables.h" 37#include "grutables.h"
@@ -45,18 +46,17 @@
45 * resources. This will likely be replaced when we better understand the 46 * resources. This will likely be replaced when we better understand the
46 * kernel/user requirements. 47 * kernel/user requirements.
47 * 48 *
48 * At boot time, the kernel permanently reserves a fixed number of 49 * Blade percpu resources reserved for kernel use. These resources are
49 * CBRs/DSRs for each cpu to use. The resources are all taken from 50 * reserved whenever the the kernel context for the blade is loaded. Note
50 * the GRU chiplet 1 on the blade. This leaves the full set of resources 51 * that the kernel context is not guaranteed to be always available. It is
51 * of chiplet 0 available to be allocated to a single user. 52 * loaded on demand & can be stolen by a user if the user demand exceeds the
53 * kernel demand. The kernel can always reload the kernel context but
54 * a SLEEP may be required!!!.
52 */ 55 */
53
54/* Blade percpu resources PERMANENTLY reserved for kernel use */
55#define GRU_NUM_KERNEL_CBR 1 56#define GRU_NUM_KERNEL_CBR 1
56#define GRU_NUM_KERNEL_DSR_BYTES 256 57#define GRU_NUM_KERNEL_DSR_BYTES 256
57#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \ 58#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \
58 GRU_CACHE_LINE_BYTES) 59 GRU_CACHE_LINE_BYTES)
59#define KERNEL_CTXNUM 15
60 60
61/* GRU instruction attributes for all instructions */ 61/* GRU instruction attributes for all instructions */
62#define IMA IMA_CB_DELAY 62#define IMA IMA_CB_DELAY
@@ -98,6 +98,88 @@ struct message_header {
98 98
99#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) 99#define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h]))
100 100
101/*
102 * Allocate a kernel context (GTS) for the specified blade.
103 * - protected by writelock on bs_kgts_sema.
104 */
105static void gru_alloc_kernel_context(struct gru_blade_state *bs, int blade_id)
106{
107 int cbr_au_count, dsr_au_count, ncpus;
108
109 ncpus = uv_blade_nr_possible_cpus(blade_id);
110 cbr_au_count = GRU_CB_COUNT_TO_AU(GRU_NUM_KERNEL_CBR * ncpus);
111 dsr_au_count = GRU_DS_BYTES_TO_AU(GRU_NUM_KERNEL_DSR_BYTES * ncpus);
112 bs->bs_kgts = gru_alloc_gts(NULL, cbr_au_count, dsr_au_count, 0, 0);
113}
114
115/*
116 * Reload the blade's kernel context into a GRU chiplet. Called holding
117 * the bs_kgts_sema for READ. Will steal user contexts if necessary.
118 */
119static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id)
120{
121 struct gru_state *gru;
122 struct gru_thread_state *kgts;
123 void *vaddr;
124 int ctxnum;
125
126 up_read(&bs->bs_kgts_sema);
127 down_write(&bs->bs_kgts_sema);
128
129 if (!bs->bs_kgts)
130 gru_alloc_kernel_context(bs, blade_id);
131 kgts = bs->bs_kgts;
132
133 if (!kgts->ts_gru) {
134 STAT(load_kernel_context);
135 while (!gru_assign_gru_context(kgts, blade_id)) {
136 msleep(1);
137 gru_steal_context(kgts, blade_id);
138 }
139 gru_load_context(kgts);
140 gru = bs->bs_kgts->ts_gru;
141 vaddr = gru->gs_gru_base_vaddr;
142 ctxnum = kgts->ts_ctxnum;
143 bs->kernel_cb = get_gseg_base_address_cb(vaddr, ctxnum, 0);
144 bs->kernel_dsr = get_gseg_base_address_ds(vaddr, ctxnum, 0);
145 }
146 downgrade_write(&bs->bs_kgts_sema);
147}
148
149/*
150 * Lock & load the kernel context for the specified blade.
151 */
152static struct gru_blade_state *gru_lock_kernel_context(int blade_id)
153{
154 struct gru_blade_state *bs;
155
156 STAT(lock_kernel_context);
157 bs = gru_base[blade_id];
158
159 down_read(&bs->bs_kgts_sema);
160 if (!bs->bs_kgts || !bs->bs_kgts->ts_gru)
161 gru_load_kernel_context(bs, blade_id);
162 return bs;
163
164}
165
166/*
167 * Unlock the kernel context for the specified blade. Context is not
168 * unloaded but may be stolen before next use.
169 */
170static void gru_unlock_kernel_context(int blade_id)
171{
172 struct gru_blade_state *bs;
173
174 bs = gru_base[blade_id];
175 up_read(&bs->bs_kgts_sema);
176 STAT(unlock_kernel_context);
177}
178
179/*
180 * Reserve & get pointers to the DSR/CBRs reserved for the current cpu.
181 * - returns with preemption disabled
182 */
101static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) 183static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
102{ 184{
103 struct gru_blade_state *bs; 185 struct gru_blade_state *bs;
@@ -105,18 +187,23 @@ static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
105 187
106 BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES); 188 BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES);
107 preempt_disable(); 189 preempt_disable();
108 bs = gru_base[uv_numa_blade_id()]; 190 bs = gru_lock_kernel_context(uv_numa_blade_id());
109 lcpu = uv_blade_processor_id(); 191 lcpu = uv_blade_processor_id();
110 *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; 192 *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE;
111 *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; 193 *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES;
112 return 0; 194 return 0;
113} 195}
114 196
197/*
198 * Free the current cpus reserved DSR/CBR resources.
199 */
115static void gru_free_cpu_resources(void *cb, void *dsr) 200static void gru_free_cpu_resources(void *cb, void *dsr)
116{ 201{
202 gru_unlock_kernel_context(uv_numa_blade_id());
117 preempt_enable(); 203 preempt_enable();
118} 204}
119 205
206/*----------------------------------------------------------------------*/
120int gru_get_cb_exception_detail(void *cb, 207int gru_get_cb_exception_detail(void *cb,
121 struct control_block_extended_exc_detail *excdet) 208 struct control_block_extended_exc_detail *excdet)
122{ 209{
@@ -597,34 +684,36 @@ EXPORT_SYMBOL_GPL(gru_copy_gpa);
597 684
598/* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/ 685/* ------------------- KERNEL QUICKTESTS RUN AT STARTUP ----------------*/
599/* Temp - will delete after we gain confidence in the GRU */ 686/* Temp - will delete after we gain confidence in the GRU */
600static __cacheline_aligned unsigned long word0;
601static __cacheline_aligned unsigned long word1;
602 687
603static int quicktest(struct gru_state *gru) 688int quicktest(void)
604{ 689{
690 unsigned long word0;
691 unsigned long word1;
605 void *cb; 692 void *cb;
606 void *ds; 693 void *dsr;
607 unsigned long *p; 694 unsigned long *p;
608 695
609 cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); 696 if (gru_get_cpu_resources(GRU_CACHE_LINE_BYTES, &cb, &dsr))
610 ds = get_gseg_base_address_ds(gru->gs_gru_base_vaddr, KERNEL_CTXNUM, 0); 697 return MQE_BUG_NO_RESOURCES;
611 p = ds; 698 p = dsr;
612 word0 = MAGIC; 699 word0 = MAGIC;
700 word1 = 0;
613 701
614 gru_vload(cb, uv_gpa(&word0), 0, XTYPE_DW, 1, 1, IMA); 702 gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
615 if (gru_wait(cb) != CBS_IDLE) 703 if (gru_wait(cb) != CBS_IDLE)
616 BUG(); 704 BUG();
617 705
618 if (*(unsigned long *)ds != MAGIC) 706 if (*p != MAGIC)
619 BUG(); 707 BUG();
620 gru_vstore(cb, uv_gpa(&word1), 0, XTYPE_DW, 1, 1, IMA); 708 gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
621 if (gru_wait(cb) != CBS_IDLE) 709 if (gru_wait(cb) != CBS_IDLE)
622 BUG(); 710 BUG();
711 gru_free_cpu_resources(cb, dsr);
623 712
624 if (word0 != word1 || word0 != MAGIC) { 713 if (word0 != word1 || word1 != MAGIC) {
625 printk 714 printk
626 ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n", 715 ("GRU quicktest err: found 0x%lx, expected 0x%lx\n",
627 gru->gs_gid, word1, MAGIC); 716 word1, MAGIC);
628 BUG(); /* ZZZ should not be fatal */ 717 BUG(); /* ZZZ should not be fatal */
629 } 718 }
630 719
@@ -635,80 +724,30 @@ static int quicktest(struct gru_state *gru)
635int gru_kservices_init(struct gru_state *gru) 724int gru_kservices_init(struct gru_state *gru)
636{ 725{
637 struct gru_blade_state *bs; 726 struct gru_blade_state *bs;
638 struct gru_context_configuration_handle *cch; 727
639 unsigned long cbr_map, dsr_map;
640 int err, num, cpus_possible;
641
642 /*
643 * Currently, resources are reserved ONLY on the second chiplet
644 * on each blade. This leaves ALL resources on chiplet 0 available
645 * for user code.
646 */
647 bs = gru->gs_blade; 728 bs = gru->gs_blade;
648 if (gru != &bs->bs_grus[1]) 729 if (gru != &bs->bs_grus[0])
649 return 0; 730 return 0;
650 731
651 cpus_possible = uv_blade_nr_possible_cpus(gru->gs_blade_id); 732 init_rwsem(&bs->bs_kgts_sema);
652
653 num = GRU_NUM_KERNEL_CBR * cpus_possible;
654 cbr_map = gru_reserve_cb_resources(gru, GRU_CB_COUNT_TO_AU(num), NULL);
655 gru->gs_reserved_cbrs += num;
656
657 num = GRU_NUM_KERNEL_DSR_BYTES * cpus_possible;
658 dsr_map = gru_reserve_ds_resources(gru, GRU_DS_BYTES_TO_AU(num), NULL);
659 gru->gs_reserved_dsr_bytes += num;
660
661 gru->gs_active_contexts++;
662 __set_bit(KERNEL_CTXNUM, &gru->gs_context_map);
663 cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM);
664
665 bs->kernel_cb = get_gseg_base_address_cb(gru->gs_gru_base_vaddr,
666 KERNEL_CTXNUM, 0);
667 bs->kernel_dsr = get_gseg_base_address_ds(gru->gs_gru_base_vaddr,
668 KERNEL_CTXNUM, 0);
669
670 lock_cch_handle(cch);
671 cch->tfm_fault_bit_enable = 0;
672 cch->tlb_int_enable = 0;
673 cch->tfm_done_bit_enable = 0;
674 cch->unmap_enable = 1;
675 cch->dsr_allocation_map = dsr_map;
676 cch->cbr_allocation_map = cbr_map;
677
678 err = cch_allocate(cch);
679 if (err) {
680 gru_dbg(grudev,
681 "Unable to allocate kernel CCH: gid %d, err %d\n",
682 gru->gs_gid, err);
683 BUG();
684 }
685 if (cch_start(cch)) {
686 gru_dbg(grudev, "Unable to start kernel CCH: gid %d, err %d\n",
687 gru->gs_gid, err);
688 BUG();
689 }
690 unlock_cch_handle(cch);
691 733
692 if (gru_options & GRU_QUICKLOOK) 734 if (gru_options & GRU_QUICKLOOK)
693 quicktest(gru); 735 quicktest();
694 return 0; 736 return 0;
695} 737}
696 738
697void gru_kservices_exit(struct gru_state *gru) 739void gru_kservices_exit(struct gru_state *gru)
698{ 740{
699 struct gru_context_configuration_handle *cch;
700 struct gru_blade_state *bs; 741 struct gru_blade_state *bs;
742 struct gru_thread_state *kgts;
701 743
702 bs = gru->gs_blade; 744 bs = gru->gs_blade;
703 if (gru != &bs->bs_grus[1]) 745 if (gru != &bs->bs_grus[0])
704 return; 746 return;
705 747
706 cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); 748 kgts = bs->bs_kgts;
707 lock_cch_handle(cch); 749 if (kgts && kgts->ts_gru)
708 if (cch_interrupt_sync(cch)) 750 gru_unload_context(kgts, 0);
709 BUG(); 751 kfree(kgts);
710 if (cch_deallocate(cch))
711 BUG();
712 unlock_cch_handle(cch);
713} 752}
714 753