Linux Audio

Check our new training course

Loading...
v5.9
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/pci.h>
  3#include <linux/interrupt.h>
  4#include <linux/timer.h>
  5#include <linux/kernel.h>
  6
  7/*
  8 * These functions are used early on before PCI scanning is done
  9 * and all of the pci_dev and pci_bus structures have been created.
 10 */
 11static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
 12	int top_bus, int busnr, int devfn)
 13{
 14	static struct pci_dev dev;
 15	static struct pci_bus bus;
 16
 17	dev.bus = &bus;
 18	dev.sysdata = hose;
 19	dev.devfn = devfn;
 20	bus.number = busnr;
 21	bus.sysdata = hose;
 22	bus.ops = hose->pci_ops;
 23
 24	if(busnr != top_bus)
 25		/* Fake a parent bus structure. */
 26		bus.parent = &bus;
 27	else
 28		bus.parent = NULL;
 29
 30	return &dev;
 31}
 32
 33#define EARLY_PCI_OP(rw, size, type)					\
 34int __init early_##rw##_config_##size(struct pci_channel *hose,		\
 35	int top_bus, int bus, int devfn, int offset, type value)	\
 36{									\
 37	return pci_##rw##_config_##size(				\
 38		fake_pci_dev(hose, top_bus, bus, devfn),		\
 39		offset, value);						\
 40}
 41
 42EARLY_PCI_OP(read, byte, u8 *)
 43EARLY_PCI_OP(read, word, u16 *)
 44EARLY_PCI_OP(read, dword, u32 *)
 45EARLY_PCI_OP(write, byte, u8)
 46EARLY_PCI_OP(write, word, u16)
 47EARLY_PCI_OP(write, dword, u32)
 48
 49int __init pci_is_66mhz_capable(struct pci_channel *hose,
 50				int top_bus, int current_bus)
 51{
 52	u32 pci_devfn;
 53	unsigned short vid;
 54	int cap66 = -1;
 55	u16 stat;
 56
 57	pr_info("PCI: Checking 66MHz capabilities...\n");
 58
 59	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
 60		if (PCI_FUNC(pci_devfn))
 61			continue;
 62		if (early_read_config_word(hose, top_bus, current_bus,
 63					   pci_devfn, PCI_VENDOR_ID, &vid) !=
 64		    PCIBIOS_SUCCESSFUL)
 65			continue;
 66		if (vid == 0xffff)
 67			continue;
 68
 69		/* check 66MHz capability */
 70		if (cap66 < 0)
 71			cap66 = 1;
 72		if (cap66) {
 73			early_read_config_word(hose, top_bus, current_bus,
 74					       pci_devfn, PCI_STATUS, &stat);
 75			if (!(stat & PCI_STATUS_66MHZ)) {
 76				printk(KERN_DEBUG
 77				       "PCI: %02x:%02x not 66MHz capable.\n",
 78				       current_bus, pci_devfn);
 79				cap66 = 0;
 80				break;
 81			}
 82		}
 83	}
 84
 85	return cap66 > 0;
 86}
 87
 88static void pcibios_enable_err(struct timer_list *t)
 89{
 90	struct pci_channel *hose = from_timer(hose, t, err_timer);
 91
 92	del_timer(&hose->err_timer);
 93	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
 94	enable_irq(hose->err_irq);
 95}
 96
 97static void pcibios_enable_serr(struct timer_list *t)
 98{
 99	struct pci_channel *hose = from_timer(hose, t, serr_timer);
100
101	del_timer(&hose->serr_timer);
102	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
103	enable_irq(hose->serr_irq);
104}
105
106void pcibios_enable_timers(struct pci_channel *hose)
107{
108	if (hose->err_irq) {
109		timer_setup(&hose->err_timer, pcibios_enable_err, 0);
 
 
110	}
111
112	if (hose->serr_irq) {
113		timer_setup(&hose->serr_timer, pcibios_enable_serr, 0);
 
 
114	}
115}
116
117/*
118 * A simple handler for the regular PCI status errors, called from IRQ
119 * context.
120 */
121unsigned int pcibios_handle_status_errors(unsigned long addr,
122					  unsigned int status,
123					  struct pci_channel *hose)
124{
125	unsigned int cmd = 0;
126
127	if (status & PCI_STATUS_REC_MASTER_ABORT) {
128		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
129		cmd |= PCI_STATUS_REC_MASTER_ABORT;
130	}
131
132	if (status & PCI_STATUS_REC_TARGET_ABORT) {
133		printk(KERN_DEBUG "PCI: target abort: ");
134		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
135				      PCI_STATUS_SIG_TARGET_ABORT |
136				      PCI_STATUS_REC_MASTER_ABORT, 1);
137		pr_cont("\n");
138
139		cmd |= PCI_STATUS_REC_TARGET_ABORT;
140	}
141
142	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
143		printk(KERN_DEBUG "PCI: parity error detected: ");
144		pcibios_report_status(PCI_STATUS_PARITY |
145				      PCI_STATUS_DETECTED_PARITY, 1);
146		pr_cont("\n");
147
148		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
149
150		/* Now back off of the IRQ for awhile */
151		if (hose->err_irq) {
152			disable_irq_nosync(hose->err_irq);
153			hose->err_timer.expires = jiffies + HZ;
154			add_timer(&hose->err_timer);
155		}
156	}
157
158	return cmd;
159}
v3.15
 
  1#include <linux/pci.h>
  2#include <linux/interrupt.h>
  3#include <linux/timer.h>
  4#include <linux/kernel.h>
  5
  6/*
  7 * These functions are used early on before PCI scanning is done
  8 * and all of the pci_dev and pci_bus structures have been created.
  9 */
 10static struct pci_dev *fake_pci_dev(struct pci_channel *hose,
 11	int top_bus, int busnr, int devfn)
 12{
 13	static struct pci_dev dev;
 14	static struct pci_bus bus;
 15
 16	dev.bus = &bus;
 17	dev.sysdata = hose;
 18	dev.devfn = devfn;
 19	bus.number = busnr;
 20	bus.sysdata = hose;
 21	bus.ops = hose->pci_ops;
 22
 23	if(busnr != top_bus)
 24		/* Fake a parent bus structure. */
 25		bus.parent = &bus;
 26	else
 27		bus.parent = NULL;
 28
 29	return &dev;
 30}
 31
 32#define EARLY_PCI_OP(rw, size, type)					\
 33int __init early_##rw##_config_##size(struct pci_channel *hose,		\
 34	int top_bus, int bus, int devfn, int offset, type value)	\
 35{									\
 36	return pci_##rw##_config_##size(				\
 37		fake_pci_dev(hose, top_bus, bus, devfn),		\
 38		offset, value);						\
 39}
 40
 41EARLY_PCI_OP(read, byte, u8 *)
 42EARLY_PCI_OP(read, word, u16 *)
 43EARLY_PCI_OP(read, dword, u32 *)
 44EARLY_PCI_OP(write, byte, u8)
 45EARLY_PCI_OP(write, word, u16)
 46EARLY_PCI_OP(write, dword, u32)
 47
 48int __init pci_is_66mhz_capable(struct pci_channel *hose,
 49				int top_bus, int current_bus)
 50{
 51	u32 pci_devfn;
 52	unsigned short vid;
 53	int cap66 = -1;
 54	u16 stat;
 55
 56	printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
 57
 58	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
 59		if (PCI_FUNC(pci_devfn))
 60			continue;
 61		if (early_read_config_word(hose, top_bus, current_bus,
 62					   pci_devfn, PCI_VENDOR_ID, &vid) !=
 63		    PCIBIOS_SUCCESSFUL)
 64			continue;
 65		if (vid == 0xffff)
 66			continue;
 67
 68		/* check 66MHz capability */
 69		if (cap66 < 0)
 70			cap66 = 1;
 71		if (cap66) {
 72			early_read_config_word(hose, top_bus, current_bus,
 73					       pci_devfn, PCI_STATUS, &stat);
 74			if (!(stat & PCI_STATUS_66MHZ)) {
 75				printk(KERN_DEBUG
 76				       "PCI: %02x:%02x not 66MHz capable.\n",
 77				       current_bus, pci_devfn);
 78				cap66 = 0;
 79				break;
 80			}
 81		}
 82	}
 83
 84	return cap66 > 0;
 85}
 86
 87static void pcibios_enable_err(unsigned long __data)
 88{
 89	struct pci_channel *hose = (struct pci_channel *)__data;
 90
 91	del_timer(&hose->err_timer);
 92	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
 93	enable_irq(hose->err_irq);
 94}
 95
 96static void pcibios_enable_serr(unsigned long __data)
 97{
 98	struct pci_channel *hose = (struct pci_channel *)__data;
 99
100	del_timer(&hose->serr_timer);
101	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
102	enable_irq(hose->serr_irq);
103}
104
105void pcibios_enable_timers(struct pci_channel *hose)
106{
107	if (hose->err_irq) {
108		init_timer(&hose->err_timer);
109		hose->err_timer.data = (unsigned long)hose;
110		hose->err_timer.function = pcibios_enable_err;
111	}
112
113	if (hose->serr_irq) {
114		init_timer(&hose->serr_timer);
115		hose->serr_timer.data = (unsigned long)hose;
116		hose->serr_timer.function = pcibios_enable_serr;
117	}
118}
119
120/*
121 * A simple handler for the regular PCI status errors, called from IRQ
122 * context.
123 */
124unsigned int pcibios_handle_status_errors(unsigned long addr,
125					  unsigned int status,
126					  struct pci_channel *hose)
127{
128	unsigned int cmd = 0;
129
130	if (status & PCI_STATUS_REC_MASTER_ABORT) {
131		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
132		cmd |= PCI_STATUS_REC_MASTER_ABORT;
133	}
134
135	if (status & PCI_STATUS_REC_TARGET_ABORT) {
136		printk(KERN_DEBUG "PCI: target abort: ");
137		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
138				      PCI_STATUS_SIG_TARGET_ABORT |
139				      PCI_STATUS_REC_MASTER_ABORT, 1);
140		printk("\n");
141
142		cmd |= PCI_STATUS_REC_TARGET_ABORT;
143	}
144
145	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
146		printk(KERN_DEBUG "PCI: parity error detected: ");
147		pcibios_report_status(PCI_STATUS_PARITY |
148				      PCI_STATUS_DETECTED_PARITY, 1);
149		printk("\n");
150
151		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
152
153		/* Now back off of the IRQ for awhile */
154		if (hose->err_irq) {
155			disable_irq_nosync(hose->err_irq);
156			hose->err_timer.expires = jiffies + HZ;
157			add_timer(&hose->err_timer);
158		}
159	}
160
161	return cmd;
162}