brintos

brintos / linux-shallow public Read only

0
0
Text · 11.9 KiB · 6085a14 Raw
455 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  This file contains quirk handling code for PnP devices4 *  Some devices do not report all their resources, and need to have extra5 *  resources added. This is most easily accomplished at initialisation time6 *  when building up the resource structure for the first time.7 *8 *  Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk>9 *  Copyright (C) 2008 Hewlett-Packard Development Company, L.P.10 *	Bjorn Helgaas <bjorn.helgaas@hp.com>11 *12 *  Heavily based on PCI quirks handling which is13 *14 *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>15 */16 17#include <linux/types.h>18#include <linux/kernel.h>19#include <linux/pci.h>20#include <linux/string.h>21#include <linux/slab.h>22#include <linux/pnp.h>23#include <linux/io.h>24#include "base.h"25 26static void quirk_awe32_add_ports(struct pnp_dev *dev,27				  struct pnp_option *option,28				  unsigned int offset)29{30	struct pnp_option *new_option;31 32	new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL);33	if (!new_option) {34		dev_err(&dev->dev, "couldn't add ioport region to option set "35			"%d\n", pnp_option_set(option));36		return;37	}38 39	*new_option = *option;40	new_option->u.port.min += offset;41	new_option->u.port.max += offset;42	list_add(&new_option->list, &option->list);43 44	dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n",45		(unsigned long long) new_option->u.port.min,46		(unsigned long long) new_option->u.port.max,47		pnp_option_set(option));48}49 50static void quirk_awe32_resources(struct pnp_dev *dev)51{52	struct pnp_option *option;53	unsigned int set = ~0;54 55	/*56	 * Add two extra ioport regions (at offset 0x400 and 0x800 from the57	 * one given) to every dependent option set.58	 */59	list_for_each_entry(option, &dev->options, list) {60		if (pnp_option_is_dependent(option) &&61		    pnp_option_set(option) != set) {62			set = pnp_option_set(option);63			quirk_awe32_add_ports(dev, option, 0x800);64			quirk_awe32_add_ports(dev, option, 0x400);65		}66	}67}68 69static void quirk_cmi8330_resources(struct pnp_dev *dev)70{71	struct pnp_option *option;72	struct pnp_irq *irq;73	struct pnp_dma *dma;74 75	list_for_each_entry(option, &dev->options, list) {76		if (!pnp_option_is_dependent(option))77			continue;78 79		if (option->type == IORESOURCE_IRQ) {80			irq = &option->u.irq;81			bitmap_zero(irq->map.bits, PNP_IRQ_NR);82			__set_bit(5, irq->map.bits);83			__set_bit(7, irq->map.bits);84			__set_bit(10, irq->map.bits);85			dev_info(&dev->dev, "set possible IRQs in "86				 "option set %d to 5, 7, 10\n",87				 pnp_option_set(option));88		} else if (option->type == IORESOURCE_DMA) {89			dma = &option->u.dma;90			if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==91						IORESOURCE_DMA_8BIT &&92			    dma->map != 0x0A) {93				dev_info(&dev->dev, "changing possible "94					 "DMA channel mask in option set %d "95					 "from %#02x to 0x0A (1, 3)\n",96					 pnp_option_set(option), dma->map);97				dma->map = 0x0A;98			}99		}100	}101}102 103static void quirk_sb16audio_resources(struct pnp_dev *dev)104{105	struct pnp_option *option;106	unsigned int prev_option_flags = ~0, n = 0;107	struct pnp_port *port;108 109	/*110	 * The default range on the OPL port for these devices is 0x388-0x388.111	 * Here we increase that range so that two such cards can be112	 * auto-configured.113	 */114	list_for_each_entry(option, &dev->options, list) {115		if (prev_option_flags != option->flags) {116			prev_option_flags = option->flags;117			n = 0;118		}119 120		if (pnp_option_is_dependent(option) &&121		    option->type == IORESOURCE_IO) {122			n++;123			port = &option->u.port;124			if (n == 3 && port->min == port->max) {125				port->max += 0x70;126				dev_info(&dev->dev, "increased option port "127					 "range from %#llx-%#llx to "128					 "%#llx-%#llx\n",129					 (unsigned long long) port->min,130					 (unsigned long long) port->min,131					 (unsigned long long) port->min,132					 (unsigned long long) port->max);133			}134		}135	}136}137 138static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev,139						  unsigned int set)140{141	struct pnp_option *tail = NULL, *first_new_option = NULL;142	struct pnp_option *option, *new_option;143	unsigned int flags;144 145	list_for_each_entry(option, &dev->options, list) {146		if (pnp_option_is_dependent(option))147			tail = option;148	}149	if (!tail) {150		dev_err(&dev->dev, "no dependent option sets\n");151		return NULL;152	}153 154	flags = pnp_new_dependent_set(dev, PNP_RES_PRIORITY_FUNCTIONAL);155	list_for_each_entry(option, &dev->options, list) {156		if (pnp_option_is_dependent(option) &&157		    pnp_option_set(option) == set) {158			new_option = kmalloc(sizeof(struct pnp_option),159					     GFP_KERNEL);160			if (!new_option) {161				dev_err(&dev->dev, "couldn't clone dependent "162					"set %d\n", set);163				return NULL;164			}165 166			*new_option = *option;167			new_option->flags = flags;168			if (!first_new_option)169				first_new_option = new_option;170 171			list_add(&new_option->list, &tail->list);172			tail = new_option;173		}174	}175 176	return first_new_option;177}178 179 180static void quirk_add_irq_optional_dependent_sets(struct pnp_dev *dev)181{182	struct pnp_option *new_option;183	unsigned int num_sets, i, set;184	struct pnp_irq *irq;185 186	num_sets = dev->num_dependent_sets;187	for (i = 0; i < num_sets; i++) {188		new_option = pnp_clone_dependent_set(dev, i);189		if (!new_option)190			return;191 192		set = pnp_option_set(new_option);193		while (new_option && pnp_option_set(new_option) == set) {194			if (new_option->type == IORESOURCE_IRQ) {195				irq = &new_option->u.irq;196				irq->flags |= IORESOURCE_IRQ_OPTIONAL;197			}198			dbg_pnp_show_option(dev, new_option);199			new_option = list_entry(new_option->list.next,200						struct pnp_option, list);201		}202 203		dev_info(&dev->dev, "added dependent option set %d (same as "204			 "set %d except IRQ optional)\n", set, i);205	}206}207 208static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)209{210	struct pnp_option *option;211	struct pnp_irq *irq = NULL;212	unsigned int independent_irqs = 0;213 214	list_for_each_entry(option, &dev->options, list) {215		if (option->type == IORESOURCE_IRQ &&216		    !pnp_option_is_dependent(option)) {217			independent_irqs++;218			irq = &option->u.irq;219		}220	}221 222	if (independent_irqs != 1)223		return;224 225	irq->flags |= IORESOURCE_IRQ_OPTIONAL;226	dev_info(&dev->dev, "made independent IRQ optional\n");227}228 229static void quirk_system_pci_resources(struct pnp_dev *dev)230{231	struct pci_dev *pdev = NULL;232	struct resource *res, *r;233	int i, j;234 235	/*236	 * Some BIOSes have PNP motherboard devices with resources that237	 * partially overlap PCI BARs.  The PNP system driver claims these238	 * motherboard resources, which prevents the normal PCI driver from239	 * requesting them later.240	 *241	 * This patch disables the PNP resources that conflict with PCI BARs242	 * so they won't be claimed by the PNP system driver.243	 */244	for_each_pci_dev(pdev) {245		pci_dev_for_each_resource(pdev, r, i) {246			unsigned long type = resource_type(r);247 248			if (!(type == IORESOURCE_IO || type == IORESOURCE_MEM) ||249			    resource_size(r) == 0)250				continue;251 252			if (r->flags & IORESOURCE_UNSET)253				continue;254 255			for (j = 0;256			     (res = pnp_get_resource(dev, type, j)); j++) {257				if (res->start == 0 && res->end == 0)258					continue;259 260				/*261				 * If the PNP region doesn't overlap the PCI262				 * region at all, there's no problem.263				 */264				if (!resource_overlaps(res, r))265					continue;266 267				/*268				 * If the PNP region completely encloses (or is269				 * at least as large as) the PCI region, that's270				 * also OK.  For example, this happens when the271				 * PNP device describes a bridge with PCI272				 * behind it.273				 */274				if (res->start <= r->start && res->end >= r->end)275					continue;276 277				/*278				 * Otherwise, the PNP region overlaps *part* of279				 * the PCI region, and that might prevent a PCI280				 * driver from requesting its resources.281				 */282				dev_warn(&dev->dev,283					 "disabling %pR because it overlaps %s BAR %d %pR\n",284					 res, pci_name(pdev), i, r);285				res->flags |= IORESOURCE_DISABLED;286			}287		}288	}289}290 291#ifdef CONFIG_AMD_NB292 293#include <asm/amd_nb.h>294 295static void quirk_amd_mmconfig_area(struct pnp_dev *dev)296{297	resource_size_t start, end;298	struct pnp_resource *pnp_res;299	struct resource *res;300	struct resource mmconfig_res, *mmconfig;301 302	mmconfig = amd_get_mmconfig_range(&mmconfig_res);303	if (!mmconfig)304		return;305 306	list_for_each_entry(pnp_res, &dev->resources, list) {307		res = &pnp_res->res;308		if (res->end < mmconfig->start || res->start > mmconfig->end ||309		    (res->start == mmconfig->start && res->end == mmconfig->end))310			continue;311 312		dev_info(&dev->dev, FW_BUG313			 "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n",314			 res, mmconfig);315		if (mmconfig->start < res->start) {316			start = mmconfig->start;317			end = res->start - 1;318			pnp_add_mem_resource(dev, start, end, 0);319		}320		if (mmconfig->end > res->end) {321			start = res->end + 1;322			end = mmconfig->end;323			pnp_add_mem_resource(dev, start, end, 0);324		}325		break;326	}327}328#endif329 330#ifdef CONFIG_PCI331/* Device IDs of parts that have 32KB MCH space */332static const unsigned int mch_quirk_devices[] = {333	0x0154,	/* Ivy Bridge */334	0x0a04, /* Haswell-ULT */335	0x0c00,	/* Haswell */336	0x1604, /* Broadwell */337};338 339static struct pci_dev *get_intel_host(void)340{341	int i;342	struct pci_dev *host;343 344	for (i = 0; i < ARRAY_SIZE(mch_quirk_devices); i++) {345		host = pci_get_device(PCI_VENDOR_ID_INTEL, mch_quirk_devices[i],346				      NULL);347		if (host)348			return host;349	}350	return NULL;351}352 353static void quirk_intel_mch(struct pnp_dev *dev)354{355	struct pci_dev *host;356	u32 addr_lo, addr_hi;357	struct pci_bus_region region;358	struct resource mch;359	struct pnp_resource *pnp_res;360	struct resource *res;361 362	host = get_intel_host();363	if (!host)364		return;365 366	/*367	 * MCHBAR is not an architected PCI BAR, so MCH space is usually368	 * reported as a PNP0C02 resource.  The MCH space was originally369	 * 16KB, but is 32KB in newer parts.  Some BIOSes still report a370	 * PNP0C02 resource that is only 16KB, which means the rest of the371	 * MCH space is consumed but unreported.372	 */373 374	/*375	 * Read MCHBAR for Host Member Mapped Register Range Base376	 * https://www-ssl.intel.com/content/www/us/en/processors/core/4th-gen-core-family-desktop-vol-2-datasheet377	 * Sec 3.1.12.378	 */379	pci_read_config_dword(host, 0x48, &addr_lo);380	region.start = addr_lo & ~0x7fff;381	pci_read_config_dword(host, 0x4c, &addr_hi);382	region.start |= (u64) addr_hi << 32;383	region.end = region.start + 32*1024 - 1;384 385	memset(&mch, 0, sizeof(mch));386	mch.flags = IORESOURCE_MEM;387	pcibios_bus_to_resource(host->bus, &mch, &region);388 389	list_for_each_entry(pnp_res, &dev->resources, list) {390		res = &pnp_res->res;391		if (res->end < mch.start || res->start > mch.end)392			continue;	/* no overlap */393		if (res->start == mch.start && res->end == mch.end)394			continue;	/* exact match */395 396		dev_info(&dev->dev, FW_BUG "PNP resource %pR covers only part of %s Intel MCH; extending to %pR\n",397			 res, pci_name(host), &mch);398		res->start = mch.start;399		res->end = mch.end;400		break;401	}402 403	pci_dev_put(host);404}405#endif406 407/*408 *  PnP Quirks409 *  Cards or devices that need some tweaking due to incomplete resource info410 */411 412static struct pnp_fixup pnp_fixups[] = {413	/* Soundblaster awe io port quirk */414	{"CTL0021", quirk_awe32_resources},415	{"CTL0022", quirk_awe32_resources},416	{"CTL0023", quirk_awe32_resources},417	/* CMI 8330 interrupt and dma fix */418	{"@X@0001", quirk_cmi8330_resources},419	/* Soundblaster audio device io port range quirk */420	{"CTL0001", quirk_sb16audio_resources},421	{"CTL0031", quirk_sb16audio_resources},422	{"CTL0041", quirk_sb16audio_resources},423	{"CTL0042", quirk_sb16audio_resources},424	{"CTL0043", quirk_sb16audio_resources},425	{"CTL0044", quirk_sb16audio_resources},426	{"CTL0045", quirk_sb16audio_resources},427	/* Add IRQ-optional MPU options */428	{"ADS7151", quirk_ad1815_mpu_resources},429	{"ADS7181", quirk_add_irq_optional_dependent_sets},430	{"AZT0002", quirk_add_irq_optional_dependent_sets},431	/* PnP resources that might overlap PCI BARs */432	{"PNP0c01", quirk_system_pci_resources},433	{"PNP0c02", quirk_system_pci_resources},434#ifdef CONFIG_AMD_NB435	{"PNP0c01", quirk_amd_mmconfig_area},436#endif437#ifdef CONFIG_PCI438	{"PNP0c02", quirk_intel_mch},439#endif440	{""}441};442 443void pnp_fixup_device(struct pnp_dev *dev)444{445	struct pnp_fixup *f;446 447	for (f = pnp_fixups; *f->id; f++) {448		if (!compare_pnp_id(dev->id, f->id))449			continue;450		pnp_dbg(&dev->dev, "%s: calling %pS\n", f->id,451			f->quirk_function);452		f->quirk_function(dev);453	}454}455