1 /*
2 * Copyright (C) 2020, Red Hat Inc, Eric Auger <eric.auger@redhat.com>
3 *
4 * This work is licensed under the terms of the GNU LGPL, version 2.
5 */
6 #include <asm/gic.h>
7 #include <alloc_page.h>
8
its_parse_typer(void)9 void its_parse_typer(void)
10 {
11 u64 typer = readq(gicv3_its_base() + GITS_TYPER);
12 struct its_typer *t = &its_data.typer;
13
14 t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1;
15 t->pta = typer & GITS_TYPER_PTA;
16 t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1;
17 t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1;
18
19 if (typer & GITS_TYPER_CIL)
20 t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1;
21 else
22 t->collid_bits = 16;
23
24 t->virt_lpi = typer & GITS_TYPER_VLPIS;
25 t->phys_lpi = typer & GITS_TYPER_PLPIS;
26 }
27
its_baser_lookup(int type,struct its_baser * baser)28 int its_baser_lookup(int type, struct its_baser *baser)
29 {
30 int i;
31
32 for (i = 0; i < GITS_BASER_NR_REGS; i++) {
33 void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8;
34 u64 val = readq(reg_addr);
35
36 if (GITS_BASER_TYPE(val) == type) {
37 assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K);
38 baser->esz = GITS_BASER_ENTRY_SIZE(val);
39 baser->indirect = val & GITS_BASER_INDIRECT;
40 baser->index = i;
41 return 0;
42 }
43 }
44 return -1;
45 }
46
47 /*
48 * Allocate the BASER table (a single page of size @baser->psz)
49 * and set the BASER valid
50 */
its_baser_alloc_table(struct its_baser * baser,size_t size)51 static void its_baser_alloc_table(struct its_baser *baser, size_t size)
52 {
53 unsigned long order = get_order(size >> PAGE_SHIFT);
54 void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8;
55 u64 val = readq(reg_addr);
56
57 baser->table_addr = alloc_pages(order);
58
59 val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID;
60
61 writeq(val, reg_addr);
62 }
63
64 /*
65 * init_cmd_queue - Allocate the command queue and initialize
66 * CBASER, CWRITER
67 */
its_cmd_queue_init(void)68 static void its_cmd_queue_init(void)
69 {
70 unsigned long order = get_order(SZ_64K >> PAGE_SHIFT);
71 u64 cbaser;
72
73 its_data.cmd_base = alloc_pages(order);
74
75 cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID;
76
77 writeq(cbaser, its_data.base + GITS_CBASER);
78
79 its_data.cmd_write = its_data.cmd_base;
80 writeq(0, its_data.base + GITS_CWRITER);
81 }
82
its_init(void)83 void its_init(void)
84 {
85 if (!its_data.base)
86 return;
87
88 its_parse_typer();
89
90 assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser));
91 assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser));
92
93 its_baser_alloc_table(&its_data.device_baser, SZ_64K);
94 its_baser_alloc_table(&its_data.coll_baser, SZ_64K);
95
96 its_cmd_queue_init();
97 }
98
99 /* must be called after gicv3_enable_defaults */
its_enable_defaults(void)100 void its_enable_defaults(void)
101 {
102 int cpu;
103
104 /* Allocate LPI config and pending tables */
105 gicv3_lpi_alloc_tables();
106
107 for_each_online_cpu(cpu)
108 gicv3_lpi_rdist_enable(cpu);
109
110 writel(GITS_CTLR_ENABLE, its_data.base + GITS_CTLR);
111 }
112
its_create_device(u32 device_id,int nr_ites)113 struct its_device *its_create_device(u32 device_id, int nr_ites)
114 {
115 struct its_device *new;
116 unsigned long n;
117
118 assert(its_data.nr_devices < GITS_MAX_DEVICES);
119
120 new = &its_data.devices[its_data.nr_devices];
121
122 new->device_id = device_id;
123 new->nr_ites = nr_ites;
124
125 n = (its_data.typer.ite_size * nr_ites) >> PAGE_SHIFT;
126 new->itt = alloc_pages(get_order(n));
127
128 its_data.nr_devices++;
129 return new;
130 }
131
its_create_collection(u16 col_id,u32 pe)132 struct its_collection *its_create_collection(u16 col_id, u32 pe)
133 {
134 struct its_collection *new;
135
136 assert(its_data.nr_collections < GITS_MAX_COLLECTIONS);
137
138 new = &its_data.collections[its_data.nr_collections];
139
140 new->col_id = col_id;
141
142 if (its_data.typer.pta)
143 new->target_address = (u64)gicv3_data.redist_base[pe];
144 else
145 new->target_address = pe << 16;
146
147 its_data.nr_collections++;
148 return new;
149 }
150
its_get_device(u32 id)151 struct its_device *its_get_device(u32 id)
152 {
153 int i;
154
155 for (i = 0; i < GITS_MAX_DEVICES; i++) {
156 if (its_data.devices[i].device_id == id)
157 return &its_data.devices[i];
158 }
159 assert(0);
160 }
161
its_get_collection(u32 id)162 struct its_collection *its_get_collection(u32 id)
163 {
164 int i;
165
166 for (i = 0; i < GITS_MAX_COLLECTIONS; i++) {
167 if (its_data.collections[i].col_id == id)
168 return &its_data.collections[i];
169 }
170 assert(0);
171 }
172