cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

scan.c (14134B)


      1/*
      2 * Broadcom specific AMBA
      3 * Bus scanning
      4 *
      5 * Licensed under the GNU/GPL. See COPYING for details.
      6 */
      7
      8#include "scan.h"
      9#include "bcma_private.h"
     10
     11#include <linux/bcma/bcma.h>
     12#include <linux/bcma/bcma_regs.h>
     13#include <linux/pci.h>
     14#include <linux/io.h>
     15#include <linux/dma-mapping.h>
     16#include <linux/slab.h>
     17
     18struct bcma_device_id_name {
     19	u16 id;
     20	const char *name;
     21};
     22
     23static const struct bcma_device_id_name bcma_arm_device_names[] = {
     24	{ BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" },
     25	{ BCMA_CORE_ARM_1176, "ARM 1176" },
     26	{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
     27	{ BCMA_CORE_ARM_CM3, "ARM CM3" },
     28};
     29
     30static const struct bcma_device_id_name bcma_bcm_device_names[] = {
     31	{ BCMA_CORE_OOB_ROUTER, "OOB Router" },
     32	{ BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" },
     33	{ BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" },
     34	{ BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" },
     35	{ BCMA_CORE_NS_PCIEG2, "PCIe Gen 2" },
     36	{ BCMA_CORE_NS_DMA, "DMA" },
     37	{ BCMA_CORE_NS_SDIO3, "SDIO3" },
     38	{ BCMA_CORE_NS_USB20, "USB 2.0" },
     39	{ BCMA_CORE_NS_USB30, "USB 3.0" },
     40	{ BCMA_CORE_NS_A9JTAG, "ARM Cortex A9 JTAG" },
     41	{ BCMA_CORE_NS_DDR23, "Denali DDR2/DDR3 memory controller" },
     42	{ BCMA_CORE_NS_ROM, "ROM" },
     43	{ BCMA_CORE_NS_NAND, "NAND flash controller" },
     44	{ BCMA_CORE_NS_QSPI, "SPI flash controller" },
     45	{ BCMA_CORE_NS_CHIPCOMMON_B, "Chipcommon B" },
     46	{ BCMA_CORE_ARMCA9, "ARM Cortex A9 core (ihost)" },
     47	{ BCMA_CORE_AMEMC, "AMEMC (DDR)" },
     48	{ BCMA_CORE_ALTA, "ALTA (I2S)" },
     49	{ BCMA_CORE_INVALID, "Invalid" },
     50	{ BCMA_CORE_CHIPCOMMON, "ChipCommon" },
     51	{ BCMA_CORE_ILINE20, "ILine 20" },
     52	{ BCMA_CORE_SRAM, "SRAM" },
     53	{ BCMA_CORE_SDRAM, "SDRAM" },
     54	{ BCMA_CORE_PCI, "PCI" },
     55	{ BCMA_CORE_ETHERNET, "Fast Ethernet" },
     56	{ BCMA_CORE_V90, "V90" },
     57	{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
     58	{ BCMA_CORE_ADSL, "ADSL" },
     59	{ BCMA_CORE_ILINE100, "ILine 100" },
     60	{ BCMA_CORE_IPSEC, "IPSEC" },
     61	{ BCMA_CORE_UTOPIA, "UTOPIA" },
     62	{ BCMA_CORE_PCMCIA, "PCMCIA" },
     63	{ BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
     64	{ BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
     65	{ BCMA_CORE_OFDM, "OFDM" },
     66	{ BCMA_CORE_EXTIF, "EXTIF" },
     67	{ BCMA_CORE_80211, "IEEE 802.11" },
     68	{ BCMA_CORE_PHY_A, "PHY A" },
     69	{ BCMA_CORE_PHY_B, "PHY B" },
     70	{ BCMA_CORE_PHY_G, "PHY G" },
     71	{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
     72	{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
     73	{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
     74	{ BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
     75	{ BCMA_CORE_SDIO_HOST, "SDIO Host" },
     76	{ BCMA_CORE_ROBOSWITCH, "Roboswitch" },
     77	{ BCMA_CORE_PARA_ATA, "PATA" },
     78	{ BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
     79	{ BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
     80	{ BCMA_CORE_PCIE, "PCIe" },
     81	{ BCMA_CORE_PHY_N, "PHY N" },
     82	{ BCMA_CORE_SRAM_CTL, "SRAM Controller" },
     83	{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
     84	{ BCMA_CORE_PHY_LP, "PHY LP" },
     85	{ BCMA_CORE_PMU, "PMU" },
     86	{ BCMA_CORE_PHY_SSN, "PHY SSN" },
     87	{ BCMA_CORE_SDIO_DEV, "SDIO Device" },
     88	{ BCMA_CORE_PHY_HT, "PHY HT" },
     89	{ BCMA_CORE_MAC_GBIT, "GBit MAC" },
     90	{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
     91	{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
     92	{ BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
     93	{ BCMA_CORE_SHARED_COMMON, "Common Shared" },
     94	{ BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
     95	{ BCMA_CORE_SPI_HOST, "SPI Host" },
     96	{ BCMA_CORE_I2S, "I2S" },
     97	{ BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
     98	{ BCMA_CORE_SHIM, "SHIM" },
     99	{ BCMA_CORE_PCIE2, "PCIe Gen2" },
    100	{ BCMA_CORE_ARM_CR4, "ARM CR4" },
    101	{ BCMA_CORE_GCI, "GCI" },
    102	{ BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
    103	{ BCMA_CORE_ARM_CA7, "ARM CA7" },
    104	{ BCMA_CORE_DEFAULT, "Default" },
    105};
    106
    107static const struct bcma_device_id_name bcma_mips_device_names[] = {
    108	{ BCMA_CORE_MIPS, "MIPS" },
    109	{ BCMA_CORE_MIPS_3302, "MIPS 3302" },
    110	{ BCMA_CORE_MIPS_74K, "MIPS 74K" },
    111};
    112
    113static const char *bcma_device_name(const struct bcma_device_id *id)
    114{
    115	const struct bcma_device_id_name *names;
    116	int size, i;
    117
    118	/* search manufacturer specific names */
    119	switch (id->manuf) {
    120	case BCMA_MANUF_ARM:
    121		names = bcma_arm_device_names;
    122		size = ARRAY_SIZE(bcma_arm_device_names);
    123		break;
    124	case BCMA_MANUF_BCM:
    125		names = bcma_bcm_device_names;
    126		size = ARRAY_SIZE(bcma_bcm_device_names);
    127		break;
    128	case BCMA_MANUF_MIPS:
    129		names = bcma_mips_device_names;
    130		size = ARRAY_SIZE(bcma_mips_device_names);
    131		break;
    132	default:
    133		return "UNKNOWN";
    134	}
    135
    136	for (i = 0; i < size; i++) {
    137		if (names[i].id == id->id)
    138			return names[i].name;
    139	}
    140
    141	return "UNKNOWN";
    142}
    143
    144static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset)
    145{
    146	return readl(bus->mmio + offset);
    147}
    148
    149static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
    150{
    151	if (bus->hosttype == BCMA_HOSTTYPE_PCI)
    152		pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
    153				       addr);
    154}
    155
    156static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
    157{
    158	u32 ent = readl(*eromptr);
    159	(*eromptr)++;
    160	return ent;
    161}
    162
    163static void bcma_erom_push_ent(u32 __iomem **eromptr)
    164{
    165	(*eromptr)--;
    166}
    167
    168static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 __iomem **eromptr)
    169{
    170	u32 ent = bcma_erom_get_ent(bus, eromptr);
    171	if (!(ent & SCAN_ER_VALID))
    172		return -ENOENT;
    173	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
    174		return -ENOENT;
    175	return ent;
    176}
    177
    178static bool bcma_erom_is_end(struct bcma_bus *bus, u32 __iomem **eromptr)
    179{
    180	u32 ent = bcma_erom_get_ent(bus, eromptr);
    181	bcma_erom_push_ent(eromptr);
    182	return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
    183}
    184
    185static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 __iomem **eromptr)
    186{
    187	u32 ent = bcma_erom_get_ent(bus, eromptr);
    188	bcma_erom_push_ent(eromptr);
    189	return (((ent & SCAN_ER_VALID)) &&
    190		((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
    191		((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
    192}
    193
    194static void bcma_erom_skip_component(struct bcma_bus *bus, u32 __iomem **eromptr)
    195{
    196	u32 ent;
    197	while (1) {
    198		ent = bcma_erom_get_ent(bus, eromptr);
    199		if ((ent & SCAN_ER_VALID) &&
    200		    ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
    201			break;
    202		if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
    203			break;
    204	}
    205	bcma_erom_push_ent(eromptr);
    206}
    207
    208static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 __iomem **eromptr)
    209{
    210	u32 ent = bcma_erom_get_ent(bus, eromptr);
    211	if (!(ent & SCAN_ER_VALID))
    212		return -ENOENT;
    213	if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
    214		return -ENOENT;
    215	return ent;
    216}
    217
    218static u32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 __iomem **eromptr,
    219				  u32 type, u8 port)
    220{
    221	u32 addrl;
    222	u32 size;
    223
    224	u32 ent = bcma_erom_get_ent(bus, eromptr);
    225	if ((!(ent & SCAN_ER_VALID)) ||
    226	    ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
    227	    ((ent & SCAN_ADDR_TYPE) != type) ||
    228	    (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
    229		bcma_erom_push_ent(eromptr);
    230		return (u32)-EINVAL;
    231	}
    232
    233	addrl = ent & SCAN_ADDR_ADDR;
    234	if (ent & SCAN_ADDR_AG32)
    235		bcma_erom_get_ent(bus, eromptr);
    236
    237	if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
    238		size = bcma_erom_get_ent(bus, eromptr);
    239		if (size & SCAN_SIZE_SG32)
    240			bcma_erom_get_ent(bus, eromptr);
    241	}
    242
    243	return addrl;
    244}
    245
    246static struct bcma_device *bcma_find_core_by_index(struct bcma_bus *bus,
    247						   u16 index)
    248{
    249	struct bcma_device *core;
    250
    251	list_for_each_entry(core, &bus->cores, list) {
    252		if (core->core_index == index)
    253			return core;
    254	}
    255	return NULL;
    256}
    257
    258static struct bcma_device *bcma_find_core_reverse(struct bcma_bus *bus, u16 coreid)
    259{
    260	struct bcma_device *core;
    261
    262	list_for_each_entry_reverse(core, &bus->cores, list) {
    263		if (core->id.id == coreid)
    264			return core;
    265	}
    266	return NULL;
    267}
    268
    269#define IS_ERR_VALUE_U32(x) ((x) >= (u32)-MAX_ERRNO)
    270
    271static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
    272			      struct bcma_device_id *match, int core_num,
    273			      struct bcma_device *core)
    274{
    275	u32 tmp;
    276	u8 i, j, k;
    277	s32 cia, cib;
    278	u8 ports[2], wrappers[2];
    279
    280	/* get CIs */
    281	cia = bcma_erom_get_ci(bus, eromptr);
    282	if (cia < 0) {
    283		bcma_erom_push_ent(eromptr);
    284		if (bcma_erom_is_end(bus, eromptr))
    285			return -ESPIPE;
    286		return -EILSEQ;
    287	}
    288	cib = bcma_erom_get_ci(bus, eromptr);
    289	if (cib < 0)
    290		return -EILSEQ;
    291
    292	/* parse CIs */
    293	core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
    294	core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
    295	core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
    296	ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
    297	ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
    298	wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
    299	wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
    300	core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
    301
    302	if (((core->id.manuf == BCMA_MANUF_ARM) &&
    303	     (core->id.id == 0xFFF)) ||
    304	    (ports[1] == 0)) {
    305		bcma_erom_skip_component(bus, eromptr);
    306		return -ENXIO;
    307	}
    308
    309	/* check if component is a core at all */
    310	if (wrappers[0] + wrappers[1] == 0) {
    311		/* Some specific cores don't need wrappers */
    312		switch (core->id.id) {
    313		case BCMA_CORE_4706_MAC_GBIT_COMMON:
    314		case BCMA_CORE_NS_CHIPCOMMON_B:
    315		case BCMA_CORE_PMU:
    316		case BCMA_CORE_GCI:
    317		/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
    318			break;
    319		default:
    320			bcma_erom_skip_component(bus, eromptr);
    321			return -ENXIO;
    322		}
    323	}
    324
    325	if (bcma_erom_is_bridge(bus, eromptr)) {
    326		bcma_erom_skip_component(bus, eromptr);
    327		return -ENXIO;
    328	}
    329
    330	if (bcma_find_core_by_index(bus, core_num)) {
    331		bcma_erom_skip_component(bus, eromptr);
    332		return -ENODEV;
    333	}
    334
    335	if (match && ((match->manuf != BCMA_ANY_MANUF &&
    336	      match->manuf != core->id.manuf) ||
    337	     (match->id != BCMA_ANY_ID && match->id != core->id.id) ||
    338	     (match->rev != BCMA_ANY_REV && match->rev != core->id.rev) ||
    339	     (match->class != BCMA_ANY_CLASS && match->class != core->id.class)
    340	    )) {
    341		bcma_erom_skip_component(bus, eromptr);
    342		return -ENODEV;
    343	}
    344
    345	/* get & parse master ports */
    346	for (i = 0; i < ports[0]; i++) {
    347		s32 mst_port_d = bcma_erom_get_mst_port(bus, eromptr);
    348		if (mst_port_d < 0)
    349			return -EILSEQ;
    350	}
    351
    352	/* First Slave Address Descriptor should be port 0:
    353	 * the main register space for the core
    354	 */
    355	tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
    356	if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
    357		/* Try again to see if it is a bridge */
    358		tmp = bcma_erom_get_addr_desc(bus, eromptr,
    359					      SCAN_ADDR_TYPE_BRIDGE, 0);
    360		if (tmp == 0 || IS_ERR_VALUE_U32(tmp)) {
    361			return -EILSEQ;
    362		} else {
    363			bcma_info(bus, "Bridge found\n");
    364			return -ENXIO;
    365		}
    366	}
    367	core->addr = tmp;
    368
    369	/* get & parse slave ports */
    370	k = 0;
    371	for (i = 0; i < ports[1]; i++) {
    372		for (j = 0; ; j++) {
    373			tmp = bcma_erom_get_addr_desc(bus, eromptr,
    374				SCAN_ADDR_TYPE_SLAVE, i);
    375			if (IS_ERR_VALUE_U32(tmp)) {
    376				/* no more entries for port _i_ */
    377				/* pr_debug("erom: slave port %d "
    378				 * "has %d descriptors\n", i, j); */
    379				break;
    380			} else if (k < ARRAY_SIZE(core->addr_s)) {
    381				core->addr_s[k] = tmp;
    382				k++;
    383			}
    384		}
    385	}
    386
    387	/* get & parse master wrappers */
    388	for (i = 0; i < wrappers[0]; i++) {
    389		for (j = 0; ; j++) {
    390			tmp = bcma_erom_get_addr_desc(bus, eromptr,
    391				SCAN_ADDR_TYPE_MWRAP, i);
    392			if (IS_ERR_VALUE_U32(tmp)) {
    393				/* no more entries for port _i_ */
    394				/* pr_debug("erom: master wrapper %d "
    395				 * "has %d descriptors\n", i, j); */
    396				break;
    397			} else {
    398				if (i == 0 && j == 0)
    399					core->wrap = tmp;
    400			}
    401		}
    402	}
    403
    404	/* get & parse slave wrappers */
    405	for (i = 0; i < wrappers[1]; i++) {
    406		u8 hack = (ports[1] == 1) ? 0 : 1;
    407		for (j = 0; ; j++) {
    408			tmp = bcma_erom_get_addr_desc(bus, eromptr,
    409				SCAN_ADDR_TYPE_SWRAP, i + hack);
    410			if (IS_ERR_VALUE_U32(tmp)) {
    411				/* no more entries for port _i_ */
    412				/* pr_debug("erom: master wrapper %d "
    413				 * has %d descriptors\n", i, j); */
    414				break;
    415			} else {
    416				if (wrappers[0] == 0 && !i && !j)
    417					core->wrap = tmp;
    418			}
    419		}
    420	}
    421	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
    422		core->io_addr = ioremap(core->addr, BCMA_CORE_SIZE);
    423		if (!core->io_addr)
    424			return -ENOMEM;
    425		if (core->wrap) {
    426			core->io_wrap = ioremap(core->wrap,
    427							BCMA_CORE_SIZE);
    428			if (!core->io_wrap) {
    429				iounmap(core->io_addr);
    430				return -ENOMEM;
    431			}
    432		}
    433	}
    434	return 0;
    435}
    436
    437void bcma_detect_chip(struct bcma_bus *bus)
    438{
    439	s32 tmp;
    440	struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
    441	char chip_id[8];
    442
    443	bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
    444
    445	tmp = bcma_scan_read32(bus, BCMA_CC_ID);
    446	chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
    447	chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
    448	chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
    449
    450	snprintf(chip_id, ARRAY_SIZE(chip_id),
    451		 (chipinfo->id > 0x9999) ? "%d" : "0x%04X", chipinfo->id);
    452	bcma_info(bus, "Found chip with id %s, rev 0x%02X and package 0x%02X\n",
    453		  chip_id, chipinfo->rev, chipinfo->pkg);
    454}
    455
    456int bcma_bus_scan(struct bcma_bus *bus)
    457{
    458	u32 erombase;
    459	u32 __iomem *eromptr, *eromend;
    460
    461	int err, core_num = 0;
    462
    463	/* Skip if bus was already scanned (e.g. during early register) */
    464	if (bus->nr_cores)
    465		return 0;
    466
    467	erombase = bcma_scan_read32(bus, BCMA_CC_EROM);
    468	if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
    469		eromptr = ioremap(erombase, BCMA_CORE_SIZE);
    470		if (!eromptr)
    471			return -ENOMEM;
    472	} else {
    473		eromptr = bus->mmio;
    474	}
    475
    476	eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
    477
    478	bcma_scan_switch_core(bus, erombase);
    479
    480	while (eromptr < eromend) {
    481		struct bcma_device *other_core;
    482		struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
    483		if (!core) {
    484			err = -ENOMEM;
    485			goto out;
    486		}
    487		INIT_LIST_HEAD(&core->list);
    488		core->bus = bus;
    489
    490		err = bcma_get_next_core(bus, &eromptr, NULL, core_num, core);
    491		if (err < 0) {
    492			kfree(core);
    493			if (err == -ENODEV) {
    494				core_num++;
    495				continue;
    496			} else if (err == -ENXIO) {
    497				continue;
    498			} else if (err == -ESPIPE) {
    499				break;
    500			}
    501			goto out;
    502		}
    503
    504		core->core_index = core_num++;
    505		bus->nr_cores++;
    506		other_core = bcma_find_core_reverse(bus, core->id.id);
    507		core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
    508		bcma_prepare_core(bus, core);
    509
    510		bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
    511			  core->core_index, bcma_device_name(&core->id),
    512			  core->id.manuf, core->id.id, core->id.rev,
    513			  core->id.class);
    514
    515		list_add_tail(&core->list, &bus->cores);
    516	}
    517
    518	err = 0;
    519out:
    520	if (bus->hosttype == BCMA_HOSTTYPE_SOC)
    521		iounmap(eromptr);
    522
    523	return err;
    524}