Merge remote-tracking branch 'origin/master' into isa/arm64
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / gic_its.c
1 #include <lunaix/mm/valloc.h>
2 #include <lunaix/mm/page.h>
3
4 #include <asm/soc/gic.h>
5
6 struct gic_its*
7 gic_its_create(struct arm_gic* gic, ptr_t regs)
8 {
9     struct gic_its* its;
10
11     its = valloc(sizeof(*its));
12
13     its->reg_ptr       = regs;
14     its->cmd_queue_ptr = gic_regptr(its->reg->base, GITS_CBASER);
15     its->table_ptr     = gic_regptr(its->reg->base, GITS_BASER);
16
17     llist_append(&gic->its, &its->its);
18     hashtable_init(its->devmaps);
19
20     return its;
21 }
22
23 ptr_t
24 __pack_base_reg(struct leaflet* page, int ic, int oc)
25 {
26     ptr_t reg = 0;
27     
28     reg |= GITS_BASER_VALID;
29     BITS_SET(reg, GITS_BASER_ICACHE, ic);
30     BITS_SET(reg, GITS_BASER_OCACHE, oc);
31     BITS_SET(reg, GITS_BASER_PA, leaflet_addr(page));
32     BITS_SET(reg, GITS_BASER_SIZE, 1);
33     BITS_SET(reg, GITS_BASER_SHARE, 0b01);
34
35     return reg;
36 }
37
38 static void
39 __configure_table_desc(struct gic_its* its, unsigned int off)
40 {
41     gicreg_t val;
42     unsigned int type, sz;
43
44     val = its->tables->base[off];
45     type = BITS_GET(val, GITS_BASERn_TYPE);
46     sz   = BITS_GET(val, GITS_BASERn_EntSz) + 1;
47
48     switch (type)
49     {
50         case 0b001: // DeviceID
51             its->nr_devid = PAGE_SIZE / sz;
52             break;
53         case 0b100: // CollectionID
54             its->nr_cid = PAGE_SIZE / sz;
55             break;
56         default:
57             return;
58     }
59
60     val = __pack_base_reg(alloc_leaflet(0), 0, 0);
61     BITS_SET(val, GITS_BASERn_TYPE, type);
62     BITS_SET(val, GITS_BASERn_EntSz, sz);
63     BITS_SET(val, GITS_BASERn_PGSZ,  0);    // 4K
64
65     its->tables->base[off] = val;
66 }
67
68 static void
69 __configure_one_its(struct arm_gic* gic, struct gic_its* its)
70 {
71     struct leaflet *leaflet;
72     struct gic_its_regs *reg;
73     gicreg_t val;
74     unsigned int field_val;
75
76     reg = its->reg;
77     wait_until(!(val = reg->base[GITS_CTLR]) & GITS_CTLR_QS);
78     reg->base[GITS_CTLR] = val & ~GITS_CTLR_EN;
79
80     val = reg->base[GITS_TYPER];
81
82     field_val = BITS_GET(val, GITS_TYPER_Devbits);
83     its->nr_devid = 1 << (field_val + 1);
84
85     field_val = BITS_GET(val, GITS_TYPER_ID_bits);
86     its->nr_evtid = 1 << (field_val + 1);
87
88     field_val = BITS_GET(val, GITS_TYPER_ITTe_sz);
89     its->nr_evtid = field_val + 1;
90
91     if (!(val & GITS_TYPER_CIL)) {
92         its->nr_cid = BITS_GET(val, GITS_TYPER_HCC);
93     }
94     else {
95         field_val = BITS_GET(val, GITS_TYPER_CIDbits);
96         its->nr_cid = field_val + 1;
97         its->ext_cids = true;
98     }
99
100     its->pta = !!(val & GITS_TYPER_PTA);
101
102     leaflet = alloc_leaflet_pinned(0);
103     val = __pack_base_reg(leaflet, 0, 0);
104     its->cmd_queue->base = val;
105     its->cmd_queue->wr_ptr = 0;
106     its->cmds_ptr = vmap(leaflet, KERNEL_DATA);
107     its->max_cmd  = leaflet_size(leaflet) / sizeof(struct gic_its_cmd);
108
109     // total of 8 GITS_BASER<n> registers
110     for (int i = 0; i < 8; i++)
111     {
112         __configure_table_desc(its, i);
113     }
114
115     reg->base[GITS_CTLR] |= GITS_CTLR_EN;
116 }
117
118 static void
119 __submit_itscmd(struct gic_its* its, struct gic_its_cmd* cmd)
120 {
121     gicreg_t reg;
122     ptr_t wrp;
123
124     reg = its->cmd_queue->wr_ptr;
125
126     wrp = BITS_GET(reg, GITS_CWRRD_OFF);
127
128     if (wrp == its->max_cmd) {
129         /*
130             it is very unlikely we will submit the commands fast
131             enough to satiate the entire queue. so we just roll
132             back to front, assume the ITS always keeping up.
133         */
134         wrp = 0;
135     }
136
137     its->cmds[wrp++] = *cmd;
138
139     reg = BITS_SET(reg, GITS_CWRRD_OFF, wrp);
140     its->cmd_queue->wr_ptr = reg;
141 }
142
143 static void
144 __build_mapc(struct gic_its *its, struct gic_its_cmd* cmd, 
145              struct gic_rd* rd, unsigned int cid)
146 {
147     cmd->dw[0] = 0x09;
148     cmd->dw[1] = 0;
149     cmd->dw[3] = 0;
150     cmd->dw[2] = (1UL << 63) | 
151                  (__ptr(rd) & ~0xffff) | 
152                  (cid & 0xffff);
153 }
154
155 static void
156 __build_mapd(struct gic_its *its, struct gic_its_cmd* cmd, 
157              struct leaflet *itt_page, unsigned int devid)
158 {
159     cmd->dw[0] = ((gicreg64_t)devid << 32) | 0x08;
160     cmd->dw[1] = ilog2(its->nr_evtid);
161     cmd->dw[3] = 0;
162     cmd->dw[2] = (1UL << 63) | 
163                  (leaflet_addr(itt_page));
164 }
165
166 static void
167 __build_mapti(struct gic_its *its, struct gic_its_cmd* cmd, 
168               unsigned int devid, unsigned int evtid, 
169               unsigned int lpid, unsigned int cid)
170 {
171     cmd->dw[0] = ((gicreg64_t)devid << 32) | 0x0A;
172     cmd->dw[1] = ((gicreg64_t)evtid << 32) | evtid;
173     cmd->dw[3] = 0;
174     cmd->dw[2] = (cid & 0xffff);
175 }
176
177 static unsigned int
178 __alloc_evtid(struct gic_its *its, unsigned int devid)
179 {
180     unsigned int evtid;
181     struct gic_its_devmap *pos, *n;
182     struct gic_its_cmd cmd;
183
184     hashtable_hash_foreach(its->devmaps, devid, pos, n, node)
185     {
186         if (pos->devid == devid) {
187             goto found;
188         }
189     }
190
191     pos = valloc(sizeof(*pos));
192     pos->next_evtid = 0;
193     pos->devid = devid;
194     hashtable_hash_in(its->devmaps, &pos->node, devid);
195
196     __build_mapd(its, &cmd, alloc_leaflet_pinned(0), devid);
197     __submit_itscmd(its, &cmd);
198
199 found:
200     evtid = pos->next_evtid++;
201
202     assert(pos->next_evtid < its->nr_evtid);
203
204     return evtid;
205 }
206
207 unsigned int
208 gic_its_map_lpi(struct gic_its* its, 
209                 unsigned int devid, unsigned int lpid)
210 {
211     unsigned int evtid;
212     struct gic_its_cmd cmd;
213
214     evtid = __alloc_evtid(its, devid);
215
216     __build_mapti(its, &cmd, devid, evtid, lpid, 0);
217     __submit_itscmd(its, &cmd);
218
219     return evtid;
220 }
221
222 void
223 gic_configure_its(struct arm_gic* gic)
224 {
225     struct gic_its *pos, *n;
226     struct gic_its_cmd cmd;
227     
228     llist_for_each(pos, n, &gic->its, its)
229     {
230         __configure_one_its(gic, pos);
231     }
232
233     // halt the cpu for a while to let ITS warming up
234     wait_until_expire(true, 10000);
235
236     // identity map every re-distributor to collection
237     llist_for_each(pos, n, &gic->its, its)
238     {
239         for (int i = 0; i < NR_CPU; i++)
240         {
241             __build_mapc(pos, &cmd, gic->pes[i]._rd, i);
242             __submit_itscmd(pos, &cmd);
243         }
244     }
245 }