brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · b5bd10a Raw
364 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2015, 2016 Cavium, Inc.4 */5 6#include <linux/kernel.h>7#include <linux/init.h>8#include <linux/ioport.h>9#include <linux/of_pci.h>10#include <linux/of.h>11#include <linux/pci-ecam.h>12#include <linux/platform_device.h>13 14#if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))15 16static void set_val(u32 v, int where, int size, u32 *val)17{18	int shift = (where & 3) * 8;19 20	pr_debug("set_val %04x: %08x\n", (unsigned int)(where & ~3), v);21	v >>= shift;22	if (size == 1)23		v &= 0xff;24	else if (size == 2)25		v &= 0xffff;26	*val = v;27}28 29static int handle_ea_bar(u32 e0, int bar, struct pci_bus *bus,30			 unsigned int devfn, int where, int size, u32 *val)31{32	void __iomem *addr;33	u32 v;34 35	/* Entries are 16-byte aligned; bits[2,3] select word in entry */36	int where_a = where & 0xc;37 38	if (where_a == 0) {39		set_val(e0, where, size, val);40		return PCIBIOS_SUCCESSFUL;41	}42	if (where_a == 0x4) {43		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */44		if (!addr)45			return PCIBIOS_DEVICE_NOT_FOUND;46 47		v = readl(addr);48		v &= ~0xf;49		v |= 2; /* EA entry-1. Base-L */50		set_val(v, where, size, val);51		return PCIBIOS_SUCCESSFUL;52	}53	if (where_a == 0x8) {54		u32 barl_orig;55		u32 barl_rb;56 57		addr = bus->ops->map_bus(bus, devfn, bar); /* BAR 0 */58		if (!addr)59			return PCIBIOS_DEVICE_NOT_FOUND;60 61		barl_orig = readl(addr + 0);62		writel(0xffffffff, addr + 0);63		barl_rb = readl(addr + 0);64		writel(barl_orig, addr + 0);65		/* zeros in unsettable bits */66		v = ~barl_rb & ~3;67		v |= 0xc; /* EA entry-2. Offset-L */68		set_val(v, where, size, val);69		return PCIBIOS_SUCCESSFUL;70	}71	if (where_a == 0xc) {72		addr = bus->ops->map_bus(bus, devfn, bar + 4); /* BAR 1 */73		if (!addr)74			return PCIBIOS_DEVICE_NOT_FOUND;75 76		v = readl(addr); /* EA entry-3. Base-H */77		set_val(v, where, size, val);78		return PCIBIOS_SUCCESSFUL;79	}80	return PCIBIOS_DEVICE_NOT_FOUND;81}82 83static int thunder_ecam_p2_config_read(struct pci_bus *bus, unsigned int devfn,84				       int where, int size, u32 *val)85{86	struct pci_config_window *cfg = bus->sysdata;87	int where_a = where & ~3;88	void __iomem *addr;89	u32 node_bits;90	u32 v;91 92	/* EA Base[63:32] may be missing some bits ... */93	switch (where_a) {94	case 0xa8:95	case 0xbc:96	case 0xd0:97	case 0xe4:98		break;99	default:100		return pci_generic_config_read(bus, devfn, where, size, val);101	}102 103	addr = bus->ops->map_bus(bus, devfn, where_a);104	if (!addr)105		return PCIBIOS_DEVICE_NOT_FOUND;106 107	v = readl(addr);108 109	/*110	 * Bit 44 of the 64-bit Base must match the same bit in111	 * the config space access window.  Since we are working with112	 * the high-order 32 bits, shift everything down by 32 bits.113	 */114	node_bits = upper_32_bits(cfg->res.start) & (1 << 12);115 116	v |= node_bits;117	set_val(v, where, size, val);118 119	return PCIBIOS_SUCCESSFUL;120}121 122static int thunder_ecam_config_read(struct pci_bus *bus, unsigned int devfn,123				    int where, int size, u32 *val)124{125	u32 v;126	u32 vendor_device;127	u32 class_rev;128	void __iomem *addr;129	int cfg_type;130	int where_a = where & ~3;131 132	addr = bus->ops->map_bus(bus, devfn, 0xc);133	if (!addr)134		return PCIBIOS_DEVICE_NOT_FOUND;135 136	v = readl(addr);137 138	/* Check for non type-00 header */139	cfg_type = (v >> 16) & 0x7f;140 141	addr = bus->ops->map_bus(bus, devfn, 8);142	if (!addr)143		return PCIBIOS_DEVICE_NOT_FOUND;144 145	class_rev = readl(addr);146	if (class_rev == 0xffffffff)147		goto no_emulation;148 149	if ((class_rev & 0xff) >= 8) {150		/* Pass-2 handling */151		if (cfg_type)152			goto no_emulation;153		return thunder_ecam_p2_config_read(bus, devfn, where,154						   size, val);155	}156 157	/*158	 * All BARs have fixed addresses specified by the EA159	 * capability; they must return zero on read.160	 */161	if (cfg_type == 0 &&162	    ((where >= 0x10 && where < 0x2c) ||163	     (where >= 0x1a4 && where < 0x1bc))) {164		/* BAR or SR-IOV BAR */165		*val = 0;166		return PCIBIOS_SUCCESSFUL;167	}168 169	addr = bus->ops->map_bus(bus, devfn, 0);170	if (!addr)171		return PCIBIOS_DEVICE_NOT_FOUND;172 173	vendor_device = readl(addr);174	if (vendor_device == 0xffffffff)175		goto no_emulation;176 177	pr_debug("%04x:%04x - Fix pass#: %08x, where: %03x, devfn: %03x\n",178		 vendor_device & 0xffff, vendor_device >> 16, class_rev,179		 (unsigned int)where, devfn);180 181	/* Check for non type-00 header */182	if (cfg_type == 0) {183		bool has_msix;184		bool is_nic = (vendor_device == 0xa01e177d);185		bool is_tns = (vendor_device == 0xa01f177d);186 187		addr = bus->ops->map_bus(bus, devfn, 0x70);188		if (!addr)189			return PCIBIOS_DEVICE_NOT_FOUND;190 191		/* E_CAP */192		v = readl(addr);193		has_msix = (v & 0xff00) != 0;194 195		if (!has_msix && where_a == 0x70) {196			v |= 0xbc00; /* next capability is EA at 0xbc */197			set_val(v, where, size, val);198			return PCIBIOS_SUCCESSFUL;199		}200		if (where_a == 0xb0) {201			addr = bus->ops->map_bus(bus, devfn, where_a);202			if (!addr)203				return PCIBIOS_DEVICE_NOT_FOUND;204 205			v = readl(addr);206			if (v & 0xff00)207				pr_err("Bad MSIX cap header: %08x\n", v);208			v |= 0xbc00; /* next capability is EA at 0xbc */209			set_val(v, where, size, val);210			return PCIBIOS_SUCCESSFUL;211		}212		if (where_a == 0xbc) {213			if (is_nic)214				v = 0x40014; /* EA last in chain, 4 entries */215			else if (is_tns)216				v = 0x30014; /* EA last in chain, 3 entries */217			else if (has_msix)218				v = 0x20014; /* EA last in chain, 2 entries */219			else220				v = 0x10014; /* EA last in chain, 1 entry */221			set_val(v, where, size, val);222			return PCIBIOS_SUCCESSFUL;223		}224		if (where_a >= 0xc0 && where_a < 0xd0)225			/* EA entry-0. PP=0, BAR0 Size:3 */226			return handle_ea_bar(0x80ff0003,227					     0x10, bus, devfn, where,228					     size, val);229		if (where_a >= 0xd0 && where_a < 0xe0 && has_msix)230			 /* EA entry-1. PP=0, BAR4 Size:3 */231			return handle_ea_bar(0x80ff0043,232					     0x20, bus, devfn, where,233					     size, val);234		if (where_a >= 0xe0 && where_a < 0xf0 && is_tns)235			/* EA entry-2. PP=0, BAR2, Size:3 */236			return handle_ea_bar(0x80ff0023,237					     0x18, bus, devfn, where,238					     size, val);239		if (where_a >= 0xe0 && where_a < 0xf0 && is_nic)240			/* EA entry-2. PP=4, VF_BAR0 (9), Size:3 */241			return handle_ea_bar(0x80ff0493,242					     0x1a4, bus, devfn, where,243					     size, val);244		if (where_a >= 0xf0 && where_a < 0x100 && is_nic)245			/* EA entry-3. PP=4, VF_BAR4 (d), Size:3 */246			return handle_ea_bar(0x80ff04d3,247					     0x1b4, bus, devfn, where,248					     size, val);249	} else if (cfg_type == 1) {250		bool is_rsl_bridge = devfn == 0x08;251		bool is_rad_bridge = devfn == 0xa0;252		bool is_zip_bridge = devfn == 0xa8;253		bool is_dfa_bridge = devfn == 0xb0;254		bool is_nic_bridge = devfn == 0x10;255 256		if (where_a == 0x70) {257			addr = bus->ops->map_bus(bus, devfn, where_a);258			if (!addr)259				return PCIBIOS_DEVICE_NOT_FOUND;260 261			v = readl(addr);262			if (v & 0xff00)263				pr_err("Bad PCIe cap header: %08x\n", v);264			v |= 0xbc00; /* next capability is EA at 0xbc */265			set_val(v, where, size, val);266			return PCIBIOS_SUCCESSFUL;267		}268		if (where_a == 0xbc) {269			if (is_nic_bridge)270				v = 0x10014; /* EA last in chain, 1 entry */271			else272				v = 0x00014; /* EA last in chain, no entries */273			set_val(v, where, size, val);274			return PCIBIOS_SUCCESSFUL;275		}276		if (where_a == 0xc0) {277			if (is_rsl_bridge || is_nic_bridge)278				v = 0x0101; /* subordinate:secondary = 1:1 */279			else if (is_rad_bridge)280				v = 0x0202; /* subordinate:secondary = 2:2 */281			else if (is_zip_bridge)282				v = 0x0303; /* subordinate:secondary = 3:3 */283			else if (is_dfa_bridge)284				v = 0x0404; /* subordinate:secondary = 4:4 */285			set_val(v, where, size, val);286			return PCIBIOS_SUCCESSFUL;287		}288		if (where_a == 0xc4 && is_nic_bridge) {289			/* Enabled, not-Write, SP=ff, PP=05, BEI=6, ES=4 */290			v = 0x80ff0564;291			set_val(v, where, size, val);292			return PCIBIOS_SUCCESSFUL;293		}294		if (where_a == 0xc8 && is_nic_bridge) {295			v = 0x00000002; /* Base-L 64-bit */296			set_val(v, where, size, val);297			return PCIBIOS_SUCCESSFUL;298		}299		if (where_a == 0xcc && is_nic_bridge) {300			v = 0xfffffffe; /* MaxOffset-L 64-bit */301			set_val(v, where, size, val);302			return PCIBIOS_SUCCESSFUL;303		}304		if (where_a == 0xd0 && is_nic_bridge) {305			v = 0x00008430; /* NIC Base-H */306			set_val(v, where, size, val);307			return PCIBIOS_SUCCESSFUL;308		}309		if (where_a == 0xd4 && is_nic_bridge) {310			v = 0x0000000f; /* MaxOffset-H */311			set_val(v, where, size, val);312			return PCIBIOS_SUCCESSFUL;313		}314	}315no_emulation:316	return pci_generic_config_read(bus, devfn, where, size, val);317}318 319static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn,320				     int where, int size, u32 val)321{322	/*323	 * All BARs have fixed addresses; ignore BAR writes so they324	 * don't get corrupted.325	 */326	if ((where >= 0x10 && where < 0x2c) ||327	    (where >= 0x1a4 && where < 0x1bc))328		/* BAR or SR-IOV BAR */329		return PCIBIOS_SUCCESSFUL;330 331	return pci_generic_config_write(bus, devfn, where, size, val);332}333 334const struct pci_ecam_ops pci_thunder_ecam_ops = {335	.pci_ops	= {336		.map_bus        = pci_ecam_map_bus,337		.read           = thunder_ecam_config_read,338		.write          = thunder_ecam_config_write,339	}340};341 342#ifdef CONFIG_PCI_HOST_THUNDER_ECAM343 344static const struct of_device_id thunder_ecam_of_match[] = {345	{346		.compatible = "cavium,pci-host-thunder-ecam",347		.data = &pci_thunder_ecam_ops,348	},349	{ },350};351 352static struct platform_driver thunder_ecam_driver = {353	.driver = {354		.name = KBUILD_MODNAME,355		.of_match_table = thunder_ecam_of_match,356		.suppress_bind_attrs = true,357	},358	.probe = pci_host_common_probe,359};360builtin_platform_driver(thunder_ecam_driver);361 362#endif363#endif364