0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/types.h>
0018 #include <linux/kernel.h>
0019 #include <linux/pci.h>
0020 #include <linux/string.h>
0021 #include <linux/slab.h>
0022 #include <linux/pnp.h>
0023 #include <linux/io.h>
0024 #include "base.h"
0025
0026 static void quirk_awe32_add_ports(struct pnp_dev *dev,
0027 struct pnp_option *option,
0028 unsigned int offset)
0029 {
0030 struct pnp_option *new_option;
0031
0032 new_option = kmalloc(sizeof(struct pnp_option), GFP_KERNEL);
0033 if (!new_option) {
0034 dev_err(&dev->dev, "couldn't add ioport region to option set "
0035 "%d\n", pnp_option_set(option));
0036 return;
0037 }
0038
0039 *new_option = *option;
0040 new_option->u.port.min += offset;
0041 new_option->u.port.max += offset;
0042 list_add(&new_option->list, &option->list);
0043
0044 dev_info(&dev->dev, "added ioport region %#llx-%#llx to set %d\n",
0045 (unsigned long long) new_option->u.port.min,
0046 (unsigned long long) new_option->u.port.max,
0047 pnp_option_set(option));
0048 }
0049
0050 static void quirk_awe32_resources(struct pnp_dev *dev)
0051 {
0052 struct pnp_option *option;
0053 unsigned int set = ~0;
0054
0055
0056
0057
0058
0059 list_for_each_entry(option, &dev->options, list) {
0060 if (pnp_option_is_dependent(option) &&
0061 pnp_option_set(option) != set) {
0062 set = pnp_option_set(option);
0063 quirk_awe32_add_ports(dev, option, 0x800);
0064 quirk_awe32_add_ports(dev, option, 0x400);
0065 }
0066 }
0067 }
0068
0069 static void quirk_cmi8330_resources(struct pnp_dev *dev)
0070 {
0071 struct pnp_option *option;
0072 struct pnp_irq *irq;
0073 struct pnp_dma *dma;
0074
0075 list_for_each_entry(option, &dev->options, list) {
0076 if (!pnp_option_is_dependent(option))
0077 continue;
0078
0079 if (option->type == IORESOURCE_IRQ) {
0080 irq = &option->u.irq;
0081 bitmap_zero(irq->map.bits, PNP_IRQ_NR);
0082 __set_bit(5, irq->map.bits);
0083 __set_bit(7, irq->map.bits);
0084 __set_bit(10, irq->map.bits);
0085 dev_info(&dev->dev, "set possible IRQs in "
0086 "option set %d to 5, 7, 10\n",
0087 pnp_option_set(option));
0088 } else if (option->type == IORESOURCE_DMA) {
0089 dma = &option->u.dma;
0090 if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
0091 IORESOURCE_DMA_8BIT &&
0092 dma->map != 0x0A) {
0093 dev_info(&dev->dev, "changing possible "
0094 "DMA channel mask in option set %d "
0095 "from %#02x to 0x0A (1, 3)\n",
0096 pnp_option_set(option), dma->map);
0097 dma->map = 0x0A;
0098 }
0099 }
0100 }
0101 }
0102
0103 static void quirk_sb16audio_resources(struct pnp_dev *dev)
0104 {
0105 struct pnp_option *option;
0106 unsigned int prev_option_flags = ~0, n = 0;
0107 struct pnp_port *port;
0108
0109
0110
0111
0112
0113
0114 list_for_each_entry(option, &dev->options, list) {
0115 if (prev_option_flags != option->flags) {
0116 prev_option_flags = option->flags;
0117 n = 0;
0118 }
0119
0120 if (pnp_option_is_dependent(option) &&
0121 option->type == IORESOURCE_IO) {
0122 n++;
0123 port = &option->u.port;
0124 if (n == 3 && port->min == port->max) {
0125 port->max += 0x70;
0126 dev_info(&dev->dev, "increased option port "
0127 "range from %#llx-%#llx to "
0128 "%#llx-%#llx\n",
0129 (unsigned long long) port->min,
0130 (unsigned long long) port->min,
0131 (unsigned long long) port->min,
0132 (unsigned long long) port->max);
0133 }
0134 }
0135 }
0136 }
0137
0138 static struct pnp_option *pnp_clone_dependent_set(struct pnp_dev *dev,
0139 unsigned int set)
0140 {
0141 struct pnp_option *tail = NULL, *first_new_option = NULL;
0142 struct pnp_option *option, *new_option;
0143 unsigned int flags;
0144
0145 list_for_each_entry(option, &dev->options, list) {
0146 if (pnp_option_is_dependent(option))
0147 tail = option;
0148 }
0149 if (!tail) {
0150 dev_err(&dev->dev, "no dependent option sets\n");
0151 return NULL;
0152 }
0153
0154 flags = pnp_new_dependent_set(dev, PNP_RES_PRIORITY_FUNCTIONAL);
0155 list_for_each_entry(option, &dev->options, list) {
0156 if (pnp_option_is_dependent(option) &&
0157 pnp_option_set(option) == set) {
0158 new_option = kmalloc(sizeof(struct pnp_option),
0159 GFP_KERNEL);
0160 if (!new_option) {
0161 dev_err(&dev->dev, "couldn't clone dependent "
0162 "set %d\n", set);
0163 return NULL;
0164 }
0165
0166 *new_option = *option;
0167 new_option->flags = flags;
0168 if (!first_new_option)
0169 first_new_option = new_option;
0170
0171 list_add(&new_option->list, &tail->list);
0172 tail = new_option;
0173 }
0174 }
0175
0176 return first_new_option;
0177 }
0178
0179
0180 static void quirk_add_irq_optional_dependent_sets(struct pnp_dev *dev)
0181 {
0182 struct pnp_option *new_option;
0183 unsigned int num_sets, i, set;
0184 struct pnp_irq *irq;
0185
0186 num_sets = dev->num_dependent_sets;
0187 for (i = 0; i < num_sets; i++) {
0188 new_option = pnp_clone_dependent_set(dev, i);
0189 if (!new_option)
0190 return;
0191
0192 set = pnp_option_set(new_option);
0193 while (new_option && pnp_option_set(new_option) == set) {
0194 if (new_option->type == IORESOURCE_IRQ) {
0195 irq = &new_option->u.irq;
0196 irq->flags |= IORESOURCE_IRQ_OPTIONAL;
0197 }
0198 dbg_pnp_show_option(dev, new_option);
0199 new_option = list_entry(new_option->list.next,
0200 struct pnp_option, list);
0201 }
0202
0203 dev_info(&dev->dev, "added dependent option set %d (same as "
0204 "set %d except IRQ optional)\n", set, i);
0205 }
0206 }
0207
0208 static void quirk_ad1815_mpu_resources(struct pnp_dev *dev)
0209 {
0210 struct pnp_option *option;
0211 struct pnp_irq *irq = NULL;
0212 unsigned int independent_irqs = 0;
0213
0214 list_for_each_entry(option, &dev->options, list) {
0215 if (option->type == IORESOURCE_IRQ &&
0216 !pnp_option_is_dependent(option)) {
0217 independent_irqs++;
0218 irq = &option->u.irq;
0219 }
0220 }
0221
0222 if (independent_irqs != 1)
0223 return;
0224
0225 irq->flags |= IORESOURCE_IRQ_OPTIONAL;
0226 dev_info(&dev->dev, "made independent IRQ optional\n");
0227 }
0228
0229 static void quirk_system_pci_resources(struct pnp_dev *dev)
0230 {
0231 struct pci_dev *pdev = NULL;
0232 struct resource *res;
0233 resource_size_t pnp_start, pnp_end, pci_start, pci_end;
0234 int i, j;
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 for_each_pci_dev(pdev) {
0246 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
0247 unsigned long flags, type;
0248
0249 flags = pci_resource_flags(pdev, i);
0250 type = flags & (IORESOURCE_IO | IORESOURCE_MEM);
0251 if (!type || pci_resource_len(pdev, i) == 0)
0252 continue;
0253
0254 if (flags & IORESOURCE_UNSET)
0255 continue;
0256
0257 pci_start = pci_resource_start(pdev, i);
0258 pci_end = pci_resource_end(pdev, i);
0259 for (j = 0;
0260 (res = pnp_get_resource(dev, type, j)); j++) {
0261 if (res->start == 0 && res->end == 0)
0262 continue;
0263
0264 pnp_start = res->start;
0265 pnp_end = res->end;
0266
0267
0268
0269
0270
0271 if (pnp_end < pci_start || pnp_start > pci_end)
0272 continue;
0273
0274
0275
0276
0277
0278
0279
0280
0281 if (pnp_start <= pci_start &&
0282 pnp_end >= pci_end)
0283 continue;
0284
0285
0286
0287
0288
0289
0290 dev_warn(&dev->dev,
0291 "disabling %pR because it overlaps "
0292 "%s BAR %d %pR\n", res,
0293 pci_name(pdev), i, &pdev->resource[i]);
0294 res->flags |= IORESOURCE_DISABLED;
0295 }
0296 }
0297 }
0298 }
0299
0300 #ifdef CONFIG_AMD_NB
0301
0302 #include <asm/amd_nb.h>
0303
0304 static void quirk_amd_mmconfig_area(struct pnp_dev *dev)
0305 {
0306 resource_size_t start, end;
0307 struct pnp_resource *pnp_res;
0308 struct resource *res;
0309 struct resource mmconfig_res, *mmconfig;
0310
0311 mmconfig = amd_get_mmconfig_range(&mmconfig_res);
0312 if (!mmconfig)
0313 return;
0314
0315 list_for_each_entry(pnp_res, &dev->resources, list) {
0316 res = &pnp_res->res;
0317 if (res->end < mmconfig->start || res->start > mmconfig->end ||
0318 (res->start == mmconfig->start && res->end == mmconfig->end))
0319 continue;
0320
0321 dev_info(&dev->dev, FW_BUG
0322 "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n",
0323 res, mmconfig);
0324 if (mmconfig->start < res->start) {
0325 start = mmconfig->start;
0326 end = res->start - 1;
0327 pnp_add_mem_resource(dev, start, end, 0);
0328 }
0329 if (mmconfig->end > res->end) {
0330 start = res->end + 1;
0331 end = mmconfig->end;
0332 pnp_add_mem_resource(dev, start, end, 0);
0333 }
0334 break;
0335 }
0336 }
0337 #endif
0338
0339 #ifdef CONFIG_PCI
0340
0341 static const unsigned int mch_quirk_devices[] = {
0342 0x0154,
0343 0x0a04,
0344 0x0c00,
0345 0x1604,
0346 };
0347
0348 static struct pci_dev *get_intel_host(void)
0349 {
0350 int i;
0351 struct pci_dev *host;
0352
0353 for (i = 0; i < ARRAY_SIZE(mch_quirk_devices); i++) {
0354 host = pci_get_device(PCI_VENDOR_ID_INTEL, mch_quirk_devices[i],
0355 NULL);
0356 if (host)
0357 return host;
0358 }
0359 return NULL;
0360 }
0361
0362 static void quirk_intel_mch(struct pnp_dev *dev)
0363 {
0364 struct pci_dev *host;
0365 u32 addr_lo, addr_hi;
0366 struct pci_bus_region region;
0367 struct resource mch;
0368 struct pnp_resource *pnp_res;
0369 struct resource *res;
0370
0371 host = get_intel_host();
0372 if (!host)
0373 return;
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388 pci_read_config_dword(host, 0x48, &addr_lo);
0389 region.start = addr_lo & ~0x7fff;
0390 pci_read_config_dword(host, 0x4c, &addr_hi);
0391 region.start |= (u64) addr_hi << 32;
0392 region.end = region.start + 32*1024 - 1;
0393
0394 memset(&mch, 0, sizeof(mch));
0395 mch.flags = IORESOURCE_MEM;
0396 pcibios_bus_to_resource(host->bus, &mch, ®ion);
0397
0398 list_for_each_entry(pnp_res, &dev->resources, list) {
0399 res = &pnp_res->res;
0400 if (res->end < mch.start || res->start > mch.end)
0401 continue;
0402 if (res->start == mch.start && res->end == mch.end)
0403 continue;
0404
0405 dev_info(&dev->dev, FW_BUG "PNP resource %pR covers only part of %s Intel MCH; extending to %pR\n",
0406 res, pci_name(host), &mch);
0407 res->start = mch.start;
0408 res->end = mch.end;
0409 break;
0410 }
0411
0412 pci_dev_put(host);
0413 }
0414 #endif
0415
0416
0417
0418
0419
0420
0421 static struct pnp_fixup pnp_fixups[] = {
0422
0423 {"CTL0021", quirk_awe32_resources},
0424 {"CTL0022", quirk_awe32_resources},
0425 {"CTL0023", quirk_awe32_resources},
0426
0427 {"@X@0001", quirk_cmi8330_resources},
0428
0429 {"CTL0001", quirk_sb16audio_resources},
0430 {"CTL0031", quirk_sb16audio_resources},
0431 {"CTL0041", quirk_sb16audio_resources},
0432 {"CTL0042", quirk_sb16audio_resources},
0433 {"CTL0043", quirk_sb16audio_resources},
0434 {"CTL0044", quirk_sb16audio_resources},
0435 {"CTL0045", quirk_sb16audio_resources},
0436
0437 {"ADS7151", quirk_ad1815_mpu_resources},
0438 {"ADS7181", quirk_add_irq_optional_dependent_sets},
0439 {"AZT0002", quirk_add_irq_optional_dependent_sets},
0440
0441 {"PNP0c01", quirk_system_pci_resources},
0442 {"PNP0c02", quirk_system_pci_resources},
0443 #ifdef CONFIG_AMD_NB
0444 {"PNP0c01", quirk_amd_mmconfig_area},
0445 #endif
0446 #ifdef CONFIG_PCI
0447 {"PNP0c02", quirk_intel_mch},
0448 #endif
0449 {""}
0450 };
0451
0452 void pnp_fixup_device(struct pnp_dev *dev)
0453 {
0454 struct pnp_fixup *f;
0455
0456 for (f = pnp_fixups; *f->id; f++) {
0457 if (!compare_pnp_id(dev->id, f->id))
0458 continue;
0459 pnp_dbg(&dev->dev, "%s: calling %pS\n", f->id,
0460 f->quirk_function);
0461 f->quirk_function(dev);
0462 }
0463 }