diff options
Diffstat (limited to 'drivers/misc/sgi-gru/grukservices.c')
-rw-r--r-- | drivers/misc/sgi-gru/grukservices.c | 201 |
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 | */ | ||
105 | static 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 | */ | ||
119 | static 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 | */ | ||
152 | static 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 | */ | ||
170 | static 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 | */ | ||
101 | static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) | 183 | static 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 | */ | ||
115 | static void gru_free_cpu_resources(void *cb, void *dsr) | 200 | static 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 | /*----------------------------------------------------------------------*/ | ||
120 | int gru_get_cb_exception_detail(void *cb, | 207 | int 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 */ |
600 | static __cacheline_aligned unsigned long word0; | ||
601 | static __cacheline_aligned unsigned long word1; | ||
602 | 687 | ||
603 | static int quicktest(struct gru_state *gru) | 688 | int 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) | |||
635 | int gru_kservices_init(struct gru_state *gru) | 724 | int 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 | ||
697 | void gru_kservices_exit(struct gru_state *gru) | 739 | void 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 | ||