Linux Audio

Check our new training course

Loading...
v5.4
  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	printk(KERN_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		printk("\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		printk("\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}
v6.13.7
  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	u16 vid;
 54	int cap66 = -1;
 55	u16 stat;
 56	int ret;
 57
 58	pr_info("PCI: Checking 66MHz capabilities...\n");
 59
 60	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
 61		if (PCI_FUNC(pci_devfn))
 62			continue;
 63		ret = early_read_config_word(hose, top_bus, current_bus,
 64					     pci_devfn, PCI_VENDOR_ID, &vid);
 65		if (ret != PCIBIOS_SUCCESSFUL)
 66			continue;
 67		if (PCI_POSSIBLE_ERROR(vid))
 68			continue;
 69
 70		/* check 66MHz capability */
 71		if (cap66 < 0)
 72			cap66 = 1;
 73		if (cap66) {
 74			early_read_config_word(hose, top_bus, current_bus,
 75					       pci_devfn, PCI_STATUS, &stat);
 76			if (!(stat & PCI_STATUS_66MHZ)) {
 77				printk(KERN_DEBUG
 78				       "PCI: %02x:%02x not 66MHz capable.\n",
 79				       current_bus, pci_devfn);
 80				cap66 = 0;
 81				break;
 82			}
 83		}
 84	}
 85
 86	return cap66 > 0;
 87}
 88
 89static void pcibios_enable_err(struct timer_list *t)
 90{
 91	struct pci_channel *hose = from_timer(hose, t, err_timer);
 92
 93	del_timer(&hose->err_timer);
 94	printk(KERN_DEBUG "PCI: re-enabling error IRQ.\n");
 95	enable_irq(hose->err_irq);
 96}
 97
 98static void pcibios_enable_serr(struct timer_list *t)
 99{
100	struct pci_channel *hose = from_timer(hose, t, serr_timer);
101
102	del_timer(&hose->serr_timer);
103	printk(KERN_DEBUG "PCI: re-enabling system error IRQ.\n");
104	enable_irq(hose->serr_irq);
105}
106
107void pcibios_enable_timers(struct pci_channel *hose)
108{
109	if (hose->err_irq) {
110		timer_setup(&hose->err_timer, pcibios_enable_err, 0);
111	}
112
113	if (hose->serr_irq) {
114		timer_setup(&hose->serr_timer, pcibios_enable_serr, 0);
115	}
116}
117
118/*
119 * A simple handler for the regular PCI status errors, called from IRQ
120 * context.
121 */
122unsigned int pcibios_handle_status_errors(unsigned long addr,
123					  unsigned int status,
124					  struct pci_channel *hose)
125{
126	unsigned int cmd = 0;
127
128	if (status & PCI_STATUS_REC_MASTER_ABORT) {
129		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", addr);
130		cmd |= PCI_STATUS_REC_MASTER_ABORT;
131	}
132
133	if (status & PCI_STATUS_REC_TARGET_ABORT) {
134		printk(KERN_DEBUG "PCI: target abort: ");
135		pcibios_report_status(PCI_STATUS_REC_TARGET_ABORT |
136				      PCI_STATUS_SIG_TARGET_ABORT |
137				      PCI_STATUS_REC_MASTER_ABORT, 1);
138		pr_cont("\n");
139
140		cmd |= PCI_STATUS_REC_TARGET_ABORT;
141	}
142
143	if (status & (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY)) {
144		printk(KERN_DEBUG "PCI: parity error detected: ");
145		pcibios_report_status(PCI_STATUS_PARITY |
146				      PCI_STATUS_DETECTED_PARITY, 1);
147		pr_cont("\n");
148
149		cmd |= PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY;
150
151		/* Now back off of the IRQ for awhile */
152		if (hose->err_irq) {
153			disable_irq_nosync(hose->err_irq);
154			hose->err_timer.expires = jiffies + HZ;
155			add_timer(&hose->err_timer);
156		}
157	}
158
159	return cmd;
160}