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

ip30-xtalk.c (4164B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ip30-xtalk.c - Very basic Crosstalk (XIO) detection support.
      4 *   Copyright (C) 2004-2007 Stanislaw Skowronek <skylark@unaligned.org>
      5 *   Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
      6 *   Copyright (C) 2007, 2014-2016 Joshua Kinard <kumba@gentoo.org>
      7 */
      8
      9#include <linux/init.h>
     10#include <linux/kernel.h>
     11#include <linux/platform_device.h>
     12#include <linux/platform_data/sgi-w1.h>
     13#include <linux/platform_data/xtalk-bridge.h>
     14
     15#include <asm/xtalk/xwidget.h>
     16#include <asm/pci/bridge.h>
     17
     18#define IP30_SWIN_BASE(widget) \
     19		(0x0000000010000000 | (((unsigned long)(widget)) << 24))
     20
     21#define IP30_RAW_SWIN_BASE(widget)	(IO_BASE + IP30_SWIN_BASE(widget))
     22
     23#define IP30_SWIN_SIZE		(1 << 24)
     24
     25#define IP30_WIDGET_XBOW        _AC(0x0, UL)    /* XBow is always 0 */
     26#define IP30_WIDGET_HEART       _AC(0x8, UL)    /* HEART is always 8 */
     27#define IP30_WIDGET_PCI_BASE    _AC(0xf, UL)    /* BaseIO PCI is always 15 */
     28
     29#define XTALK_NODEV             0xffffffff
     30
     31#define XBOW_REG_LINK_STAT_0    0x114
     32#define XBOW_REG_LINK_BLK_SIZE  0x40
     33#define XBOW_REG_LINK_ALIVE     0x80000000
     34
     35#define HEART_INTR_ADDR		0x00000080
     36
     37#define xtalk_read	__raw_readl
     38
     39static void bridge_platform_create(int widget, int masterwid)
     40{
     41	struct xtalk_bridge_platform_data *bd;
     42	struct sgi_w1_platform_data *wd;
     43	struct platform_device *pdev;
     44	struct resource w1_res;
     45
     46	wd = kzalloc(sizeof(*wd), GFP_KERNEL);
     47	if (!wd)
     48		goto no_mem;
     49
     50	snprintf(wd->dev_id, sizeof(wd->dev_id), "bridge-%012lx",
     51		 IP30_SWIN_BASE(widget));
     52
     53	memset(&w1_res, 0, sizeof(w1_res));
     54	w1_res.start = IP30_SWIN_BASE(widget) +
     55				offsetof(struct bridge_regs, b_nic);
     56	w1_res.end = w1_res.start + 3;
     57	w1_res.flags = IORESOURCE_MEM;
     58
     59	pdev = platform_device_alloc("sgi_w1", PLATFORM_DEVID_AUTO);
     60	if (!pdev) {
     61		kfree(wd);
     62		goto no_mem;
     63	}
     64	platform_device_add_resources(pdev, &w1_res, 1);
     65	platform_device_add_data(pdev, wd, sizeof(*wd));
     66	/* platform_device_add_data() duplicates the data */
     67	kfree(wd);
     68	platform_device_add(pdev);
     69
     70	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
     71	if (!bd)
     72		goto no_mem;
     73	pdev = platform_device_alloc("xtalk-bridge", PLATFORM_DEVID_AUTO);
     74	if (!pdev) {
     75		kfree(bd);
     76		goto no_mem;
     77	}
     78
     79	bd->bridge_addr	= IP30_RAW_SWIN_BASE(widget);
     80	bd->intr_addr	= HEART_INTR_ADDR;
     81	bd->nasid	= 0;
     82	bd->masterwid	= masterwid;
     83
     84	bd->mem.name	= "Bridge PCI MEM";
     85	bd->mem.start	= IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
     86	bd->mem.end	= IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
     87	bd->mem.flags	= IORESOURCE_MEM;
     88	bd->mem_offset	= IP30_SWIN_BASE(widget);
     89
     90	bd->io.name	= "Bridge PCI IO";
     91	bd->io.start	= IP30_SWIN_BASE(widget) + BRIDGE_DEVIO0;
     92	bd->io.end	= IP30_SWIN_BASE(widget) + IP30_SWIN_SIZE - 1;
     93	bd->io.flags	= IORESOURCE_IO;
     94	bd->io_offset	= IP30_SWIN_BASE(widget);
     95
     96	platform_device_add_data(pdev, bd, sizeof(*bd));
     97	/* platform_device_add_data() duplicates the data */
     98	kfree(bd);
     99	platform_device_add(pdev);
    100	pr_info("xtalk:%x bridge widget\n", widget);
    101	return;
    102
    103no_mem:
    104	pr_warn("xtalk:%x bridge create out of memory\n", widget);
    105}
    106
    107static unsigned int __init xbow_widget_active(s8 wid)
    108{
    109	unsigned int link_stat;
    110
    111	link_stat = xtalk_read((void *)(IP30_RAW_SWIN_BASE(IP30_WIDGET_XBOW) +
    112					XBOW_REG_LINK_STAT_0 +
    113					XBOW_REG_LINK_BLK_SIZE *
    114					(wid - 8)));
    115
    116	return (link_stat & XBOW_REG_LINK_ALIVE) ? 1 : 0;
    117}
    118
    119static void __init xtalk_init_widget(s8 wid, s8 masterwid)
    120{
    121	xwidget_part_num_t partnum;
    122	widgetreg_t widget_id;
    123
    124	if (!xbow_widget_active(wid))
    125		return;
    126
    127	widget_id = xtalk_read((void *)(IP30_RAW_SWIN_BASE(wid) + WIDGET_ID));
    128
    129	partnum = XWIDGET_PART_NUM(widget_id);
    130
    131	switch (partnum) {
    132	case BRIDGE_WIDGET_PART_NUM:
    133	case XBRIDGE_WIDGET_PART_NUM:
    134		bridge_platform_create(wid, masterwid);
    135		break;
    136	default:
    137		pr_info("xtalk:%x unknown widget (0x%x)\n", wid, partnum);
    138		break;
    139	}
    140}
    141
    142static int __init ip30_xtalk_init(void)
    143{
    144	int i;
    145
    146	/*
    147	 * Walk widget IDs backwards so that BaseIO is probed first.  This
    148	 * ensures that the BaseIO IOC3 is always detected as eth0.
    149	 */
    150	for (i = IP30_WIDGET_PCI_BASE; i > IP30_WIDGET_HEART; i--)
    151		xtalk_init_widget(i, IP30_WIDGET_HEART);
    152
    153	return 0;
    154}
    155
    156arch_initcall(ip30_xtalk_init);