1ba74b106SEric Auger /* 2ba74b106SEric Auger * Copyright (C) 2020, Red Hat Inc, Eric Auger <eric.auger@redhat.com> 3ba74b106SEric Auger * 4ba74b106SEric Auger * This work is licensed under the terms of the GNU LGPL, version 2. 5ba74b106SEric Auger */ 6ba74b106SEric Auger #include <asm/gic.h> 7ba74b106SEric Auger #include <alloc_page.h> 8ba74b106SEric Auger 9ba74b106SEric Auger void its_parse_typer(void) 10ba74b106SEric Auger { 11ba74b106SEric Auger u64 typer = readq(gicv3_its_base() + GITS_TYPER); 12ba74b106SEric Auger struct its_typer *t = &its_data.typer; 13ba74b106SEric Auger 14ba74b106SEric Auger t->ite_size = ((typer & GITS_TYPER_ITT_ENTRY_SIZE) >> GITS_TYPER_ITT_ENTRY_SIZE_SHIFT) + 1; 15ba74b106SEric Auger t->pta = typer & GITS_TYPER_PTA; 16ba74b106SEric Auger t->eventid_bits = ((typer & GITS_TYPER_IDBITS) >> GITS_TYPER_IDBITS_SHIFT) + 1; 17ba74b106SEric Auger t->deviceid_bits = ((typer & GITS_TYPER_DEVBITS) >> GITS_TYPER_DEVBITS_SHIFT) + 1; 18ba74b106SEric Auger 19ba74b106SEric Auger if (typer & GITS_TYPER_CIL) 20ba74b106SEric Auger t->collid_bits = ((typer & GITS_TYPER_CIDBITS) >> GITS_TYPER_CIDBITS_SHIFT) + 1; 21ba74b106SEric Auger else 22ba74b106SEric Auger t->collid_bits = 16; 23ba74b106SEric Auger 24ba74b106SEric Auger t->virt_lpi = typer & GITS_TYPER_VLPIS; 25ba74b106SEric Auger t->phys_lpi = typer & GITS_TYPER_PLPIS; 26ba74b106SEric Auger } 27ba74b106SEric Auger 28ba74b106SEric Auger int its_baser_lookup(int type, struct its_baser *baser) 29ba74b106SEric Auger { 30ba74b106SEric Auger int i; 31ba74b106SEric Auger 32ba74b106SEric Auger for (i = 0; i < GITS_BASER_NR_REGS; i++) { 33ba74b106SEric Auger void *reg_addr = gicv3_its_base() + GITS_BASER + i * 8; 34ba74b106SEric Auger u64 val = readq(reg_addr); 35ba74b106SEric Auger 36ba74b106SEric Auger if (GITS_BASER_TYPE(val) == type) { 37ba74b106SEric Auger assert((val & GITS_BASER_PAGE_SIZE_MASK) == GITS_BASER_PAGE_SIZE_64K); 38ba74b106SEric Auger baser->esz = GITS_BASER_ENTRY_SIZE(val); 39ba74b106SEric Auger baser->indirect = val & GITS_BASER_INDIRECT; 40ba74b106SEric Auger baser->index = i; 41ba74b106SEric Auger return 0; 42ba74b106SEric Auger } 43ba74b106SEric Auger } 44ba74b106SEric Auger return -1; 45ba74b106SEric Auger } 46ba74b106SEric Auger 47ba74b106SEric Auger /* 48ba74b106SEric Auger * Allocate the BASER table (a single page of size @baser->psz) 49ba74b106SEric Auger * and set the BASER valid 50ba74b106SEric Auger */ 51ba74b106SEric Auger static void its_baser_alloc_table(struct its_baser *baser, size_t size) 52ba74b106SEric Auger { 53ba74b106SEric Auger unsigned long order = get_order(size >> PAGE_SHIFT); 54ba74b106SEric Auger void *reg_addr = gicv3_its_base() + GITS_BASER + baser->index * 8; 55ba74b106SEric Auger u64 val = readq(reg_addr); 56ba74b106SEric Auger 57ba74b106SEric Auger baser->table_addr = alloc_pages(order); 58ba74b106SEric Auger 59ba74b106SEric Auger val |= virt_to_phys(baser->table_addr) | GITS_BASER_VALID; 60ba74b106SEric Auger 61ba74b106SEric Auger writeq(val, reg_addr); 62ba74b106SEric Auger } 63ba74b106SEric Auger 64ba74b106SEric Auger /* 65ba74b106SEric Auger * init_cmd_queue - Allocate the command queue and initialize 66ba74b106SEric Auger * CBASER, CWRITER 67ba74b106SEric Auger */ 68ba74b106SEric Auger static void its_cmd_queue_init(void) 69ba74b106SEric Auger { 70ba74b106SEric Auger unsigned long order = get_order(SZ_64K >> PAGE_SHIFT); 71ba74b106SEric Auger u64 cbaser; 72ba74b106SEric Auger 73ba74b106SEric Auger its_data.cmd_base = alloc_pages(order); 74ba74b106SEric Auger 75ba74b106SEric Auger cbaser = virt_to_phys(its_data.cmd_base) | (SZ_64K / SZ_4K - 1) | GITS_CBASER_VALID; 76ba74b106SEric Auger 77ba74b106SEric Auger writeq(cbaser, its_data.base + GITS_CBASER); 78ba74b106SEric Auger 79ba74b106SEric Auger its_data.cmd_write = its_data.cmd_base; 80ba74b106SEric Auger writeq(0, its_data.base + GITS_CWRITER); 81ba74b106SEric Auger } 82ba74b106SEric Auger 83ba74b106SEric Auger void its_init(void) 84ba74b106SEric Auger { 85ba74b106SEric Auger if (!its_data.base) 86ba74b106SEric Auger return; 87ba74b106SEric Auger 88ba74b106SEric Auger its_parse_typer(); 89ba74b106SEric Auger 90ba74b106SEric Auger assert(!its_baser_lookup(GITS_BASER_TYPE_DEVICE, &its_data.device_baser)); 91ba74b106SEric Auger assert(!its_baser_lookup(GITS_BASER_TYPE_COLLECTION, &its_data.coll_baser)); 92ba74b106SEric Auger 93ba74b106SEric Auger its_baser_alloc_table(&its_data.device_baser, SZ_64K); 94ba74b106SEric Auger its_baser_alloc_table(&its_data.coll_baser, SZ_64K); 95ba74b106SEric Auger 96ba74b106SEric Auger its_cmd_queue_init(); 97ba74b106SEric Auger } 98ba74b106SEric Auger 9980374e12SEric Auger /* must be called after gicv3_enable_defaults */ 10080374e12SEric Auger void its_enable_defaults(void) 10180374e12SEric Auger { 10280374e12SEric Auger int cpu; 10380374e12SEric Auger 10480374e12SEric Auger /* Allocate LPI config and pending tables */ 10580374e12SEric Auger gicv3_lpi_alloc_tables(); 10680374e12SEric Auger 10780374e12SEric Auger for_each_present_cpu(cpu) 10880374e12SEric Auger gicv3_lpi_rdist_enable(cpu); 10980374e12SEric Auger 11080374e12SEric Auger writel(GITS_CTLR_ENABLE, its_data.base + GITS_CTLR); 11180374e12SEric Auger } 1120c87bc34SEric Auger 1130c87bc34SEric Auger struct its_device *its_create_device(u32 device_id, int nr_ites) 1140c87bc34SEric Auger { 1150c87bc34SEric Auger struct its_device *new; 1160c87bc34SEric Auger unsigned long n; 1170c87bc34SEric Auger 1180c87bc34SEric Auger assert(its_data.nr_devices < GITS_MAX_DEVICES); 1190c87bc34SEric Auger 1200c87bc34SEric Auger new = &its_data.devices[its_data.nr_devices]; 1210c87bc34SEric Auger 1220c87bc34SEric Auger new->device_id = device_id; 1230c87bc34SEric Auger new->nr_ites = nr_ites; 1240c87bc34SEric Auger 1250c87bc34SEric Auger n = (its_data.typer.ite_size * nr_ites) >> PAGE_SHIFT; 1260c87bc34SEric Auger new->itt = alloc_pages(get_order(n)); 1270c87bc34SEric Auger 1280c87bc34SEric Auger its_data.nr_devices++; 1290c87bc34SEric Auger return new; 1300c87bc34SEric Auger } 1310c87bc34SEric Auger 1320c87bc34SEric Auger struct its_collection *its_create_collection(u16 col_id, u32 pe) 1330c87bc34SEric Auger { 1340c87bc34SEric Auger struct its_collection *new; 1350c87bc34SEric Auger 1360c87bc34SEric Auger assert(its_data.nr_collections < GITS_MAX_COLLECTIONS); 1370c87bc34SEric Auger 1380c87bc34SEric Auger new = &its_data.collections[its_data.nr_collections]; 1390c87bc34SEric Auger 1400c87bc34SEric Auger new->col_id = col_id; 1410c87bc34SEric Auger 1420c87bc34SEric Auger if (its_data.typer.pta) 1430c87bc34SEric Auger new->target_address = (u64)gicv3_data.redist_base[pe]; 1440c87bc34SEric Auger else 1450c87bc34SEric Auger new->target_address = pe << 16; 1460c87bc34SEric Auger 1470c87bc34SEric Auger its_data.nr_collections++; 1480c87bc34SEric Auger return new; 1490c87bc34SEric Auger } 150*64260a5fSEric Auger 151*64260a5fSEric Auger struct its_device *its_get_device(u32 id) 152*64260a5fSEric Auger { 153*64260a5fSEric Auger int i; 154*64260a5fSEric Auger 155*64260a5fSEric Auger for (i = 0; i < GITS_MAX_DEVICES; i++) { 156*64260a5fSEric Auger if (its_data.devices[i].device_id == id) 157*64260a5fSEric Auger return &its_data.devices[i]; 158*64260a5fSEric Auger } 159*64260a5fSEric Auger assert(0); 160*64260a5fSEric Auger } 161*64260a5fSEric Auger 162*64260a5fSEric Auger struct its_collection *its_get_collection(u32 id) 163*64260a5fSEric Auger { 164*64260a5fSEric Auger int i; 165*64260a5fSEric Auger 166*64260a5fSEric Auger for (i = 0; i < GITS_MAX_COLLECTIONS; i++) { 167*64260a5fSEric Auger if (its_data.collections[i].col_id == id) 168*64260a5fSEric Auger return &its_data.collections[i]; 169*64260a5fSEric Auger } 170*64260a5fSEric Auger assert(0); 171*64260a5fSEric Auger } 172