PCI changes for the v3.13 merge window:
Resource management - Fix host bridge window coalescing (Alexey Neyman) - Pass type, width, and prefetchability for window alignment (Wei Yang) PCI device hotplug - Convert acpiphp, acpiphp_ibm to dynamic debug (Lan Tianyu) Power management - Remove pci_pm_complete() (Liu Chuansheng) MSI - Fail initialization if device is not in PCI_D0 (Yijing Wang) MPS (Max Payload Size) - Use pcie_get_mps() and pcie_set_mps() to simplify code (Yijing Wang) - Use pcie_set_readrq() to simplify code (Yijing Wang) - Use cached pci_dev->pcie_mpss to simplify code (Yijing Wang) SR-IOV - Enable upstream bridges even for VFs on virtual buses (Bjorn Helgaas) - Use pci_is_root_bus() to avoid catching virtual buses (Wei Yang) Virtualization - Add x86 MSI masking ops (Konrad Rzeszutek Wilk) Freescale i.MX6 - Support i.MX6 PCIe controller (Sean Cross) - Increase link startup timeout (Marek Vasut) - Probe PCIe in fs_initcall() (Marek Vasut) - Fix imprecise abort handler (Tim Harvey) - Remove redundant of_match_ptr (Sachin Kamat) Renesas R-Car - Support Gen2 internal PCIe controller (Valentine Barshak) Samsung Exynos - Add MSI support (Jingoo Han) - Turn off power when link fails (Jingoo Han) - Add Jingoo Han as maintainer (Jingoo Han) - Add clk_disable_unprepare() on error path (Wei Yongjun) - Remove redundant of_match_ptr (Sachin Kamat) Synopsys DesignWare - Add irq_create_mapping() (Pratyush Anand) - Add header guards (Seungwon Jeon) Miscellaneous - Enable native PCIe services by default on non-ACPI (Andrew Murray) - Cleanup _OSC usage and messages (Bjorn Helgaas) - Remove pcibios_last_bus boot option on non-x86 (Bjorn Helgaas) - Convert bus code to use bus_, drv_, and dev_groups (Greg Kroah-Hartman) - Remove unused pci_mem_start (Myron Stowe) - Make sysfs functions static (Sachin Kamat) - Warn on invalid return from driver probe (Stephen M. Cameron) - Remove Intel Haswell D3 delays (Todd E Brandt) - Call pci_set_master() in core if driver doesn't do it (Yinghai Lu) - Use pci_is_pcie() to simplify code (Yijing Wang) - Use PCIe capability accessors to simplify code (Yijing Wang) - Use cached pci_dev->pcie_cap to simplify code (Yijing Wang) - Removed unused "is_pcie" from struct pci_dev (Yijing Wang) - Simplify sysfs CPU affinity implementation (Yijing Wang)) -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJSgUzsAAoJEFmIoMA60/r8wmsQAJhwmtkUYR2L4T1g9smAyjJz bLm5zoC6WdywFcbTpTBfsTrS1CHIQG5akRgkEXGdr99epiho5F2lwmagWsUR4ijL 39Qn3knAUMgtNjoVXXI106h/DfTyxSmkZBfih2AQFyWobJq+0kg7hjQQA3+836b4 8ssWr1+NSl6JJTqYQ0Paw1kSqvvYoXsu5rWFEfCHk8D0s/1bvr5ldAUpk2jTg93I uo9/5+O264yt1YoKZOMqAMZLUfd5DaWY1mV3yeF0Uauy1pBmol5csE8ckqJPDrES PRdJT1+PhBeLYWcgXANOBZsW58ddxA0pQ5jQV6VJHQWsm5cE82OBpYJf6xUZ2moV o6DZ0KRnCPVA3NllYYR16H+wbMfADwwO83QoA+QTIZJy/WgpDH3Cst+m8KePGqbL uFgDdXSws9Bs1BCFs7bfYzAM3OdkBFnn+ac7JoPXKP5ibgAp9nDlurgK2r90zRnp j15vHMx0mV+e8B8/iwiW5eRtg7NoCHYiNfFy7JalOlsPmYr2KFazBVKclp13Hng7 fe/Jy6X4UhWoQPdqsy4ftvSQb0gm1MClxFJeZ3VAt6LY9j8OP6S/Vdf6lpAL85KR lAQoQzB+lOhTPdXxFY2xgGkITkqPDOQMjPfowYUYFwybqBuG6BHXZPJobL+niBlb Nh+M2WlUUA9Z3V6rWJB6 =CTPk -----END PGP SIGNATURE----- Merge tag 'pci-v3.13-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI changes from Bjorn Helgaas: "Resource management - Fix host bridge window coalescing (Alexey Neyman) - Pass type, width, and prefetchability for window alignment (Wei Yang) PCI device hotplug - Convert acpiphp, acpiphp_ibm to dynamic debug (Lan Tianyu) Power management - Remove pci_pm_complete() (Liu Chuansheng) MSI - Fail initialization if device is not in PCI_D0 (Yijing Wang) MPS (Max Payload Size) - Use pcie_get_mps() and pcie_set_mps() to simplify code (Yijing Wang) - Use pcie_set_readrq() to simplify code (Yijing Wang) - Use cached pci_dev->pcie_mpss to simplify code (Yijing Wang) SR-IOV - Enable upstream bridges even for VFs on virtual buses (Bjorn Helgaas) - Use pci_is_root_bus() to avoid catching virtual buses (Wei Yang) Virtualization - Add x86 MSI masking ops (Konrad Rzeszutek Wilk) Freescale i.MX6 - Support i.MX6 PCIe controller (Sean Cross) - Increase link startup timeout (Marek Vasut) - Probe PCIe in fs_initcall() (Marek Vasut) - Fix imprecise abort handler (Tim Harvey) - Remove redundant of_match_ptr (Sachin Kamat) Renesas R-Car - Support Gen2 internal PCIe controller (Valentine Barshak) Samsung Exynos - Add MSI support (Jingoo Han) - Turn off power when link fails (Jingoo Han) - Add Jingoo Han as maintainer (Jingoo Han) - Add clk_disable_unprepare() on error path (Wei Yongjun) - Remove redundant of_match_ptr (Sachin Kamat) Synopsys DesignWare - Add irq_create_mapping() (Pratyush Anand) - Add header guards (Seungwon Jeon) Miscellaneous - Enable native PCIe services by default on non-ACPI (Andrew Murray) - Cleanup _OSC usage and messages (Bjorn Helgaas) - Remove pcibios_last_bus boot option on non-x86 (Bjorn Helgaas) - Convert bus code to use bus_, drv_, and dev_groups (Greg Kroah-Hartman) - Remove unused pci_mem_start (Myron Stowe) - Make sysfs functions static (Sachin Kamat) - Warn on invalid return from driver probe (Stephen M. Cameron) - Remove Intel Haswell D3 delays (Todd E Brandt) - Call pci_set_master() in core if driver doesn't do it (Yinghai Lu) - Use pci_is_pcie() to simplify code (Yijing Wang) - Use PCIe capability accessors to simplify code (Yijing Wang) - Use cached pci_dev->pcie_cap to simplify code (Yijing Wang) - Removed unused "is_pcie" from struct pci_dev (Yijing Wang) - Simplify sysfs CPU affinity implementation (Yijing Wang)" * tag 'pci-v3.13-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (79 commits) PCI: Enable upstream bridges even for VFs on virtual buses PCI: Add pci_upstream_bridge() PCI: Add x86_msi.msi_mask_irq() and msix_mask_irq() PCI: Warn on driver probe return value greater than zero PCI: Drop warning about drivers that don't use pci_set_master() PCI: Workaround missing pci_set_master in pci drivers powerpc/pci: Use pci_is_pcie() to simplify code [fix] PCI: Update pcie_ports 'auto' behavior for non-ACPI platforms PCI: imx6: Probe the PCIe in fs_initcall() PCI: Add R-Car Gen2 internal PCI support PCI: imx6: Remove redundant of_match_ptr PCI: Report pci_pme_active() kmalloc failure mn10300/PCI: Remove useless pcibios_last_bus frv/PCI: Remove pcibios_last_bus PCI: imx6: Increase link startup timeout PCI: exynos: Remove redundant of_match_ptr PCI: imx6: Fix imprecise abort handler PCI: Fail MSI/MSI-X initialization if device is not in PCI_D0 PCI: imx6: Remove redundant dev_err() in imx6_pcie_probe() x86/PCI: Coalesce multiple overlapping host bridge windows ...
This commit is contained in:
commit
2f466d33f5
@ -525,8 +525,9 @@ corresponding register block for you.
|
||||
6. Other interesting functions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
pci_find_slot() Find pci_dev corresponding to given bus and
|
||||
slot numbers.
|
||||
pci_get_domain_bus_and_slot() Find pci_dev corresponding to given domain,
|
||||
bus and slot and number. If the device is
|
||||
found, its reference count is increased.
|
||||
pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3)
|
||||
pci_find_capability() Find specified capability in device's capability
|
||||
list.
|
||||
@ -582,7 +583,8 @@ having sane locking.
|
||||
|
||||
pci_find_device() Superseded by pci_get_device()
|
||||
pci_find_subsys() Superseded by pci_get_subsys()
|
||||
pci_find_slot() Superseded by pci_get_slot()
|
||||
pci_find_slot() Superseded by pci_get_domain_bus_and_slot()
|
||||
pci_get_slot() Superseded by pci_get_domain_bus_and_slot()
|
||||
|
||||
|
||||
The alternative is the traditional PCI device driver that walks PCI
|
||||
|
@ -3,7 +3,7 @@
|
||||
Required properties:
|
||||
- compatible: should contain "snps,dw-pcie" to identify the
|
||||
core, plus an identifier for the specific instance, such
|
||||
as "samsung,exynos5440-pcie".
|
||||
as "samsung,exynos5440-pcie" or "fsl,imx6q-pcie".
|
||||
- reg: base addresses and lengths of the pcie controller,
|
||||
the phy controller, additional register for the phy controller.
|
||||
- interrupts: interrupt values for level interrupt,
|
||||
@ -21,6 +21,11 @@ Required properties:
|
||||
- num-lanes: number of lanes to use
|
||||
- reset-gpio: gpio pin number of power good signal
|
||||
|
||||
Optional properties for fsl,imx6q-pcie
|
||||
- power-on-gpio: gpio pin number of power-enable signal
|
||||
- wake-up-gpio: gpio pin number of incoming wakeup signal
|
||||
- disable-gpio: gpio pin number of outgoing rfkill/endpoint disable signal
|
||||
|
||||
Example:
|
||||
|
||||
SoC specific DT Entry:
|
||||
|
@ -6427,6 +6427,7 @@ S: Supported
|
||||
F: Documentation/PCI/
|
||||
F: drivers/pci/
|
||||
F: include/linux/pci*
|
||||
F: arch/x86/pci/
|
||||
|
||||
PCI DRIVER FOR NVIDIA TEGRA
|
||||
M: Thierry Reding <thierry.reding@gmail.com>
|
||||
@ -6435,6 +6436,12 @@ S: Supported
|
||||
F: Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt
|
||||
F: drivers/pci/host/pci-tegra.c
|
||||
|
||||
PCI DRIVER FOR SAMSUNG EXYNOS
|
||||
M: Jingoo Han <jg1.han@samsung.com>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/pci/host/pci-exynos.c
|
||||
|
||||
PCMCIA SUBSYSTEM
|
||||
P: Linux PCMCIA Team
|
||||
L: linux-pcmcia@lists.infradead.org
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#define pcibios_assign_all_busses(void) 1
|
||||
|
||||
extern unsigned long pci_mem_start;
|
||||
#define PCIBIOS_MIN_IO 0x1000
|
||||
#define PCIBIOS_MIN_MEM 0x10000000
|
||||
|
||||
|
@ -30,7 +30,6 @@ void pcibios_resource_survey(void);
|
||||
|
||||
/* pci-vdk.c */
|
||||
|
||||
extern int __nongpreldata pcibios_last_bus;
|
||||
extern struct pci_ops *__nongpreldata pci_root_ops;
|
||||
|
||||
/* pci-irq.c */
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
unsigned int __nongpreldata pci_probe = 1;
|
||||
|
||||
int __nongpreldata pcibios_last_bus = -1;
|
||||
struct pci_ops *__nongpreldata pci_root_ops;
|
||||
|
||||
/*
|
||||
@ -219,37 +218,6 @@ static struct pci_ops * __init pci_check_direct(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Discover remaining PCI buses in case there are peer host bridges.
|
||||
* We use the number of last PCI bus provided by the PCI BIOS.
|
||||
*/
|
||||
static void __init pcibios_fixup_peer_bridges(void)
|
||||
{
|
||||
struct pci_bus bus;
|
||||
struct pci_dev dev;
|
||||
int n;
|
||||
u16 l;
|
||||
|
||||
if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
|
||||
return;
|
||||
printk("PCI: Peer bridge fixup\n");
|
||||
for (n=0; n <= pcibios_last_bus; n++) {
|
||||
if (pci_find_bus(0, n))
|
||||
continue;
|
||||
bus.number = n;
|
||||
bus.ops = pci_root_ops;
|
||||
dev.bus = &bus;
|
||||
for(dev.devfn=0; dev.devfn<256; dev.devfn += 8)
|
||||
if (!pci_read_config_word(&dev, PCI_VENDOR_ID, &l) &&
|
||||
l != 0x0000 && l != 0xffff) {
|
||||
printk("Found device at %02x:%02x [%04x]\n", n, dev.devfn, l);
|
||||
printk("PCI: Discovered peer bus %02x\n", n);
|
||||
pci_scan_bus(n, pci_root_ops, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
|
||||
*/
|
||||
@ -418,7 +386,6 @@ int __init pcibios_init(void)
|
||||
pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
|
||||
|
||||
pcibios_irq_init();
|
||||
pcibios_fixup_peer_bridges();
|
||||
pcibios_fixup_irqs();
|
||||
pcibios_resource_survey();
|
||||
|
||||
@ -432,9 +399,6 @@ char * __init pcibios_setup(char *str)
|
||||
if (!strcmp(str, "off")) {
|
||||
pci_probe = 0;
|
||||
return NULL;
|
||||
} else if (!strncmp(str, "lastbus=", 8)) {
|
||||
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ extern void unit_pci_init(void);
|
||||
#define pcibios_assign_all_busses() 0
|
||||
#endif
|
||||
|
||||
extern unsigned long pci_mem_start;
|
||||
#define PCIBIOS_MIN_IO 0xBE000004
|
||||
#define PCIBIOS_MIN_MEM 0xB8000000
|
||||
|
||||
|
@ -35,9 +35,6 @@
|
||||
|
||||
struct mn10300_cpuinfo boot_cpu_data;
|
||||
|
||||
/* For PCI or other memory-mapped resources */
|
||||
unsigned long pci_mem_start = 0x18000000;
|
||||
|
||||
static char __initdata cmd_line[COMMAND_LINE_SIZE];
|
||||
char redboot_command_line[COMMAND_LINE_SIZE] =
|
||||
"console=ttyS0,115200 root=/dev/mtdblock3 rw";
|
||||
|
@ -35,7 +35,6 @@ extern void pcibios_resource_survey(void);
|
||||
|
||||
/* pci.c */
|
||||
|
||||
extern int pcibios_last_bus;
|
||||
extern struct pci_ops *pci_root_ops;
|
||||
|
||||
extern struct irq_routing_table *pcibios_get_irq_routing_table(void);
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
unsigned int pci_probe = 1;
|
||||
|
||||
int pcibios_last_bus = -1;
|
||||
struct pci_ops *pci_root_ops;
|
||||
|
||||
/*
|
||||
@ -392,10 +391,6 @@ char *__init pcibios_setup(char *str)
|
||||
if (!strcmp(str, "off")) {
|
||||
pci_probe = 0;
|
||||
return NULL;
|
||||
|
||||
} else if (!strncmp(str, "lastbus=", 8)) {
|
||||
pcibios_last_bus = simple_strtol(str+8, NULL, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -189,14 +189,13 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
|
||||
}
|
||||
|
||||
/* If PCI-E capable, dump PCI-E cap 10, and the AER */
|
||||
cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
if (cap) {
|
||||
if (pci_is_pcie(dev)) {
|
||||
n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
|
||||
printk(KERN_WARNING
|
||||
"EEH: PCI-E capabilities and status follow:\n");
|
||||
|
||||
for (i=0; i<=8; i++) {
|
||||
eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
|
||||
eeh_ops->read_config(dn, dev->pcie_cap+4*i, 4, &cfg);
|
||||
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
|
||||
printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev)
|
||||
u8 hdr_type;
|
||||
|
||||
/* if we aren't a PCIe don't bother */
|
||||
if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
|
||||
if (!pci_is_pcie(dev))
|
||||
return;
|
||||
|
||||
/* if we aren't in host mode don't bother */
|
||||
|
@ -251,15 +251,12 @@ static void fixup_read_and_payload_sizes(void)
|
||||
/* Scan for the smallest maximum payload size. */
|
||||
for_each_pci_dev(dev) {
|
||||
u32 devcap;
|
||||
int max_payload;
|
||||
|
||||
if (!pci_is_pcie(dev))
|
||||
continue;
|
||||
|
||||
pcie_capability_read_dword(dev, PCI_EXP_DEVCAP, &devcap);
|
||||
max_payload = devcap & PCI_EXP_DEVCAP_PAYLOAD;
|
||||
if (max_payload < smallest_max_payload)
|
||||
smallest_max_payload = max_payload;
|
||||
if (dev->pcie_mpss < smallest_max_payload)
|
||||
smallest_max_payload = dev->pcie_mpss;
|
||||
}
|
||||
|
||||
/* Now, set the max_payload_size for all devices to that value. */
|
||||
|
@ -172,6 +172,7 @@ struct x86_platform_ops {
|
||||
|
||||
struct pci_dev;
|
||||
struct msi_msg;
|
||||
struct msi_desc;
|
||||
|
||||
struct x86_msi_ops {
|
||||
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
|
||||
@ -182,6 +183,8 @@ struct x86_msi_ops {
|
||||
void (*teardown_msi_irqs)(struct pci_dev *dev);
|
||||
void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
|
||||
int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
|
||||
u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag);
|
||||
u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag);
|
||||
};
|
||||
|
||||
struct IO_APIC_route_entry;
|
||||
|
@ -116,6 +116,8 @@ struct x86_msi_ops x86_msi = {
|
||||
.teardown_msi_irqs = default_teardown_msi_irqs,
|
||||
.restore_msi_irqs = default_restore_msi_irqs,
|
||||
.setup_hpet_msi = default_setup_hpet_msi,
|
||||
.msi_mask_irq = default_msi_mask_irq,
|
||||
.msix_mask_irq = default_msix_mask_irq,
|
||||
};
|
||||
|
||||
/* MSI arch specific hooks */
|
||||
@ -138,6 +140,14 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq)
|
||||
{
|
||||
x86_msi.restore_msi_irqs(dev, irq);
|
||||
}
|
||||
u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
{
|
||||
return x86_msi.msi_mask_irq(desc, mask, flag);
|
||||
}
|
||||
u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
{
|
||||
return x86_msi.msix_mask_irq(desc, flag);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct x86_io_apic_ops x86_io_apic_ops = {
|
||||
|
@ -354,12 +354,12 @@ static void coalesce_windows(struct pci_root_info *info, unsigned long type)
|
||||
* the kernel resource tree doesn't allow overlaps.
|
||||
*/
|
||||
if (resource_overlaps(res1, res2)) {
|
||||
res1->start = min(res1->start, res2->start);
|
||||
res1->end = max(res1->end, res2->end);
|
||||
res2->start = min(res1->start, res2->start);
|
||||
res2->end = max(res1->end, res2->end);
|
||||
dev_info(&info->bridge->dev,
|
||||
"host bridge window expanded to %pR; %pR ignored\n",
|
||||
res1, res2);
|
||||
res2->flags = 0;
|
||||
res2, res1);
|
||||
res1->flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int wh
|
||||
offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)];
|
||||
|
||||
if ((offset) && (where == offset))
|
||||
value = value & 0xfffffffc;
|
||||
value = value & ~PCI_EXP_LNKCTL_ASPMC;
|
||||
|
||||
return raw_pci_write(pci_domain_nr(bus), bus->number,
|
||||
devfn, where, size, value);
|
||||
@ -252,7 +252,7 @@ static struct pci_ops quirk_pcie_aspm_ops = {
|
||||
*/
|
||||
static void pcie_rootport_aspm_quirk(struct pci_dev *pdev)
|
||||
{
|
||||
int cap_base, i;
|
||||
int i;
|
||||
struct pci_bus *pbus;
|
||||
struct pci_dev *dev;
|
||||
|
||||
@ -278,7 +278,7 @@ static void pcie_rootport_aspm_quirk(struct pci_dev *pdev)
|
||||
for (i = GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i)
|
||||
quirk_aspm_offset[i] = 0;
|
||||
|
||||
pbus->ops = pbus->parent->ops;
|
||||
pci_bus_set_ops(pbus, pbus->parent->ops);
|
||||
} else {
|
||||
/*
|
||||
* If devices are attached to the root port at power-up or
|
||||
@ -286,13 +286,15 @@ static void pcie_rootport_aspm_quirk(struct pci_dev *pdev)
|
||||
* each root port to save the register offsets and replace the
|
||||
* bus ops.
|
||||
*/
|
||||
list_for_each_entry(dev, &pbus->devices, bus_list) {
|
||||
list_for_each_entry(dev, &pbus->devices, bus_list)
|
||||
/* There are 0 to 8 devices attached to this bus */
|
||||
cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP);
|
||||
quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)] = cap_base + 0x10;
|
||||
}
|
||||
pbus->ops = &quirk_pcie_aspm_ops;
|
||||
quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)] =
|
||||
dev->pcie_cap + PCI_EXP_LNKCTL;
|
||||
|
||||
pci_bus_set_ops(pbus, &quirk_pcie_aspm_ops);
|
||||
dev_info(&pbus->dev, "writes to ASPM control bits will be ignored\n");
|
||||
}
|
||||
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk);
|
||||
|
@ -382,7 +382,14 @@ static void xen_teardown_msi_irq(unsigned int irq)
|
||||
{
|
||||
xen_destroy_irq(irq);
|
||||
}
|
||||
|
||||
static u32 xen_nop_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static u32 xen_nop_msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int __init pci_xen_init(void)
|
||||
@ -406,6 +413,8 @@ int __init pci_xen_init(void)
|
||||
x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
|
||||
x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
|
||||
x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@ -485,6 +494,8 @@ int __init pci_xen_initial_domain(void)
|
||||
x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
|
||||
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
|
||||
x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
|
||||
x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
|
||||
x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
|
||||
#endif
|
||||
xen_setup_acpi_sci();
|
||||
__acpi_register_gsi = acpi_register_gsi_xen;
|
||||
|
@ -758,9 +758,9 @@ int apei_osc_setup(void)
|
||||
.cap.pointer = capbuf,
|
||||
};
|
||||
|
||||
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_TYPE] = 1;
|
||||
capbuf[OSC_CONTROL_TYPE] = 0;
|
||||
capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_DWORD] = 1;
|
||||
capbuf[OSC_CONTROL_DWORD] = 0;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))
|
||||
|| ACPI_FAILURE(acpi_run_osc(handle, &context)))
|
||||
|
@ -256,7 +256,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
|
||||
acpi_print_osc_error(handle, context,
|
||||
"_OSC invalid revision");
|
||||
if (errors & OSC_CAPABILITIES_MASK_ERROR) {
|
||||
if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
|
||||
if (((u32 *)context->cap.pointer)[OSC_QUERY_DWORD]
|
||||
& OSC_QUERY_ENABLE)
|
||||
goto out_success;
|
||||
status = AE_SUPPORT;
|
||||
@ -296,30 +296,30 @@ static void acpi_bus_osc_support(void)
|
||||
};
|
||||
acpi_handle handle;
|
||||
|
||||
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
|
||||
capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_DWORD] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
|
||||
#if defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR) ||\
|
||||
defined(CONFIG_ACPI_PROCESSOR_AGGREGATOR_MODULE)
|
||||
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
|
||||
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PAD_SUPPORT;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE)
|
||||
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT;
|
||||
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PPC_OST_SUPPORT;
|
||||
#endif
|
||||
|
||||
#ifdef ACPI_HOTPLUG_OST
|
||||
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_HOTPLUG_OST_SUPPORT;
|
||||
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
|
||||
#endif
|
||||
|
||||
if (!ghes_disable)
|
||||
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT;
|
||||
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
|
||||
return;
|
||||
if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) {
|
||||
u32 *capbuf_ret = context.ret.pointer;
|
||||
if (context.ret.length > OSC_SUPPORT_TYPE)
|
||||
if (context.ret.length > OSC_SUPPORT_DWORD)
|
||||
osc_sb_apei_support_acked =
|
||||
capbuf_ret[OSC_SUPPORT_TYPE] & OSC_SB_APEI_SUPPORT;
|
||||
capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
|
||||
kfree(context.ret.pointer);
|
||||
}
|
||||
/* do we need to check other returned cap? Sounds no */
|
||||
|
@ -51,10 +51,10 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
||||
const struct acpi_device_id *not_used);
|
||||
static void acpi_pci_root_remove(struct acpi_device *device);
|
||||
|
||||
#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
|
||||
| OSC_ACTIVE_STATE_PWR_SUPPORT \
|
||||
| OSC_CLOCK_PWR_CAPABILITY_SUPPORT \
|
||||
| OSC_MSI_SUPPORT)
|
||||
#define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \
|
||||
| OSC_PCI_ASPM_SUPPORT \
|
||||
| OSC_PCI_CLOCK_PM_SUPPORT \
|
||||
| OSC_PCI_MSI_SUPPORT)
|
||||
|
||||
static const struct acpi_device_id root_device_ids[] = {
|
||||
{"PNP0A03", 0},
|
||||
@ -129,6 +129,55 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle,
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
struct pci_osc_bit_struct {
|
||||
u32 bit;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
static struct pci_osc_bit_struct pci_osc_support_bit[] = {
|
||||
{ OSC_PCI_EXT_CONFIG_SUPPORT, "ExtendedConfig" },
|
||||
{ OSC_PCI_ASPM_SUPPORT, "ASPM" },
|
||||
{ OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" },
|
||||
{ OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" },
|
||||
{ OSC_PCI_MSI_SUPPORT, "MSI" },
|
||||
};
|
||||
|
||||
static struct pci_osc_bit_struct pci_osc_control_bit[] = {
|
||||
{ OSC_PCI_EXPRESS_NATIVE_HP_CONTROL, "PCIeHotplug" },
|
||||
{ OSC_PCI_SHPC_NATIVE_HP_CONTROL, "SHPCHotplug" },
|
||||
{ OSC_PCI_EXPRESS_PME_CONTROL, "PME" },
|
||||
{ OSC_PCI_EXPRESS_AER_CONTROL, "AER" },
|
||||
{ OSC_PCI_EXPRESS_CAPABILITY_CONTROL, "PCIeCapability" },
|
||||
};
|
||||
|
||||
static void decode_osc_bits(struct acpi_pci_root *root, char *msg, u32 word,
|
||||
struct pci_osc_bit_struct *table, int size)
|
||||
{
|
||||
char buf[80];
|
||||
int i, len = 0;
|
||||
struct pci_osc_bit_struct *entry;
|
||||
|
||||
buf[0] = '\0';
|
||||
for (i = 0, entry = table; i < size; i++, entry++)
|
||||
if (word & entry->bit)
|
||||
len += snprintf(buf + len, sizeof(buf) - len, "%s%s",
|
||||
len ? " " : "", entry->desc);
|
||||
|
||||
dev_info(&root->device->dev, "_OSC: %s [%s]\n", msg, buf);
|
||||
}
|
||||
|
||||
static void decode_osc_support(struct acpi_pci_root *root, char *msg, u32 word)
|
||||
{
|
||||
decode_osc_bits(root, msg, word, pci_osc_support_bit,
|
||||
ARRAY_SIZE(pci_osc_support_bit));
|
||||
}
|
||||
|
||||
static void decode_osc_control(struct acpi_pci_root *root, char *msg, u32 word)
|
||||
{
|
||||
decode_osc_bits(root, msg, word, pci_osc_control_bit,
|
||||
ARRAY_SIZE(pci_osc_control_bit));
|
||||
}
|
||||
|
||||
static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766";
|
||||
|
||||
static acpi_status acpi_pci_run_osc(acpi_handle handle,
|
||||
@ -160,14 +209,14 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
|
||||
support &= OSC_PCI_SUPPORT_MASKS;
|
||||
support |= root->osc_support_set;
|
||||
|
||||
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_TYPE] = support;
|
||||
capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_DWORD] = support;
|
||||
if (control) {
|
||||
*control &= OSC_PCI_CONTROL_MASKS;
|
||||
capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set;
|
||||
capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set;
|
||||
} else {
|
||||
/* Run _OSC query only with existing controls. */
|
||||
capbuf[OSC_CONTROL_TYPE] = root->osc_control_set;
|
||||
capbuf[OSC_CONTROL_DWORD] = root->osc_control_set;
|
||||
}
|
||||
|
||||
status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
|
||||
@ -182,11 +231,7 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,
|
||||
static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle tmp;
|
||||
|
||||
status = acpi_get_handle(root->device->handle, "_OSC", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
mutex_lock(&osc_lock);
|
||||
status = acpi_pci_query_osc(root, flags, NULL);
|
||||
mutex_unlock(&osc_lock);
|
||||
@ -318,9 +363,8 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
|
||||
acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
|
||||
{
|
||||
struct acpi_pci_root *root;
|
||||
acpi_status status;
|
||||
acpi_status status = AE_OK;
|
||||
u32 ctrl, capbuf[3];
|
||||
acpi_handle tmp;
|
||||
|
||||
if (!mask)
|
||||
return AE_BAD_PARAMETER;
|
||||
@ -333,10 +377,6 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
|
||||
if (!root)
|
||||
return AE_NOT_EXIST;
|
||||
|
||||
status = acpi_get_handle(handle, "_OSC", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
mutex_lock(&osc_lock);
|
||||
|
||||
*mask = ctrl | root->osc_control_set;
|
||||
@ -351,17 +391,21 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
|
||||
goto out;
|
||||
if (ctrl == *mask)
|
||||
break;
|
||||
decode_osc_control(root, "platform does not support",
|
||||
ctrl & ~(*mask));
|
||||
ctrl = *mask;
|
||||
}
|
||||
|
||||
if ((ctrl & req) != req) {
|
||||
decode_osc_control(root, "not requesting control; platform does not support",
|
||||
req & ~(ctrl));
|
||||
status = AE_SUPPORT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
capbuf[OSC_QUERY_TYPE] = 0;
|
||||
capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
|
||||
capbuf[OSC_CONTROL_TYPE] = ctrl;
|
||||
capbuf[OSC_QUERY_DWORD] = 0;
|
||||
capbuf[OSC_SUPPORT_DWORD] = root->osc_support_set;
|
||||
capbuf[OSC_CONTROL_DWORD] = ctrl;
|
||||
status = acpi_pci_run_osc(handle, capbuf, mask);
|
||||
if (ACPI_SUCCESS(status))
|
||||
root->osc_control_set = *mask;
|
||||
@ -371,6 +415,87 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_pci_osc_control_set);
|
||||
|
||||
static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
|
||||
int *clear_aspm)
|
||||
{
|
||||
u32 support, control, requested;
|
||||
acpi_status status;
|
||||
struct acpi_device *device = root->device;
|
||||
acpi_handle handle = device->handle;
|
||||
|
||||
/*
|
||||
* All supported architectures that use ACPI have support for
|
||||
* PCI domains, so we indicate this in _OSC support capabilities.
|
||||
*/
|
||||
support = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
|
||||
if (pci_ext_cfg_avail())
|
||||
support |= OSC_PCI_EXT_CONFIG_SUPPORT;
|
||||
if (pcie_aspm_support_enabled())
|
||||
support |= OSC_PCI_ASPM_SUPPORT | OSC_PCI_CLOCK_PM_SUPPORT;
|
||||
if (pci_msi_enabled())
|
||||
support |= OSC_PCI_MSI_SUPPORT;
|
||||
|
||||
decode_osc_support(root, "OS supports", support);
|
||||
status = acpi_pci_osc_support(root, support);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n",
|
||||
acpi_format_exception(status));
|
||||
*no_aspm = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pcie_ports_disabled) {
|
||||
dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) {
|
||||
decode_osc_support(root, "not requesting OS control; OS requires",
|
||||
ACPI_PCIE_REQ_SUPPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL
|
||||
| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
|
||||
| OSC_PCI_EXPRESS_PME_CONTROL;
|
||||
|
||||
if (pci_aer_available()) {
|
||||
if (aer_acpi_firmware_first())
|
||||
dev_info(&device->dev,
|
||||
"PCIe AER handled by firmware\n");
|
||||
else
|
||||
control |= OSC_PCI_EXPRESS_AER_CONTROL;
|
||||
}
|
||||
|
||||
requested = control;
|
||||
status = acpi_pci_osc_control_set(handle, &control,
|
||||
OSC_PCI_EXPRESS_CAPABILITY_CONTROL);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
decode_osc_control(root, "OS now controls", control);
|
||||
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
|
||||
/*
|
||||
* We have ASPM control, but the FADT indicates
|
||||
* that it's unsupported. Clear it.
|
||||
*/
|
||||
*clear_aspm = 1;
|
||||
}
|
||||
} else {
|
||||
decode_osc_control(root, "OS requested", requested);
|
||||
decode_osc_control(root, "platform willing to grant", control);
|
||||
dev_info(&device->dev, "_OSC failed (%s); disabling ASPM\n",
|
||||
acpi_format_exception(status));
|
||||
|
||||
/*
|
||||
* We want to disable ASPM here, but aspm_disabled
|
||||
* needs to remain in its state from boot so that we
|
||||
* properly handle PCIe 1.1 devices. So we set this
|
||||
* flag here, to defer the action until after the ACPI
|
||||
* root scan.
|
||||
*/
|
||||
*no_aspm = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_pci_root_add(struct acpi_device *device,
|
||||
const struct acpi_device_id *not_used)
|
||||
{
|
||||
@ -378,9 +503,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
||||
acpi_status status;
|
||||
int result;
|
||||
struct acpi_pci_root *root;
|
||||
u32 flags, base_flags;
|
||||
acpi_handle handle = device->handle;
|
||||
bool no_aspm = false, clear_aspm = false;
|
||||
int no_aspm = 0, clear_aspm = 0;
|
||||
|
||||
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
|
||||
if (!root)
|
||||
@ -433,81 +557,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
|
||||
|
||||
root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);
|
||||
|
||||
/*
|
||||
* All supported architectures that use ACPI have support for
|
||||
* PCI domains, so we indicate this in _OSC support capabilities.
|
||||
*/
|
||||
flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
|
||||
acpi_pci_osc_support(root, flags);
|
||||
|
||||
if (pci_ext_cfg_avail())
|
||||
flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
|
||||
if (pcie_aspm_support_enabled()) {
|
||||
flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
|
||||
OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
|
||||
}
|
||||
if (pci_msi_enabled())
|
||||
flags |= OSC_MSI_SUPPORT;
|
||||
if (flags != base_flags) {
|
||||
status = acpi_pci_osc_support(root, flags);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_info(&device->dev, "ACPI _OSC support "
|
||||
"notification failed, disabling PCIe ASPM\n");
|
||||
no_aspm = true;
|
||||
flags = base_flags;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pcie_ports_disabled
|
||||
&& (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
|
||||
flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
|
||||
| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
|
||||
| OSC_PCI_EXPRESS_PME_CONTROL;
|
||||
|
||||
if (pci_aer_available()) {
|
||||
if (aer_acpi_firmware_first())
|
||||
dev_dbg(&device->dev,
|
||||
"PCIe errors handled by BIOS.\n");
|
||||
else
|
||||
flags |= OSC_PCI_EXPRESS_AER_CONTROL;
|
||||
}
|
||||
|
||||
dev_info(&device->dev,
|
||||
"Requesting ACPI _OSC control (0x%02x)\n", flags);
|
||||
|
||||
status = acpi_pci_osc_control_set(handle, &flags,
|
||||
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
dev_info(&device->dev,
|
||||
"ACPI _OSC control (0x%02x) granted\n", flags);
|
||||
if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
|
||||
/*
|
||||
* We have ASPM control, but the FADT indicates
|
||||
* that it's unsupported. Clear it.
|
||||
*/
|
||||
clear_aspm = true;
|
||||
}
|
||||
} else {
|
||||
dev_info(&device->dev,
|
||||
"ACPI _OSC request failed (%s), "
|
||||
"returned control mask: 0x%02x\n",
|
||||
acpi_format_exception(status), flags);
|
||||
dev_info(&device->dev,
|
||||
"ACPI _OSC control for PCIe not granted, disabling ASPM\n");
|
||||
/*
|
||||
* We want to disable ASPM here, but aspm_disabled
|
||||
* needs to remain in its state from boot so that we
|
||||
* properly handle PCIe 1.1 devices. So we set this
|
||||
* flag here, to defer the action until after the ACPI
|
||||
* root scan.
|
||||
*/
|
||||
no_aspm = true;
|
||||
}
|
||||
} else {
|
||||
dev_info(&device->dev,
|
||||
"Unable to request _OSC control "
|
||||
"(_OSC support mask: 0x%02x)\n", flags);
|
||||
}
|
||||
negotiate_os_control(root, &no_aspm, &clear_aspm);
|
||||
|
||||
/*
|
||||
* TBD: Need PCI interface for enumeration/configuration of roots.
|
||||
|
@ -1174,23 +1174,16 @@ int evergreen_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
|
||||
|
||||
void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
|
||||
{
|
||||
u16 ctl, v;
|
||||
int err;
|
||||
|
||||
err = pcie_capability_read_word(rdev->pdev, PCI_EXP_DEVCTL, &ctl);
|
||||
if (err)
|
||||
return;
|
||||
|
||||
v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12;
|
||||
int readrq;
|
||||
u16 v;
|
||||
|
||||
readrq = pcie_get_readrq(rdev->pdev);
|
||||
v = ffs(readrq) - 8;
|
||||
/* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it
|
||||
* to avoid hangs or perfomance issues
|
||||
*/
|
||||
if ((v == 0) || (v == 6) || (v == 7)) {
|
||||
ctl &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
ctl |= (2 << 12);
|
||||
pcie_capability_write_word(rdev->pdev, PCI_EXP_DEVCTL, ctl);
|
||||
}
|
||||
if ((v == 0) || (v == 6) || (v == 7))
|
||||
pcie_set_readrq(rdev->pdev, 512);
|
||||
}
|
||||
|
||||
static bool dce4_is_in_vblank(struct radeon_device *rdev, int crtc)
|
||||
|
@ -51,8 +51,8 @@
|
||||
* file calls, even though this violates some
|
||||
* expectations of harmlessness.
|
||||
*/
|
||||
static int qib_tune_pcie_caps(struct qib_devdata *);
|
||||
static int qib_tune_pcie_coalesce(struct qib_devdata *);
|
||||
static void qib_tune_pcie_caps(struct qib_devdata *);
|
||||
static void qib_tune_pcie_coalesce(struct qib_devdata *);
|
||||
|
||||
/*
|
||||
* Do all the common PCIe setup and initialization.
|
||||
@ -476,30 +476,6 @@ void qib_pcie_reenable(struct qib_devdata *dd, u16 cmd, u8 iline, u8 cline)
|
||||
"pci_enable_device failed after reset: %d\n", r);
|
||||
}
|
||||
|
||||
/* code to adjust PCIe capabilities. */
|
||||
|
||||
static int fld2val(int wd, int mask)
|
||||
{
|
||||
int lsbmask;
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
wd &= mask;
|
||||
lsbmask = mask ^ (mask & (mask - 1));
|
||||
wd /= lsbmask;
|
||||
return wd;
|
||||
}
|
||||
|
||||
static int val2fld(int wd, int mask)
|
||||
{
|
||||
int lsbmask;
|
||||
|
||||
if (!mask)
|
||||
return 0;
|
||||
lsbmask = mask ^ (mask & (mask - 1));
|
||||
wd *= lsbmask;
|
||||
return wd;
|
||||
}
|
||||
|
||||
static int qib_pcie_coalesce;
|
||||
module_param_named(pcie_coalesce, qib_pcie_coalesce, int, S_IRUGO);
|
||||
@ -511,7 +487,7 @@ MODULE_PARM_DESC(pcie_coalesce, "tune PCIe colescing on some Intel chipsets");
|
||||
* of these chipsets, with some BIOS settings, and enabling it on those
|
||||
* systems may result in the system crashing, and/or data corruption.
|
||||
*/
|
||||
static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
|
||||
static void qib_tune_pcie_coalesce(struct qib_devdata *dd)
|
||||
{
|
||||
int r;
|
||||
struct pci_dev *parent;
|
||||
@ -519,18 +495,18 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
|
||||
u32 mask, bits, val;
|
||||
|
||||
if (!qib_pcie_coalesce)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
/* Find out supported and configured values for parent (root) */
|
||||
parent = dd->pcidev->bus->self;
|
||||
if (parent->bus->parent) {
|
||||
qib_devinfo(dd->pcidev, "Parent not root\n");
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
if (!pci_is_pcie(parent))
|
||||
return 1;
|
||||
return;
|
||||
if (parent->vendor != 0x8086)
|
||||
return 1;
|
||||
return;
|
||||
|
||||
/*
|
||||
* - bit 12: Max_rdcmp_Imt_EN: need to set to 1
|
||||
@ -563,13 +539,12 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
|
||||
mask = (3U << 24) | (7U << 10);
|
||||
} else {
|
||||
/* not one of the chipsets that we know about */
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
pci_read_config_dword(parent, 0x48, &val);
|
||||
val &= ~mask;
|
||||
val |= bits;
|
||||
r = pci_write_config_dword(parent, 0x48, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -580,55 +555,44 @@ static int qib_pcie_caps;
|
||||
module_param_named(pcie_caps, qib_pcie_caps, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)");
|
||||
|
||||
static int qib_tune_pcie_caps(struct qib_devdata *dd)
|
||||
static void qib_tune_pcie_caps(struct qib_devdata *dd)
|
||||
{
|
||||
int ret = 1; /* Assume the worst */
|
||||
struct pci_dev *parent;
|
||||
u16 pcaps, pctl, ecaps, ectl;
|
||||
int rc_sup, ep_sup;
|
||||
int rc_cur, ep_cur;
|
||||
u16 rc_mpss, rc_mps, ep_mpss, ep_mps;
|
||||
u16 rc_mrrs, ep_mrrs, max_mrrs;
|
||||
|
||||
/* Find out supported and configured values for parent (root) */
|
||||
parent = dd->pcidev->bus->self;
|
||||
if (parent->bus->parent) {
|
||||
if (!pci_is_root_bus(parent->bus)) {
|
||||
qib_devinfo(dd->pcidev, "Parent not root\n");
|
||||
goto bail;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pci_is_pcie(parent) || !pci_is_pcie(dd->pcidev))
|
||||
goto bail;
|
||||
pcie_capability_read_word(parent, PCI_EXP_DEVCAP, &pcaps);
|
||||
pcie_capability_read_word(parent, PCI_EXP_DEVCTL, &pctl);
|
||||
return;
|
||||
|
||||
rc_mpss = parent->pcie_mpss;
|
||||
rc_mps = ffs(pcie_get_mps(parent)) - 8;
|
||||
/* Find out supported and configured values for endpoint (us) */
|
||||
pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCAP, &ecaps);
|
||||
pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &ectl);
|
||||
ep_mpss = dd->pcidev->pcie_mpss;
|
||||
ep_mps = ffs(pcie_get_mps(dd->pcidev)) - 8;
|
||||
|
||||
ret = 0;
|
||||
/* Find max payload supported by root, endpoint */
|
||||
rc_sup = fld2val(pcaps, PCI_EXP_DEVCAP_PAYLOAD);
|
||||
ep_sup = fld2val(ecaps, PCI_EXP_DEVCAP_PAYLOAD);
|
||||
if (rc_sup > ep_sup)
|
||||
rc_sup = ep_sup;
|
||||
|
||||
rc_cur = fld2val(pctl, PCI_EXP_DEVCTL_PAYLOAD);
|
||||
ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_PAYLOAD);
|
||||
if (rc_mpss > ep_mpss)
|
||||
rc_mpss = ep_mpss;
|
||||
|
||||
/* If Supported greater than limit in module param, limit it */
|
||||
if (rc_sup > (qib_pcie_caps & 7))
|
||||
rc_sup = qib_pcie_caps & 7;
|
||||
if (rc_mpss > (qib_pcie_caps & 7))
|
||||
rc_mpss = qib_pcie_caps & 7;
|
||||
/* If less than (allowed, supported), bump root payload */
|
||||
if (rc_sup > rc_cur) {
|
||||
rc_cur = rc_sup;
|
||||
pctl = (pctl & ~PCI_EXP_DEVCTL_PAYLOAD) |
|
||||
val2fld(rc_cur, PCI_EXP_DEVCTL_PAYLOAD);
|
||||
pcie_capability_write_word(parent, PCI_EXP_DEVCTL, pctl);
|
||||
if (rc_mpss > rc_mps) {
|
||||
rc_mps = rc_mpss;
|
||||
pcie_set_mps(parent, 128 << rc_mps);
|
||||
}
|
||||
/* If less than (allowed, supported), bump endpoint payload */
|
||||
if (rc_sup > ep_cur) {
|
||||
ep_cur = rc_sup;
|
||||
ectl = (ectl & ~PCI_EXP_DEVCTL_PAYLOAD) |
|
||||
val2fld(ep_cur, PCI_EXP_DEVCTL_PAYLOAD);
|
||||
pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, ectl);
|
||||
if (rc_mpss > ep_mps) {
|
||||
ep_mps = rc_mpss;
|
||||
pcie_set_mps(dd->pcidev, 128 << ep_mps);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -636,26 +600,22 @@ static int qib_tune_pcie_caps(struct qib_devdata *dd)
|
||||
* No field for max supported, but PCIe spec limits it to 4096,
|
||||
* which is code '5' (log2(4096) - 7)
|
||||
*/
|
||||
rc_sup = 5;
|
||||
if (rc_sup > ((qib_pcie_caps >> 4) & 7))
|
||||
rc_sup = (qib_pcie_caps >> 4) & 7;
|
||||
rc_cur = fld2val(pctl, PCI_EXP_DEVCTL_READRQ);
|
||||
ep_cur = fld2val(ectl, PCI_EXP_DEVCTL_READRQ);
|
||||
max_mrrs = 5;
|
||||
if (max_mrrs > ((qib_pcie_caps >> 4) & 7))
|
||||
max_mrrs = (qib_pcie_caps >> 4) & 7;
|
||||
|
||||
if (rc_sup > rc_cur) {
|
||||
rc_cur = rc_sup;
|
||||
pctl = (pctl & ~PCI_EXP_DEVCTL_READRQ) |
|
||||
val2fld(rc_cur, PCI_EXP_DEVCTL_READRQ);
|
||||
pcie_capability_write_word(parent, PCI_EXP_DEVCTL, pctl);
|
||||
max_mrrs = 128 << max_mrrs;
|
||||
rc_mrrs = pcie_get_readrq(parent);
|
||||
ep_mrrs = pcie_get_readrq(dd->pcidev);
|
||||
|
||||
if (max_mrrs > rc_mrrs) {
|
||||
rc_mrrs = max_mrrs;
|
||||
pcie_set_readrq(parent, rc_mrrs);
|
||||
}
|
||||
if (rc_sup > ep_cur) {
|
||||
ep_cur = rc_sup;
|
||||
ectl = (ectl & ~PCI_EXP_DEVCTL_READRQ) |
|
||||
val2fld(ep_cur, PCI_EXP_DEVCTL_READRQ);
|
||||
pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, ectl);
|
||||
if (max_mrrs > ep_mrrs) {
|
||||
ep_mrrs = max_mrrs;
|
||||
pcie_set_readrq(dd->pcidev, ep_mrrs);
|
||||
}
|
||||
bail:
|
||||
return ret;
|
||||
}
|
||||
/* End of PCIe capability tuning */
|
||||
|
||||
|
@ -15,8 +15,22 @@ config PCI_EXYNOS
|
||||
select PCIEPORTBUS
|
||||
select PCIE_DW
|
||||
|
||||
config PCI_IMX6
|
||||
bool "Freescale i.MX6 PCIe controller"
|
||||
depends on SOC_IMX6Q
|
||||
select PCIEPORTBUS
|
||||
select PCIE_DW
|
||||
|
||||
config PCI_TEGRA
|
||||
bool "NVIDIA Tegra PCIe controller"
|
||||
depends on ARCH_TEGRA
|
||||
|
||||
config PCI_RCAR_GEN2
|
||||
bool "Renesas R-Car Gen2 Internal PCI controller"
|
||||
depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
|
||||
help
|
||||
Say Y here if you want internal PCI support on R-Car Gen2 SoC.
|
||||
There are 3 internal PCI controllers available with a single
|
||||
built-in EHCI/OHCI host controller present on each one.
|
||||
|
||||
endmenu
|
||||
|
@ -1,4 +1,6 @@
|
||||
obj-$(CONFIG_PCIE_DW) += pcie-designware.o
|
||||
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
|
||||
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
||||
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
|
||||
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
|
||||
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
|
||||
|
@ -48,6 +48,7 @@ struct exynos_pcie {
|
||||
#define PCIE_IRQ_SPECIAL 0x008
|
||||
#define PCIE_IRQ_EN_PULSE 0x00c
|
||||
#define PCIE_IRQ_EN_LEVEL 0x010
|
||||
#define IRQ_MSI_ENABLE (0x1 << 2)
|
||||
#define PCIE_IRQ_EN_SPECIAL 0x014
|
||||
#define PCIE_PWR_RESET 0x018
|
||||
#define PCIE_CORE_RESET 0x01c
|
||||
@ -77,18 +78,28 @@ struct exynos_pcie {
|
||||
#define PCIE_PHY_PLL_BIAS 0x00c
|
||||
#define PCIE_PHY_DCC_FEEDBACK 0x014
|
||||
#define PCIE_PHY_PLL_DIV_1 0x05c
|
||||
#define PCIE_PHY_COMMON_POWER 0x064
|
||||
#define PCIE_PHY_COMMON_PD_CMN (0x1 << 3)
|
||||
#define PCIE_PHY_TRSV0_EMP_LVL 0x084
|
||||
#define PCIE_PHY_TRSV0_DRV_LVL 0x088
|
||||
#define PCIE_PHY_TRSV0_RXCDR 0x0ac
|
||||
#define PCIE_PHY_TRSV0_POWER 0x0c4
|
||||
#define PCIE_PHY_TRSV0_PD_TSV (0x1 << 7)
|
||||
#define PCIE_PHY_TRSV0_LVCC 0x0dc
|
||||
#define PCIE_PHY_TRSV1_EMP_LVL 0x144
|
||||
#define PCIE_PHY_TRSV1_RXCDR 0x16c
|
||||
#define PCIE_PHY_TRSV1_POWER 0x184
|
||||
#define PCIE_PHY_TRSV1_PD_TSV (0x1 << 7)
|
||||
#define PCIE_PHY_TRSV1_LVCC 0x19c
|
||||
#define PCIE_PHY_TRSV2_EMP_LVL 0x204
|
||||
#define PCIE_PHY_TRSV2_RXCDR 0x22c
|
||||
#define PCIE_PHY_TRSV2_POWER 0x244
|
||||
#define PCIE_PHY_TRSV2_PD_TSV (0x1 << 7)
|
||||
#define PCIE_PHY_TRSV2_LVCC 0x25c
|
||||
#define PCIE_PHY_TRSV3_EMP_LVL 0x2c4
|
||||
#define PCIE_PHY_TRSV3_RXCDR 0x2ec
|
||||
#define PCIE_PHY_TRSV3_POWER 0x304
|
||||
#define PCIE_PHY_TRSV3_PD_TSV (0x1 << 7)
|
||||
#define PCIE_PHY_TRSV3_LVCC 0x31c
|
||||
|
||||
static inline void exynos_elb_writel(struct exynos_pcie *pcie, u32 val, u32 reg)
|
||||
@ -202,6 +213,58 @@ static void exynos_pcie_deassert_phy_reset(struct pcie_port *pp)
|
||||
exynos_blk_writel(exynos_pcie, 0, PCIE_PHY_TRSV_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_power_on_phy(struct pcie_port *pp)
|
||||
{
|
||||
u32 val;
|
||||
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER);
|
||||
val &= ~PCIE_PHY_COMMON_PD_CMN;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER);
|
||||
val &= ~PCIE_PHY_TRSV0_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER);
|
||||
val &= ~PCIE_PHY_TRSV1_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER);
|
||||
val &= ~PCIE_PHY_TRSV2_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER);
|
||||
val &= ~PCIE_PHY_TRSV3_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER);
|
||||
}
|
||||
|
||||
static void exynos_pcie_power_off_phy(struct pcie_port *pp)
|
||||
{
|
||||
u32 val;
|
||||
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_COMMON_POWER);
|
||||
val |= PCIE_PHY_COMMON_PD_CMN;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_COMMON_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV0_POWER);
|
||||
val |= PCIE_PHY_TRSV0_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV0_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV1_POWER);
|
||||
val |= PCIE_PHY_TRSV1_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV1_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV2_POWER);
|
||||
val |= PCIE_PHY_TRSV2_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV2_POWER);
|
||||
|
||||
val = exynos_phy_readl(exynos_pcie, PCIE_PHY_TRSV3_POWER);
|
||||
val |= PCIE_PHY_TRSV3_PD_TSV;
|
||||
exynos_phy_writel(exynos_pcie, val, PCIE_PHY_TRSV3_POWER);
|
||||
}
|
||||
|
||||
static void exynos_pcie_init_phy(struct pcie_port *pp)
|
||||
{
|
||||
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
|
||||
@ -270,6 +333,9 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
|
||||
/* de-assert phy reset */
|
||||
exynos_pcie_deassert_phy_reset(pp);
|
||||
|
||||
/* power on phy */
|
||||
exynos_pcie_power_on_phy(pp);
|
||||
|
||||
/* initialize phy */
|
||||
exynos_pcie_init_phy(pp);
|
||||
|
||||
@ -302,6 +368,9 @@ static int exynos_pcie_establish_link(struct pcie_port *pp)
|
||||
PCIE_PHY_PLL_LOCKED);
|
||||
dev_info(pp->dev, "PLL Locked: 0x%x\n", val);
|
||||
}
|
||||
/* power off phy */
|
||||
exynos_pcie_power_off_phy(pp);
|
||||
|
||||
dev_err(pp->dev, "PCIe Link Fail\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -342,9 +411,36 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct pcie_port *pp = arg;
|
||||
|
||||
dw_handle_msi_irq(pp);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void exynos_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
u32 val;
|
||||
struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
|
||||
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
/* enable MSI interrupt */
|
||||
val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL);
|
||||
val |= IRQ_MSI_ENABLE;
|
||||
exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL);
|
||||
return;
|
||||
}
|
||||
|
||||
static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
|
||||
{
|
||||
exynos_pcie_enable_irq_pulse(pp);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
exynos_pcie_msi_init(pp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -430,6 +526,22 @@ static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->msi_irq = platform_get_irq(pdev, 0);
|
||||
if (!pp->msi_irq) {
|
||||
dev_err(&pdev->dev, "failed to get msi irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, pp->msi_irq,
|
||||
exynos_pcie_msi_irq_handler,
|
||||
IRQF_SHARED, "exynos-pcie", pp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request msi irq\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pp->root_bus_nr = -1;
|
||||
pp->ops = &exynos_pcie_host_ops;
|
||||
|
||||
@ -487,18 +599,24 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
elbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
exynos_pcie->elbi_base = devm_ioremap_resource(&pdev->dev, elbi_base);
|
||||
if (IS_ERR(exynos_pcie->elbi_base))
|
||||
return PTR_ERR(exynos_pcie->elbi_base);
|
||||
if (IS_ERR(exynos_pcie->elbi_base)) {
|
||||
ret = PTR_ERR(exynos_pcie->elbi_base);
|
||||
goto fail_bus_clk;
|
||||
}
|
||||
|
||||
phy_base = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
exynos_pcie->phy_base = devm_ioremap_resource(&pdev->dev, phy_base);
|
||||
if (IS_ERR(exynos_pcie->phy_base))
|
||||
return PTR_ERR(exynos_pcie->phy_base);
|
||||
if (IS_ERR(exynos_pcie->phy_base)) {
|
||||
ret = PTR_ERR(exynos_pcie->phy_base);
|
||||
goto fail_bus_clk;
|
||||
}
|
||||
|
||||
block_base = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
exynos_pcie->block_base = devm_ioremap_resource(&pdev->dev, block_base);
|
||||
if (IS_ERR(exynos_pcie->block_base))
|
||||
return PTR_ERR(exynos_pcie->block_base);
|
||||
if (IS_ERR(exynos_pcie->block_base)) {
|
||||
ret = PTR_ERR(exynos_pcie->block_base);
|
||||
goto fail_bus_clk;
|
||||
}
|
||||
|
||||
ret = add_pcie_port(pp, pdev);
|
||||
if (ret < 0)
|
||||
@ -535,7 +653,7 @@ static struct platform_driver exynos_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-pcie",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(exynos_pcie_of_match),
|
||||
.of_match_table = exynos_pcie_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
568
drivers/pci/host/pci-imx6.c
Normal file
568
drivers/pci/host/pci-imx6.c
Normal file
@ -0,0 +1,568 @@
|
||||
/*
|
||||
* PCIe host controller driver for Freescale i.MX6 SoCs
|
||||
*
|
||||
* Copyright (C) 2013 Kosagi
|
||||
* http://www.kosagi.com
|
||||
*
|
||||
* Author: Sean Cross <xobs@kosagi.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/resource.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define to_imx6_pcie(x) container_of(x, struct imx6_pcie, pp)
|
||||
|
||||
struct imx6_pcie {
|
||||
int reset_gpio;
|
||||
int power_on_gpio;
|
||||
int wake_up_gpio;
|
||||
int disable_gpio;
|
||||
struct clk *lvds_gate;
|
||||
struct clk *sata_ref_100m;
|
||||
struct clk *pcie_ref_125m;
|
||||
struct clk *pcie_axi;
|
||||
struct pcie_port pp;
|
||||
struct regmap *iomuxc_gpr;
|
||||
void __iomem *mem_base;
|
||||
};
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
|
||||
#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
|
||||
|
||||
#define PCIE_PHY_CTRL (PL_OFFSET + 0x114)
|
||||
#define PCIE_PHY_CTRL_DATA_LOC 0
|
||||
#define PCIE_PHY_CTRL_CAP_ADR_LOC 16
|
||||
#define PCIE_PHY_CTRL_CAP_DAT_LOC 17
|
||||
#define PCIE_PHY_CTRL_WR_LOC 18
|
||||
#define PCIE_PHY_CTRL_RD_LOC 19
|
||||
|
||||
#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
|
||||
#define PCIE_PHY_STAT_ACK_LOC 16
|
||||
|
||||
/* PHY registers (not memory-mapped) */
|
||||
#define PCIE_PHY_RX_ASIC_OUT 0x100D
|
||||
|
||||
#define PHY_RX_OVRD_IN_LO 0x1005
|
||||
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
|
||||
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
|
||||
|
||||
static int pcie_phy_poll_ack(void __iomem *dbi_base, int exp_val)
|
||||
{
|
||||
u32 val;
|
||||
u32 max_iterations = 10;
|
||||
u32 wait_counter = 0;
|
||||
|
||||
do {
|
||||
val = readl(dbi_base + PCIE_PHY_STAT);
|
||||
val = (val >> PCIE_PHY_STAT_ACK_LOC) & 0x1;
|
||||
wait_counter++;
|
||||
|
||||
if (val == exp_val)
|
||||
return 0;
|
||||
|
||||
udelay(1);
|
||||
} while (wait_counter < max_iterations);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int pcie_phy_wait_ack(void __iomem *dbi_base, int addr)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
val = addr << PCIE_PHY_CTRL_DATA_LOC;
|
||||
writel(val, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
val |= (0x1 << PCIE_PHY_CTRL_CAP_ADR_LOC);
|
||||
writel(val, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
ret = pcie_phy_poll_ack(dbi_base, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = addr << PCIE_PHY_CTRL_DATA_LOC;
|
||||
writel(val, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
ret = pcie_phy_poll_ack(dbi_base, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read from the 16-bit PCIe PHY control registers (not memory-mapped) */
|
||||
static int pcie_phy_read(void __iomem *dbi_base, int addr , int *data)
|
||||
{
|
||||
u32 val, phy_ctl;
|
||||
int ret;
|
||||
|
||||
ret = pcie_phy_wait_ack(dbi_base, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* assert Read signal */
|
||||
phy_ctl = 0x1 << PCIE_PHY_CTRL_RD_LOC;
|
||||
writel(phy_ctl, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
ret = pcie_phy_poll_ack(dbi_base, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = readl(dbi_base + PCIE_PHY_STAT);
|
||||
*data = val & 0xffff;
|
||||
|
||||
/* deassert Read signal */
|
||||
writel(0x00, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
ret = pcie_phy_poll_ack(dbi_base, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcie_phy_write(void __iomem *dbi_base, int addr, int data)
|
||||
{
|
||||
u32 var;
|
||||
int ret;
|
||||
|
||||
/* write addr */
|
||||
/* cap addr */
|
||||
ret = pcie_phy_wait_ack(dbi_base, addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
var = data << PCIE_PHY_CTRL_DATA_LOC;
|
||||
writel(var, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
/* capture data */
|
||||
var |= (0x1 << PCIE_PHY_CTRL_CAP_DAT_LOC);
|
||||
writel(var, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
ret = pcie_phy_poll_ack(dbi_base, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* deassert cap data */
|
||||
var = data << PCIE_PHY_CTRL_DATA_LOC;
|
||||
writel(var, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
/* wait for ack de-assertion */
|
||||
ret = pcie_phy_poll_ack(dbi_base, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* assert wr signal */
|
||||
var = 0x1 << PCIE_PHY_CTRL_WR_LOC;
|
||||
writel(var, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
/* wait for ack */
|
||||
ret = pcie_phy_poll_ack(dbi_base, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* deassert wr signal */
|
||||
var = data << PCIE_PHY_CTRL_DATA_LOC;
|
||||
writel(var, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
/* wait for ack de-assertion */
|
||||
ret = pcie_phy_poll_ack(dbi_base, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(0x0, dbi_base + PCIE_PHY_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Added for PCI abort handling */
|
||||
static int imx6q_pcie_abort_handler(unsigned long addr,
|
||||
unsigned int fsr, struct pt_regs *regs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
|
||||
IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
|
||||
IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);
|
||||
|
||||
gpio_set_value(imx6_pcie->reset_gpio, 0);
|
||||
msleep(100);
|
||||
gpio_set_value(imx6_pcie->reset_gpio, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
|
||||
int ret;
|
||||
|
||||
if (gpio_is_valid(imx6_pcie->power_on_gpio))
|
||||
gpio_set_value(imx6_pcie->power_on_gpio, 1);
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
|
||||
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
|
||||
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
|
||||
|
||||
ret = clk_prepare_enable(imx6_pcie->sata_ref_100m);
|
||||
if (ret) {
|
||||
dev_err(pp->dev, "unable to enable sata_ref_100m\n");
|
||||
goto err_sata_ref;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(imx6_pcie->pcie_ref_125m);
|
||||
if (ret) {
|
||||
dev_err(pp->dev, "unable to enable pcie_ref_125m\n");
|
||||
goto err_pcie_ref;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(imx6_pcie->lvds_gate);
|
||||
if (ret) {
|
||||
dev_err(pp->dev, "unable to enable lvds_gate\n");
|
||||
goto err_lvds_gate;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(imx6_pcie->pcie_axi);
|
||||
if (ret) {
|
||||
dev_err(pp->dev, "unable to enable pcie_axi\n");
|
||||
goto err_pcie_axi;
|
||||
}
|
||||
|
||||
/* allow the clocks to stabilize */
|
||||
usleep_range(200, 500);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pcie_axi:
|
||||
clk_disable_unprepare(imx6_pcie->lvds_gate);
|
||||
err_lvds_gate:
|
||||
clk_disable_unprepare(imx6_pcie->pcie_ref_125m);
|
||||
err_pcie_ref:
|
||||
clk_disable_unprepare(imx6_pcie->sata_ref_100m);
|
||||
err_sata_ref:
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void imx6_pcie_init_phy(struct pcie_port *pp)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
|
||||
|
||||
/* configure constant input signal to the pcie ctrl and phy */
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_LOS_LEVEL, 9 << 4);
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
|
||||
IMX6Q_GPR8_TX_DEEMPH_GEN1, 0 << 0);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
|
||||
IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
|
||||
IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
|
||||
IMX6Q_GPR8_TX_SWING_FULL, 127 << 18);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR8,
|
||||
IMX6Q_GPR8_TX_SWING_LOW, 127 << 25);
|
||||
}
|
||||
|
||||
static void imx6_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
int count = 0;
|
||||
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
|
||||
|
||||
imx6_pcie_assert_core_reset(pp);
|
||||
|
||||
imx6_pcie_init_phy(pp);
|
||||
|
||||
imx6_pcie_deassert_core_reset(pp);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
|
||||
|
||||
while (!dw_pcie_link_up(pp)) {
|
||||
usleep_range(100, 1000);
|
||||
count++;
|
||||
if (count >= 200) {
|
||||
dev_err(pp->dev, "phy link never came up\n");
|
||||
dev_dbg(pp->dev,
|
||||
"DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
|
||||
readl(pp->dbi_base + PCIE_PHY_DEBUG_R0),
|
||||
readl(pp->dbi_base + PCIE_PHY_DEBUG_R1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int imx6_pcie_link_up(struct pcie_port *pp)
|
||||
{
|
||||
u32 rc, ltssm, rx_valid, temp;
|
||||
|
||||
/* link is debug bit 36, debug register 1 starts at bit 32 */
|
||||
rc = readl(pp->dbi_base + PCIE_PHY_DEBUG_R1) & (0x1 << (36 - 32));
|
||||
if (rc)
|
||||
return -EAGAIN;
|
||||
|
||||
/*
|
||||
* From L0, initiate MAC entry to gen2 if EP/RC supports gen2.
|
||||
* Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2).
|
||||
* If (MAC/LTSSM.state == Recovery.RcvrLock)
|
||||
* && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition
|
||||
* to gen2 is stuck
|
||||
*/
|
||||
pcie_phy_read(pp->dbi_base, PCIE_PHY_RX_ASIC_OUT, &rx_valid);
|
||||
ltssm = readl(pp->dbi_base + PCIE_PHY_DEBUG_R0) & 0x3F;
|
||||
|
||||
if (rx_valid & 0x01)
|
||||
return 0;
|
||||
|
||||
if (ltssm != 0x0d)
|
||||
return 0;
|
||||
|
||||
dev_err(pp->dev, "transition to gen2 is stuck, reset PHY!\n");
|
||||
|
||||
pcie_phy_read(pp->dbi_base,
|
||||
PHY_RX_OVRD_IN_LO, &temp);
|
||||
temp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN
|
||||
| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
|
||||
pcie_phy_write(pp->dbi_base,
|
||||
PHY_RX_OVRD_IN_LO, temp);
|
||||
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
pcie_phy_read(pp->dbi_base,
|
||||
PHY_RX_OVRD_IN_LO, &temp);
|
||||
temp &= ~(PHY_RX_OVRD_IN_LO_RX_DATA_EN
|
||||
| PHY_RX_OVRD_IN_LO_RX_PLL_EN);
|
||||
pcie_phy_write(pp->dbi_base,
|
||||
PHY_RX_OVRD_IN_LO, temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pcie_host_ops imx6_pcie_host_ops = {
|
||||
.link_up = imx6_pcie_link_up,
|
||||
.host_init = imx6_pcie_host_init,
|
||||
};
|
||||
|
||||
static int imx6_add_pcie_port(struct pcie_port *pp,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pp->irq = platform_get_irq(pdev, 0);
|
||||
if (!pp->irq) {
|
||||
dev_err(&pdev->dev, "failed to get irq\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pp->root_bus_nr = -1;
|
||||
pp->ops = &imx6_pcie_host_ops;
|
||||
|
||||
spin_lock_init(&pp->conf_lock);
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to initialize host\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init imx6_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie;
|
||||
struct pcie_port *pp;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
imx6_pcie = devm_kzalloc(&pdev->dev, sizeof(*imx6_pcie), GFP_KERNEL);
|
||||
if (!imx6_pcie)
|
||||
return -ENOMEM;
|
||||
|
||||
pp = &imx6_pcie->pp;
|
||||
pp->dev = &pdev->dev;
|
||||
|
||||
/* Added for PCI abort handling */
|
||||
hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0,
|
||||
"imprecise external abort");
|
||||
|
||||
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!dbi_base) {
|
||||
dev_err(&pdev->dev, "dbi_base memory resource not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pp->dbi_base = devm_ioremap_resource(&pdev->dev, dbi_base);
|
||||
if (IS_ERR(pp->dbi_base)) {
|
||||
ret = PTR_ERR(pp->dbi_base);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Fetch GPIOs */
|
||||
imx6_pcie->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
if (!gpio_is_valid(imx6_pcie->reset_gpio)) {
|
||||
dev_err(&pdev->dev, "no reset-gpio defined\n");
|
||||
ret = -ENODEV;
|
||||
}
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
imx6_pcie->reset_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"PCIe reset");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get reset gpio\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
imx6_pcie->power_on_gpio = of_get_named_gpio(np, "power-on-gpio", 0);
|
||||
if (gpio_is_valid(imx6_pcie->power_on_gpio)) {
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
imx6_pcie->power_on_gpio,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"PCIe power enable");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get power-on gpio\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
imx6_pcie->wake_up_gpio = of_get_named_gpio(np, "wake-up-gpio", 0);
|
||||
if (gpio_is_valid(imx6_pcie->wake_up_gpio)) {
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
imx6_pcie->wake_up_gpio,
|
||||
GPIOF_IN,
|
||||
"PCIe wake up");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get wake-up gpio\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
imx6_pcie->disable_gpio = of_get_named_gpio(np, "disable-gpio", 0);
|
||||
if (gpio_is_valid(imx6_pcie->disable_gpio)) {
|
||||
ret = devm_gpio_request_one(&pdev->dev,
|
||||
imx6_pcie->disable_gpio,
|
||||
GPIOF_OUT_INIT_HIGH,
|
||||
"PCIe disable endpoint");
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to get disable-ep gpio\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch clocks */
|
||||
imx6_pcie->lvds_gate = devm_clk_get(&pdev->dev, "lvds_gate");
|
||||
if (IS_ERR(imx6_pcie->lvds_gate)) {
|
||||
dev_err(&pdev->dev,
|
||||
"lvds_gate clock select missing or invalid\n");
|
||||
ret = PTR_ERR(imx6_pcie->lvds_gate);
|
||||
goto err;
|
||||
}
|
||||
|
||||
imx6_pcie->sata_ref_100m = devm_clk_get(&pdev->dev, "sata_ref_100m");
|
||||
if (IS_ERR(imx6_pcie->sata_ref_100m)) {
|
||||
dev_err(&pdev->dev,
|
||||
"sata_ref_100m clock source missing or invalid\n");
|
||||
ret = PTR_ERR(imx6_pcie->sata_ref_100m);
|
||||
goto err;
|
||||
}
|
||||
|
||||
imx6_pcie->pcie_ref_125m = devm_clk_get(&pdev->dev, "pcie_ref_125m");
|
||||
if (IS_ERR(imx6_pcie->pcie_ref_125m)) {
|
||||
dev_err(&pdev->dev,
|
||||
"pcie_ref_125m clock source missing or invalid\n");
|
||||
ret = PTR_ERR(imx6_pcie->pcie_ref_125m);
|
||||
goto err;
|
||||
}
|
||||
|
||||
imx6_pcie->pcie_axi = devm_clk_get(&pdev->dev, "pcie_axi");
|
||||
if (IS_ERR(imx6_pcie->pcie_axi)) {
|
||||
dev_err(&pdev->dev,
|
||||
"pcie_axi clock source missing or invalid\n");
|
||||
ret = PTR_ERR(imx6_pcie->pcie_axi);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Grab GPR config register range */
|
||||
imx6_pcie->iomuxc_gpr =
|
||||
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
|
||||
if (IS_ERR(imx6_pcie->iomuxc_gpr)) {
|
||||
dev_err(&pdev->dev, "unable to find iomuxc registers\n");
|
||||
ret = PTR_ERR(imx6_pcie->iomuxc_gpr);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = imx6_add_pcie_port(pp, pdev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
platform_set_drvdata(pdev, imx6_pcie);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx6_pcie_of_match[] = {
|
||||
{ .compatible = "fsl,imx6q-pcie", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx6_pcie_of_match);
|
||||
|
||||
static struct platform_driver imx6_pcie_driver = {
|
||||
.driver = {
|
||||
.name = "imx6q-pcie",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = imx6_pcie_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
/* Freescale PCIe driver does not allow module unload */
|
||||
|
||||
static int __init imx6_pcie_init(void)
|
||||
{
|
||||
return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
|
||||
}
|
||||
fs_initcall(imx6_pcie_init);
|
||||
|
||||
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
|
||||
MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");
|
||||
MODULE_LICENSE("GPL v2");
|
333
drivers/pci/host/pci-rcar-gen2.c
Normal file
333
drivers/pci/host/pci-rcar-gen2.c
Normal file
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* pci-rcar-gen2: internal PCI bus support
|
||||
*
|
||||
* Copyright (C) 2013 Renesas Solutions Corp.
|
||||
* Copyright (C) 2013 Cogent Embedded, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* AHB-PCI Bridge PCI communication registers */
|
||||
#define RCAR_AHBPCI_PCICOM_OFFSET 0x800
|
||||
|
||||
#define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00)
|
||||
#define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04)
|
||||
#define RCAR_PCIAHB_PREFETCH0 0x0
|
||||
#define RCAR_PCIAHB_PREFETCH4 0x1
|
||||
#define RCAR_PCIAHB_PREFETCH8 0x2
|
||||
#define RCAR_PCIAHB_PREFETCH16 0x3
|
||||
|
||||
#define RCAR_AHBPCI_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x10)
|
||||
#define RCAR_AHBPCI_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x14)
|
||||
#define RCAR_AHBPCI_WIN_CTR_MEM (3 << 1)
|
||||
#define RCAR_AHBPCI_WIN_CTR_CFG (5 << 1)
|
||||
#define RCAR_AHBPCI_WIN1_HOST (1 << 30)
|
||||
#define RCAR_AHBPCI_WIN1_DEVICE (1 << 31)
|
||||
|
||||
#define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20)
|
||||
#define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24)
|
||||
#define RCAR_PCI_INT_A (1 << 16)
|
||||
#define RCAR_PCI_INT_B (1 << 17)
|
||||
#define RCAR_PCI_INT_PME (1 << 19)
|
||||
|
||||
#define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30)
|
||||
#define RCAR_AHB_BUS_MMODE_HTRANS (1 << 0)
|
||||
#define RCAR_AHB_BUS_MMODE_BYTE_BURST (1 << 1)
|
||||
#define RCAR_AHB_BUS_MMODE_WR_INCR (1 << 2)
|
||||
#define RCAR_AHB_BUS_MMODE_HBUS_REQ (1 << 7)
|
||||
#define RCAR_AHB_BUS_SMODE_READYCTR (1 << 17)
|
||||
#define RCAR_AHB_BUS_MODE (RCAR_AHB_BUS_MMODE_HTRANS | \
|
||||
RCAR_AHB_BUS_MMODE_BYTE_BURST | \
|
||||
RCAR_AHB_BUS_MMODE_WR_INCR | \
|
||||
RCAR_AHB_BUS_MMODE_HBUS_REQ | \
|
||||
RCAR_AHB_BUS_SMODE_READYCTR)
|
||||
|
||||
#define RCAR_USBCTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x34)
|
||||
#define RCAR_USBCTR_USBH_RST (1 << 0)
|
||||
#define RCAR_USBCTR_PCICLK_MASK (1 << 1)
|
||||
#define RCAR_USBCTR_PLL_RST (1 << 2)
|
||||
#define RCAR_USBCTR_DIRPD (1 << 8)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN2_EN (1 << 9)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN1_256M (0 << 10)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN1_512M (1 << 10)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN1_1G (2 << 10)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN1_2G (3 << 10)
|
||||
#define RCAR_USBCTR_PCIAHB_WIN1_MASK (3 << 10)
|
||||
|
||||
#define RCAR_PCI_ARBITER_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x40)
|
||||
#define RCAR_PCI_ARBITER_PCIREQ0 (1 << 0)
|
||||
#define RCAR_PCI_ARBITER_PCIREQ1 (1 << 1)
|
||||
#define RCAR_PCI_ARBITER_PCIBP_MODE (1 << 12)
|
||||
|
||||
#define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48)
|
||||
|
||||
/* Number of internal PCI controllers */
|
||||
#define RCAR_PCI_NR_CONTROLLERS 3
|
||||
|
||||
struct rcar_pci_priv {
|
||||
void __iomem *reg;
|
||||
struct resource io_res;
|
||||
struct resource mem_res;
|
||||
struct resource *cfg_res;
|
||||
int irq;
|
||||
};
|
||||
|
||||
/* PCI configuration space operations */
|
||||
static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct pci_sys_data *sys = bus->sysdata;
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
int slot, val;
|
||||
|
||||
if (sys->busnr != bus->number || PCI_FUNC(devfn))
|
||||
return NULL;
|
||||
|
||||
/* Only one EHCI/OHCI device built-in */
|
||||
slot = PCI_SLOT(devfn);
|
||||
if (slot > 2)
|
||||
return NULL;
|
||||
|
||||
val = slot ? RCAR_AHBPCI_WIN1_DEVICE | RCAR_AHBPCI_WIN_CTR_CFG :
|
||||
RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG;
|
||||
|
||||
iowrite32(val, priv->reg + RCAR_AHBPCI_WIN1_CTR_REG);
|
||||
return priv->reg + (slot >> 1) * 0x100 + where;
|
||||
}
|
||||
|
||||
static int rcar_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where);
|
||||
|
||||
if (!reg)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
*val = ioread8(reg);
|
||||
break;
|
||||
case 2:
|
||||
*val = ioread16(reg);
|
||||
break;
|
||||
default:
|
||||
*val = ioread32(reg);
|
||||
break;
|
||||
}
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where);
|
||||
|
||||
if (!reg)
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
switch (size) {
|
||||
case 1:
|
||||
iowrite8(val, reg);
|
||||
break;
|
||||
case 2:
|
||||
iowrite16(val, reg);
|
||||
break;
|
||||
default:
|
||||
iowrite32(val, reg);
|
||||
break;
|
||||
}
|
||||
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/* PCI interrupt mapping */
|
||||
static int __init rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
struct pci_sys_data *sys = dev->bus->sysdata;
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
|
||||
return priv->irq;
|
||||
}
|
||||
|
||||
/* PCI host controller setup */
|
||||
static int __init rcar_pci_setup(int nr, struct pci_sys_data *sys)
|
||||
{
|
||||
struct rcar_pci_priv *priv = sys->private_data;
|
||||
void __iomem *reg = priv->reg;
|
||||
u32 val;
|
||||
|
||||
val = ioread32(reg + RCAR_PCI_UNIT_REV_REG);
|
||||
pr_info("PCI: bus%u revision %x\n", sys->busnr, val);
|
||||
|
||||
/* Disable Direct Power Down State and assert reset */
|
||||
val = ioread32(reg + RCAR_USBCTR_REG) & ~RCAR_USBCTR_DIRPD;
|
||||
val |= RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST;
|
||||
iowrite32(val, reg + RCAR_USBCTR_REG);
|
||||
udelay(4);
|
||||
|
||||
/* De-assert reset and set PCIAHB window1 size to 1GB */
|
||||
val &= ~(RCAR_USBCTR_PCIAHB_WIN1_MASK | RCAR_USBCTR_PCICLK_MASK |
|
||||
RCAR_USBCTR_USBH_RST | RCAR_USBCTR_PLL_RST);
|
||||
iowrite32(val | RCAR_USBCTR_PCIAHB_WIN1_1G, reg + RCAR_USBCTR_REG);
|
||||
|
||||
/* Configure AHB master and slave modes */
|
||||
iowrite32(RCAR_AHB_BUS_MODE, reg + RCAR_AHB_BUS_CTR_REG);
|
||||
|
||||
/* Configure PCI arbiter */
|
||||
val = ioread32(reg + RCAR_PCI_ARBITER_CTR_REG);
|
||||
val |= RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 |
|
||||
RCAR_PCI_ARBITER_PCIBP_MODE;
|
||||
iowrite32(val, reg + RCAR_PCI_ARBITER_CTR_REG);
|
||||
|
||||
/* PCI-AHB mapping: 0x40000000-0x80000000 */
|
||||
iowrite32(0x40000000 | RCAR_PCIAHB_PREFETCH16,
|
||||
reg + RCAR_PCIAHB_WIN1_CTR_REG);
|
||||
|
||||
/* AHB-PCI mapping: OHCI/EHCI registers */
|
||||
val = priv->mem_res.start | RCAR_AHBPCI_WIN_CTR_MEM;
|
||||
iowrite32(val, reg + RCAR_AHBPCI_WIN2_CTR_REG);
|
||||
|
||||
/* Enable AHB-PCI bridge PCI configuration access */
|
||||
iowrite32(RCAR_AHBPCI_WIN1_HOST | RCAR_AHBPCI_WIN_CTR_CFG,
|
||||
reg + RCAR_AHBPCI_WIN1_CTR_REG);
|
||||
/* Set PCI-AHB Window1 address */
|
||||
iowrite32(0x40000000 | PCI_BASE_ADDRESS_MEM_PREFETCH,
|
||||
reg + PCI_BASE_ADDRESS_1);
|
||||
/* Set AHB-PCI bridge PCI communication area address */
|
||||
val = priv->cfg_res->start + RCAR_AHBPCI_PCICOM_OFFSET;
|
||||
iowrite32(val, reg + PCI_BASE_ADDRESS_0);
|
||||
|
||||
val = ioread32(reg + PCI_COMMAND);
|
||||
val |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
|
||||
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
|
||||
iowrite32(val, reg + PCI_COMMAND);
|
||||
|
||||
/* Enable PCI interrupts */
|
||||
iowrite32(RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME,
|
||||
reg + RCAR_PCI_INT_ENABLE_REG);
|
||||
|
||||
/* Add PCI resources */
|
||||
pci_add_resource(&sys->resources, &priv->io_res);
|
||||
pci_add_resource(&sys->resources, &priv->mem_res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct pci_ops rcar_pci_ops = {
|
||||
.read = rcar_pci_read_config,
|
||||
.write = rcar_pci_write_config,
|
||||
};
|
||||
|
||||
static struct hw_pci rcar_hw_pci __initdata = {
|
||||
.map_irq = rcar_pci_map_irq,
|
||||
.ops = &rcar_pci_ops,
|
||||
.setup = rcar_pci_setup,
|
||||
};
|
||||
|
||||
static int rcar_pci_count __initdata;
|
||||
|
||||
static int __init rcar_pci_add_controller(struct rcar_pci_priv *priv)
|
||||
{
|
||||
void **private_data;
|
||||
int count;
|
||||
|
||||
if (rcar_hw_pci.nr_controllers < rcar_pci_count)
|
||||
goto add_priv;
|
||||
|
||||
/* (Re)allocate private data pointer array if needed */
|
||||
count = rcar_pci_count + RCAR_PCI_NR_CONTROLLERS;
|
||||
private_data = kzalloc(count * sizeof(void *), GFP_KERNEL);
|
||||
if (!private_data)
|
||||
return -ENOMEM;
|
||||
|
||||
rcar_pci_count = count;
|
||||
if (rcar_hw_pci.private_data) {
|
||||
memcpy(private_data, rcar_hw_pci.private_data,
|
||||
rcar_hw_pci.nr_controllers * sizeof(void *));
|
||||
kfree(rcar_hw_pci.private_data);
|
||||
}
|
||||
|
||||
rcar_hw_pci.private_data = private_data;
|
||||
|
||||
add_priv:
|
||||
/* Add private data pointer to the array */
|
||||
rcar_hw_pci.private_data[rcar_hw_pci.nr_controllers++] = priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init rcar_pci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *cfg_res, *mem_res;
|
||||
struct rcar_pci_priv *priv;
|
||||
void __iomem *reg;
|
||||
|
||||
cfg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
reg = devm_ioremap_resource(&pdev->dev, cfg_res);
|
||||
if (!reg)
|
||||
return -ENODEV;
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!mem_res || !mem_res->start)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct rcar_pci_priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->mem_res = *mem_res;
|
||||
/*
|
||||
* The controller does not support/use port I/O,
|
||||
* so setup a dummy port I/O region here.
|
||||
*/
|
||||
priv->io_res.start = priv->mem_res.start;
|
||||
priv->io_res.end = priv->mem_res.end;
|
||||
priv->io_res.flags = IORESOURCE_IO;
|
||||
|
||||
priv->cfg_res = cfg_res;
|
||||
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
priv->reg = reg;
|
||||
|
||||
return rcar_pci_add_controller(priv);
|
||||
}
|
||||
|
||||
static struct platform_driver rcar_pci_driver = {
|
||||
.driver = {
|
||||
.name = "pci-rcar-gen2",
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rcar_pci_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = platform_driver_probe(&rcar_pci_driver, rcar_pci_probe);
|
||||
if (!retval)
|
||||
pci_common_init(&rcar_hw_pci);
|
||||
|
||||
/* Private data pointer array is not needed any more */
|
||||
kfree(rcar_hw_pci.private_data);
|
||||
rcar_hw_pci.private_data = NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
subsys_initcall(rcar_pci_init);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Renesas R-Car Gen2 internal PCI");
|
||||
MODULE_AUTHOR("Valentine Barshak <valentine.barshak@cogentembedded.com>");
|
@ -408,7 +408,7 @@ static void __iomem *tegra_pcie_bus_map(struct tegra_pcie *pcie,
|
||||
|
||||
list_for_each_entry(bus, &pcie->busses, list)
|
||||
if (bus->nr == busnr)
|
||||
return bus->area->addr;
|
||||
return (void __iomem *)bus->area->addr;
|
||||
|
||||
bus = tegra_pcie_bus_alloc(pcie, busnr);
|
||||
if (IS_ERR(bus))
|
||||
@ -416,7 +416,7 @@ static void __iomem *tegra_pcie_bus_map(struct tegra_pcie *pcie,
|
||||
|
||||
list_add_tail(&bus->list, &pcie->busses);
|
||||
|
||||
return bus->area->addr;
|
||||
return (void __iomem *)bus->area->addr;
|
||||
}
|
||||
|
||||
static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
|
||||
|
@ -11,8 +11,11 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci_regs.h>
|
||||
@ -64,7 +67,7 @@
|
||||
|
||||
static struct hw_pci dw_pci;
|
||||
|
||||
unsigned long global_io_offset;
|
||||
static unsigned long global_io_offset;
|
||||
|
||||
static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
|
||||
{
|
||||
@ -115,8 +118,8 @@ static inline void dw_pcie_writel_rc(struct pcie_port *pp, u32 val, u32 reg)
|
||||
writel(val, pp->dbi_base + reg);
|
||||
}
|
||||
|
||||
int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -128,8 +131,8 @@ int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -142,6 +145,205 @@ int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct irq_chip dw_msi_irq_chip = {
|
||||
.name = "PCI-MSI",
|
||||
.irq_enable = unmask_msi_irq,
|
||||
.irq_disable = mask_msi_irq,
|
||||
.irq_mask = mask_msi_irq,
|
||||
.irq_unmask = unmask_msi_irq,
|
||||
};
|
||||
|
||||
/* MSI int handler */
|
||||
void dw_handle_msi_irq(struct pcie_port *pp)
|
||||
{
|
||||
unsigned long val;
|
||||
int i, pos, irq;
|
||||
|
||||
for (i = 0; i < MAX_MSI_CTRLS; i++) {
|
||||
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
|
||||
(u32 *)&val);
|
||||
if (val) {
|
||||
pos = 0;
|
||||
while ((pos = find_next_bit(&val, 32, pos)) != 32) {
|
||||
irq = irq_find_mapping(pp->irq_domain,
|
||||
i * 32 + pos);
|
||||
generic_handle_irq(irq);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
|
||||
}
|
||||
}
|
||||
|
||||
void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
|
||||
|
||||
/* program the msi_data */
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
|
||||
virt_to_phys((void *)pp->msi_data));
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
|
||||
}
|
||||
|
||||
static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
|
||||
{
|
||||
int flag = 1;
|
||||
|
||||
do {
|
||||
pos = find_next_zero_bit(pp->msi_irq_in_use,
|
||||
MAX_MSI_IRQS, pos);
|
||||
/*if you have reached to the end then get out from here.*/
|
||||
if (pos == MAX_MSI_IRQS)
|
||||
return -ENOSPC;
|
||||
/*
|
||||
* Check if this position is at correct offset.nvec is always a
|
||||
* power of two. pos0 must be nvec bit alligned.
|
||||
*/
|
||||
if (pos % msgvec)
|
||||
pos += msgvec - (pos % msgvec);
|
||||
else
|
||||
flag = 0;
|
||||
} while (flag);
|
||||
|
||||
*pos0 = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
|
||||
{
|
||||
int res, bit, irq, pos0, pos1, i;
|
||||
u32 val;
|
||||
struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
|
||||
|
||||
if (!pp) {
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pos0 = find_first_zero_bit(pp->msi_irq_in_use,
|
||||
MAX_MSI_IRQS);
|
||||
if (pos0 % no_irqs) {
|
||||
if (find_valid_pos0(pp, no_irqs, pos0, &pos0))
|
||||
goto no_valid_irq;
|
||||
}
|
||||
if (no_irqs > 1) {
|
||||
pos1 = find_next_bit(pp->msi_irq_in_use,
|
||||
MAX_MSI_IRQS, pos0);
|
||||
/* there must be nvec number of consecutive free bits */
|
||||
while ((pos1 - pos0) < no_irqs) {
|
||||
if (find_valid_pos0(pp, no_irqs, pos1, &pos0))
|
||||
goto no_valid_irq;
|
||||
pos1 = find_next_bit(pp->msi_irq_in_use,
|
||||
MAX_MSI_IRQS, pos0);
|
||||
}
|
||||
}
|
||||
|
||||
irq = irq_find_mapping(pp->irq_domain, pos0);
|
||||
if (!irq)
|
||||
goto no_valid_irq;
|
||||
|
||||
i = 0;
|
||||
while (i < no_irqs) {
|
||||
set_bit(pos0 + i, pp->msi_irq_in_use);
|
||||
irq_alloc_descs((irq + i), (irq + i), 1, 0);
|
||||
irq_set_msi_desc(irq + i, desc);
|
||||
/*Enable corresponding interrupt in MSI interrupt controller */
|
||||
res = ((pos0 + i) / 32) * 12;
|
||||
bit = (pos0 + i) % 32;
|
||||
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
|
||||
val |= 1 << bit;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
|
||||
i++;
|
||||
}
|
||||
|
||||
*pos = pos0;
|
||||
return irq;
|
||||
|
||||
no_valid_irq:
|
||||
*pos = pos0;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static void clear_irq(unsigned int irq)
|
||||
{
|
||||
int res, bit, val, pos;
|
||||
struct irq_desc *desc;
|
||||
struct msi_desc *msi;
|
||||
struct pcie_port *pp;
|
||||
struct irq_data *data = irq_get_irq_data(irq);
|
||||
|
||||
/* get the port structure */
|
||||
desc = irq_to_desc(irq);
|
||||
msi = irq_desc_get_msi_desc(desc);
|
||||
pp = sys_to_pcie(msi->dev->bus->sysdata);
|
||||
if (!pp) {
|
||||
BUG();
|
||||
return;
|
||||
}
|
||||
|
||||
pos = data->hwirq;
|
||||
|
||||
irq_free_desc(irq);
|
||||
|
||||
clear_bit(pos, pp->msi_irq_in_use);
|
||||
|
||||
/* Disable corresponding interrupt on MSI interrupt controller */
|
||||
res = (pos / 32) * 12;
|
||||
bit = pos % 32;
|
||||
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
|
||||
val &= ~(1 << bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
|
||||
}
|
||||
|
||||
static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
|
||||
struct msi_desc *desc)
|
||||
{
|
||||
int irq, pos, msgvec;
|
||||
u16 msg_ctr;
|
||||
struct msi_msg msg;
|
||||
struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
|
||||
|
||||
if (!pp) {
|
||||
BUG();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
|
||||
&msg_ctr);
|
||||
msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
if (msgvec == 0)
|
||||
msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
|
||||
if (msgvec > 5)
|
||||
msgvec = 0;
|
||||
|
||||
irq = assign_irq((1 << msgvec), desc, &pos);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
|
||||
msg_ctr |= msgvec << 4;
|
||||
pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
|
||||
msg_ctr);
|
||||
desc->msi_attrib.multiple = msgvec;
|
||||
|
||||
msg.address_lo = virt_to_phys((void *)pp->msi_data);
|
||||
msg.address_hi = 0x0;
|
||||
msg.data = pos;
|
||||
write_msi_msg(irq, &msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
|
||||
{
|
||||
clear_irq(irq);
|
||||
}
|
||||
|
||||
static struct msi_chip dw_pcie_msi_chip = {
|
||||
.setup_irq = dw_msi_setup_irq,
|
||||
.teardown_irq = dw_msi_teardown_irq,
|
||||
};
|
||||
|
||||
int dw_pcie_link_up(struct pcie_port *pp)
|
||||
{
|
||||
if (pp->ops->link_up)
|
||||
@ -150,12 +352,27 @@ int dw_pcie_link_up(struct pcie_port *pp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
|
||||
irq_set_chip_data(irq, domain->host_data);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops msi_domain_ops = {
|
||||
.map = dw_pcie_msi_map,
|
||||
};
|
||||
|
||||
int __init dw_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct device_node *np = pp->dev->of_node;
|
||||
struct of_pci_range range;
|
||||
struct of_pci_range_parser parser;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
if (of_pci_range_parser_init(&parser, np)) {
|
||||
dev_err(pp->dev, "missing ranges property\n");
|
||||
@ -223,6 +440,19 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
|
||||
MAX_MSI_IRQS, &msi_domain_ops,
|
||||
&dw_pcie_msi_chip);
|
||||
if (!pp->irq_domain) {
|
||||
dev_err(pp->dev, "irq domain init failed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_MSI_IRQS; i++)
|
||||
irq_create_mapping(pp->irq_domain, i);
|
||||
}
|
||||
|
||||
if (pp->ops->host_init)
|
||||
pp->ops->host_init(pp);
|
||||
|
||||
@ -438,7 +668,7 @@ static struct pci_ops dw_pcie_ops = {
|
||||
.write = dw_pcie_wr_conf,
|
||||
};
|
||||
|
||||
int dw_pcie_setup(int nr, struct pci_sys_data *sys)
|
||||
static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
|
||||
{
|
||||
struct pcie_port *pp;
|
||||
|
||||
@ -461,7 +691,7 @@ int dw_pcie_setup(int nr, struct pci_sys_data *sys)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
||||
static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct pcie_port *pp = sys_to_pcie(sys);
|
||||
@ -478,17 +708,28 @@ struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
|
||||
return bus;
|
||||
}
|
||||
|
||||
int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata);
|
||||
|
||||
return pp->irq;
|
||||
}
|
||||
|
||||
static void dw_pcie_add_bus(struct pci_bus *bus)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
struct pcie_port *pp = sys_to_pcie(bus->sysdata);
|
||||
|
||||
dw_pcie_msi_chip.dev = pp->dev;
|
||||
bus->msi = &dw_pcie_msi_chip;
|
||||
}
|
||||
}
|
||||
|
||||
static struct hw_pci dw_pci = {
|
||||
.setup = dw_pcie_setup,
|
||||
.scan = dw_pcie_scan_bus,
|
||||
.map_irq = dw_pcie_map_irq,
|
||||
.add_bus = dw_pcie_add_bus,
|
||||
};
|
||||
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
@ -11,6 +11,9 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _PCIE_DESIGNWARE_H
|
||||
#define _PCIE_DESIGNWARE_H
|
||||
|
||||
struct pcie_port_info {
|
||||
u32 cfg0_size;
|
||||
u32 cfg1_size;
|
||||
@ -20,6 +23,14 @@ struct pcie_port_info {
|
||||
phys_addr_t mem_bus_addr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Maximum number of MSI IRQs can be 256 per controller. But keep
|
||||
* it 32 as of now. Probably we will never need more than 32. If needed,
|
||||
* then increment it in multiple of 32.
|
||||
*/
|
||||
#define MAX_MSI_IRQS 32
|
||||
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
|
||||
|
||||
struct pcie_port {
|
||||
struct device *dev;
|
||||
u8 root_bus_nr;
|
||||
@ -38,6 +49,10 @@ struct pcie_port {
|
||||
int irq;
|
||||
u32 lanes;
|
||||
struct pcie_host_ops *ops;
|
||||
int msi_irq;
|
||||
struct irq_domain *irq_domain;
|
||||
unsigned long msi_data;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
|
||||
};
|
||||
|
||||
struct pcie_host_ops {
|
||||
@ -51,15 +66,12 @@ struct pcie_host_ops {
|
||||
void (*host_init)(struct pcie_port *pp);
|
||||
};
|
||||
|
||||
extern unsigned long global_io_offset;
|
||||
|
||||
int cfg_read(void __iomem *addr, int where, int size, u32 *val);
|
||||
int cfg_write(void __iomem *addr, int where, int size, u32 val);
|
||||
int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val);
|
||||
int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val);
|
||||
void dw_handle_msi_irq(struct pcie_port *pp);
|
||||
void dw_pcie_msi_init(struct pcie_port *pp);
|
||||
int dw_pcie_link_up(struct pcie_port *pp);
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp);
|
||||
int dw_pcie_host_init(struct pcie_port *pp);
|
||||
int dw_pcie_setup(int nr, struct pci_sys_data *sys);
|
||||
struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys);
|
||||
int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin);
|
||||
|
||||
#endif /* _PCIE_DESIGNWARE_H */
|
||||
|
@ -338,7 +338,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
||||
acpi_handle chandle, handle;
|
||||
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
flags &= OSC_SHPC_NATIVE_HP_CONTROL;
|
||||
flags &= OSC_PCI_SHPC_NATIVE_HP_CONTROL;
|
||||
if (!flags) {
|
||||
err("Invalid flags %u specified!\n", flags);
|
||||
return -EINVAL;
|
||||
|
@ -39,16 +39,6 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci_hotplug.h>
|
||||
|
||||
#define dbg(format, arg...) \
|
||||
do { \
|
||||
if (acpiphp_debug) \
|
||||
printk(KERN_DEBUG "%s: " format, \
|
||||
MY_NAME , ## arg); \
|
||||
} while (0)
|
||||
#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
|
||||
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
|
||||
#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
|
||||
|
||||
struct acpiphp_context;
|
||||
struct acpiphp_bridge;
|
||||
struct acpiphp_slot;
|
||||
|
@ -31,6 +31,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "acpiphp: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -43,12 +45,9 @@
|
||||
#include <linux/smp.h>
|
||||
#include "acpiphp.h"
|
||||
|
||||
#define MY_NAME "acpiphp"
|
||||
|
||||
/* name size which is used for entries in pcihpfs */
|
||||
#define SLOT_NAME_SIZE 21 /* {_SUN} */
|
||||
|
||||
bool acpiphp_debug;
|
||||
bool acpiphp_disabled;
|
||||
|
||||
/* local variables */
|
||||
@ -61,9 +60,7 @@ static struct acpiphp_attention_info *attention_info;
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
|
||||
MODULE_PARM_DESC(disable, "disable acpiphp driver");
|
||||
module_param_named(debug, acpiphp_debug, bool, 0644);
|
||||
module_param_named(disable, acpiphp_disabled, bool, 0444);
|
||||
|
||||
/* export the attention callback registration methods */
|
||||
@ -139,7 +136,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
/* enable the specified slot */
|
||||
return acpiphp_enable_slot(slot->acpi_slot);
|
||||
@ -156,7 +153,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
/* disable the specified slot */
|
||||
return acpiphp_disable_and_eject_slot(slot->acpi_slot);
|
||||
@ -176,7 +173,8 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__,
|
||||
hotplug_slot_name(hotplug_slot));
|
||||
|
||||
if (attention_info && try_module_get(attention_info->owner)) {
|
||||
retval = attention_info->set_attn(hotplug_slot, status);
|
||||
@ -199,7 +197,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
*value = acpiphp_get_power_status(slot->acpi_slot);
|
||||
|
||||
@ -221,7 +219,8 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__,
|
||||
hotplug_slot_name(hotplug_slot));
|
||||
|
||||
if (attention_info && try_module_get(attention_info->owner)) {
|
||||
retval = attention_info->get_attn(hotplug_slot, value);
|
||||
@ -244,7 +243,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
*value = acpiphp_get_latch_status(slot->acpi_slot);
|
||||
|
||||
@ -264,7 +263,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
*value = acpiphp_get_adapter_status(slot->acpi_slot);
|
||||
|
||||
@ -279,7 +278,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
|
||||
{
|
||||
struct slot *slot = hotplug_slot->private;
|
||||
|
||||
dbg("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
pr_debug("%s - physical_slot = %s\n", __func__, slot_name(slot));
|
||||
|
||||
kfree(slot->hotplug_slot);
|
||||
kfree(slot);
|
||||
@ -322,11 +321,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot,
|
||||
if (retval == -EBUSY)
|
||||
goto error_hpslot;
|
||||
if (retval) {
|
||||
err("pci_hp_register failed with error %d\n", retval);
|
||||
pr_err("pci_hp_register failed with error %d\n", retval);
|
||||
goto error_hpslot;
|
||||
}
|
||||
|
||||
info("Slot [%s] registered\n", slot_name(slot));
|
||||
pr_info("Slot [%s] registered\n", slot_name(slot));
|
||||
|
||||
return 0;
|
||||
error_hpslot:
|
||||
@ -343,17 +342,17 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
|
||||
struct slot *slot = acpiphp_slot->slot;
|
||||
int retval = 0;
|
||||
|
||||
info("Slot [%s] unregistered\n", slot_name(slot));
|
||||
pr_info("Slot [%s] unregistered\n", slot_name(slot));
|
||||
|
||||
retval = pci_hp_deregister(slot->hotplug_slot);
|
||||
if (retval)
|
||||
err("pci_hp_deregister failed with error %d\n", retval);
|
||||
pr_err("pci_hp_deregister failed with error %d\n", retval);
|
||||
}
|
||||
|
||||
|
||||
void __init acpiphp_init(void)
|
||||
{
|
||||
info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
|
||||
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "%s\n",
|
||||
acpiphp_disabled ? ", disabled by user; please report a bug"
|
||||
: "");
|
||||
}
|
||||
|
@ -39,6 +39,8 @@
|
||||
* bus. It loses the refcount when the the driver unloads.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "acpiphp_glue: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@ -58,8 +60,6 @@ static LIST_HEAD(bridge_list);
|
||||
static DEFINE_MUTEX(bridge_mutex);
|
||||
static DEFINE_MUTEX(acpiphp_context_lock);
|
||||
|
||||
#define MY_NAME "acpiphp_glue"
|
||||
|
||||
static void handle_hotplug_event(acpi_handle handle, u32 type, void *data);
|
||||
static void acpiphp_sanitize_bus(struct pci_bus *bus);
|
||||
static void acpiphp_set_hpp_values(struct pci_bus *bus);
|
||||
@ -335,7 +335,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
|
||||
if (ACPI_FAILURE(status))
|
||||
sun = bridge->nr_slots;
|
||||
|
||||
dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
|
||||
pr_debug("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
|
||||
sun, pci_domain_nr(pbus), pbus->number, device);
|
||||
|
||||
retval = acpiphp_register_hotplug_slot(slot, sun);
|
||||
@ -343,10 +343,10 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
|
||||
slot->slot = NULL;
|
||||
bridge->nr_slots--;
|
||||
if (retval == -EBUSY)
|
||||
warn("Slot %llu already registered by another "
|
||||
pr_warn("Slot %llu already registered by another "
|
||||
"hotplug driver\n", sun);
|
||||
else
|
||||
warn("acpiphp_register_hotplug_slot failed "
|
||||
pr_warn("acpiphp_register_hotplug_slot failed "
|
||||
"(err code = 0x%x)\n", retval);
|
||||
}
|
||||
/* Even if the slot registration fails, we can still use it. */
|
||||
@ -369,7 +369,7 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data,
|
||||
if (register_hotplug_dock_device(handle,
|
||||
&acpiphp_dock_ops, context,
|
||||
acpiphp_dock_init, acpiphp_dock_release))
|
||||
dbg("failed to register dock device\n");
|
||||
pr_debug("failed to register dock device\n");
|
||||
}
|
||||
|
||||
/* install notify handler */
|
||||
@ -427,7 +427,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
|
||||
ACPI_SYSTEM_NOTIFY,
|
||||
handle_hotplug_event);
|
||||
if (ACPI_FAILURE(status))
|
||||
err("failed to remove notify handler\n");
|
||||
pr_err("failed to remove notify handler\n");
|
||||
}
|
||||
}
|
||||
if (slot->slot)
|
||||
@ -826,8 +826,9 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
switch (type) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
/* bus re-enumerate */
|
||||
dbg("%s: Bus check notify on %s\n", __func__, objname);
|
||||
dbg("%s: re-enumerating slots under %s\n", __func__, objname);
|
||||
pr_debug("%s: Bus check notify on %s\n", __func__, objname);
|
||||
pr_debug("%s: re-enumerating slots under %s\n",
|
||||
__func__, objname);
|
||||
if (bridge) {
|
||||
acpiphp_check_bridge(bridge);
|
||||
} else {
|
||||
@ -841,7 +842,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
/* device check */
|
||||
dbg("%s: Device check notify on %s\n", __func__, objname);
|
||||
pr_debug("%s: Device check notify on %s\n", __func__, objname);
|
||||
if (bridge) {
|
||||
acpiphp_check_bridge(bridge);
|
||||
} else {
|
||||
@ -862,7 +863,7 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
|
||||
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
/* request device eject */
|
||||
dbg("%s: Device eject notify on %s\n", __func__, objname);
|
||||
pr_debug("%s: Device eject notify on %s\n", __func__, objname);
|
||||
acpiphp_disable_and_eject_slot(func->slot);
|
||||
break;
|
||||
}
|
||||
|
@ -25,6 +25,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "acpiphp_ibm: " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@ -43,23 +45,11 @@
|
||||
#define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
|
||||
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver IBM extension"
|
||||
|
||||
static bool debug;
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
module_param(debug, bool, 0644);
|
||||
MODULE_PARM_DESC(debug, " Debugging mode enabled or not");
|
||||
#define MY_NAME "acpiphp_ibm"
|
||||
|
||||
#undef dbg
|
||||
#define dbg(format, arg...) \
|
||||
do { \
|
||||
if (debug) \
|
||||
printk(KERN_DEBUG "%s: " format, \
|
||||
MY_NAME , ## arg); \
|
||||
} while (0)
|
||||
|
||||
#define FOUND_APCI 0x61504349
|
||||
/* these are the names for the IBM ACPI pseudo-device */
|
||||
@ -189,7 +179,7 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
|
||||
|
||||
ibm_slot = ibm_slot_from_id(hpslot_to_sun(slot));
|
||||
|
||||
dbg("%s: set slot %d (%d) attention status to %d\n", __func__,
|
||||
pr_debug("%s: set slot %d (%d) attention status to %d\n", __func__,
|
||||
ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
|
||||
(status ? 1 : 0));
|
||||
|
||||
@ -202,10 +192,10 @@ static int ibm_set_attention_status(struct hotplug_slot *slot, u8 status)
|
||||
|
||||
stat = acpi_evaluate_integer(ibm_acpi_handle, "APLS", ¶ms, &rc);
|
||||
if (ACPI_FAILURE(stat)) {
|
||||
err("APLS evaluation failed: 0x%08x\n", stat);
|
||||
pr_err("APLS evaluation failed: 0x%08x\n", stat);
|
||||
return -ENODEV;
|
||||
} else if (!rc) {
|
||||
err("APLS method failed: 0x%08llx\n", rc);
|
||||
pr_err("APLS method failed: 0x%08llx\n", rc);
|
||||
return -ERANGE;
|
||||
}
|
||||
return 0;
|
||||
@ -234,7 +224,7 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status)
|
||||
else
|
||||
*status = 0;
|
||||
|
||||
dbg("%s: get slot %d (%d) attention status is %d\n", __func__,
|
||||
pr_debug("%s: get slot %d (%d) attention status is %d\n", __func__,
|
||||
ibm_slot->slot.slot_num, ibm_slot->slot.slot_id,
|
||||
*status);
|
||||
|
||||
@ -266,10 +256,10 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
|
||||
u8 subevent = event & 0xf0;
|
||||
struct notification *note = context;
|
||||
|
||||
dbg("%s: Received notification %02x\n", __func__, event);
|
||||
pr_debug("%s: Received notification %02x\n", __func__, event);
|
||||
|
||||
if (subevent == 0x80) {
|
||||
dbg("%s: generationg bus event\n", __func__);
|
||||
pr_debug("%s: generationg bus event\n", __func__);
|
||||
acpi_bus_generate_netlink_event(note->device->pnp.device_class,
|
||||
dev_name(¬e->device->dev),
|
||||
note->event, detail);
|
||||
@ -301,7 +291,7 @@ static int ibm_get_table_from_acpi(char **bufp)
|
||||
|
||||
status = acpi_evaluate_object(ibm_acpi_handle, "APCI", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
err("%s: APCI evaluation failed\n", __func__);
|
||||
pr_err("%s: APCI evaluation failed\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -309,13 +299,13 @@ static int ibm_get_table_from_acpi(char **bufp)
|
||||
if (!(package) ||
|
||||
(package->type != ACPI_TYPE_PACKAGE) ||
|
||||
!(package->package.elements)) {
|
||||
err("%s: Invalid APCI object\n", __func__);
|
||||
pr_err("%s: Invalid APCI object\n", __func__);
|
||||
goto read_table_done;
|
||||
}
|
||||
|
||||
for(size = 0, i = 0; i < package->package.count; i++) {
|
||||
if (package->package.elements[i].type != ACPI_TYPE_BUFFER) {
|
||||
err("%s: Invalid APCI element %d\n", __func__, i);
|
||||
pr_err("%s: Invalid APCI element %d\n", __func__, i);
|
||||
goto read_table_done;
|
||||
}
|
||||
size += package->package.elements[i].buffer.length;
|
||||
@ -325,7 +315,7 @@ static int ibm_get_table_from_acpi(char **bufp)
|
||||
goto read_table_done;
|
||||
|
||||
lbuf = kzalloc(size, GFP_KERNEL);
|
||||
dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
|
||||
pr_debug("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
|
||||
__func__, package->package.count, size, lbuf);
|
||||
|
||||
if (lbuf) {
|
||||
@ -371,7 +361,7 @@ static ssize_t ibm_read_apci_table(struct file *filp, struct kobject *kobj,
|
||||
int bytes_read = -EINVAL;
|
||||
char *table = NULL;
|
||||
|
||||
dbg("%s: pos = %d, size = %zd\n", __func__, (int)pos, size);
|
||||
pr_debug("%s: pos = %d, size = %zd\n", __func__, (int)pos, size);
|
||||
|
||||
if (pos == 0) {
|
||||
bytes_read = ibm_get_table_from_acpi(&table);
|
||||
@ -403,7 +393,7 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
|
||||
|
||||
status = acpi_get_object_info(handle, &info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
err("%s: Failed to get device information status=0x%x\n",
|
||||
pr_err("%s: Failed to get device information status=0x%x\n",
|
||||
__func__, status);
|
||||
return retval;
|
||||
}
|
||||
@ -411,7 +401,7 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
|
||||
if (info->current_status && (info->valid & ACPI_VALID_HID) &&
|
||||
(!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) ||
|
||||
!strcmp(info->hardware_id.string, IBM_HARDWARE_ID2))) {
|
||||
dbg("found hardware: %s, handle: %p\n",
|
||||
pr_debug("found hardware: %s, handle: %p\n",
|
||||
info->hardware_id.string, handle);
|
||||
*phandle = handle;
|
||||
/* returning non-zero causes the search to stop
|
||||
@ -432,18 +422,18 @@ static int __init ibm_acpiphp_init(void)
|
||||
struct acpi_device *device;
|
||||
struct kobject *sysdir = &pci_slots_kset->kobj;
|
||||
|
||||
dbg("%s\n", __func__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, ibm_find_acpi_device, NULL,
|
||||
&ibm_acpi_handle, NULL) != FOUND_APCI) {
|
||||
err("%s: acpi_walk_namespace failed\n", __func__);
|
||||
pr_err("%s: acpi_walk_namespace failed\n", __func__);
|
||||
retval = -ENODEV;
|
||||
goto init_return;
|
||||
}
|
||||
dbg("%s: found IBM aPCI device\n", __func__);
|
||||
pr_debug("%s: found IBM aPCI device\n", __func__);
|
||||
if (acpi_bus_get_device(ibm_acpi_handle, &device)) {
|
||||
err("%s: acpi_bus_get_device failed\n", __func__);
|
||||
pr_err("%s: acpi_bus_get_device failed\n", __func__);
|
||||
retval = -ENODEV;
|
||||
goto init_return;
|
||||
}
|
||||
@ -457,7 +447,7 @@ static int __init ibm_acpiphp_init(void)
|
||||
ACPI_DEVICE_NOTIFY, ibm_handle_events,
|
||||
&ibm_note);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
err("%s: Failed to register notification handler\n",
|
||||
pr_err("%s: Failed to register notification handler\n",
|
||||
__func__);
|
||||
retval = -EBUSY;
|
||||
goto init_cleanup;
|
||||
@ -479,17 +469,17 @@ static void __exit ibm_acpiphp_exit(void)
|
||||
acpi_status status;
|
||||
struct kobject *sysdir = &pci_slots_kset->kobj;
|
||||
|
||||
dbg("%s\n", __func__);
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (acpiphp_unregister_attention(&ibm_attention_info))
|
||||
err("%s: attention info deregistration failed", __func__);
|
||||
pr_err("%s: attention info deregistration failed", __func__);
|
||||
|
||||
status = acpi_remove_notify_handler(
|
||||
ibm_acpi_handle,
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
ibm_handle_events);
|
||||
if (ACPI_FAILURE(status))
|
||||
err("%s: Notification handler removal failed\n", __func__);
|
||||
pr_err("%s: Notification handler removal failed\n", __func__);
|
||||
/* remove the /sys entries */
|
||||
sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr);
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ static inline const char *slot_name(struct slot *slot)
|
||||
#include <linux/pci-acpi.h>
|
||||
static inline int get_hp_hw_control_from_firmware(struct pci_dev *dev)
|
||||
{
|
||||
u32 flags = OSC_SHPC_NATIVE_HP_CONTROL;
|
||||
u32 flags = OSC_PCI_SHPC_NATIVE_HP_CONTROL;
|
||||
return acpi_get_hp_hw_control_from_firmware(dev, flags);
|
||||
}
|
||||
#else
|
||||
|
@ -185,7 +185,7 @@ static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
|
||||
* reliably as devices without an INTx disable bit will then generate a
|
||||
* level IRQ which will never be cleared.
|
||||
*/
|
||||
static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
{
|
||||
u32 mask_bits = desc->masked;
|
||||
|
||||
@ -199,9 +199,14 @@ static u32 __msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
return mask_bits;
|
||||
}
|
||||
|
||||
__weak u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
{
|
||||
return default_msi_mask_irq(desc, mask, flag);
|
||||
}
|
||||
|
||||
static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
{
|
||||
desc->masked = __msi_mask_irq(desc, mask, flag);
|
||||
desc->masked = arch_msi_mask_irq(desc, mask, flag);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -211,7 +216,7 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
|
||||
* file. This saves a few milliseconds when initialising devices with lots
|
||||
* of MSI-X interrupts.
|
||||
*/
|
||||
static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
{
|
||||
u32 mask_bits = desc->masked;
|
||||
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
|
||||
@ -224,9 +229,14 @@ static u32 __msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
return mask_bits;
|
||||
}
|
||||
|
||||
__weak u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
{
|
||||
return default_msix_mask_irq(desc, flag);
|
||||
}
|
||||
|
||||
static void msix_mask_irq(struct msi_desc *desc, u32 flag)
|
||||
{
|
||||
desc->masked = __msix_mask_irq(desc, flag);
|
||||
desc->masked = arch_msix_mask_irq(desc, flag);
|
||||
}
|
||||
|
||||
static void msi_set_mask_bit(struct irq_data *data, u32 flag)
|
||||
@ -831,7 +841,7 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
|
||||
int status, maxvec;
|
||||
u16 msgctl;
|
||||
|
||||
if (!dev->msi_cap)
|
||||
if (!dev->msi_cap || dev->current_state != PCI_D0)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
|
||||
@ -862,7 +872,7 @@ int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec)
|
||||
int ret, nvec;
|
||||
u16 msgctl;
|
||||
|
||||
if (!dev->msi_cap)
|
||||
if (!dev->msi_cap || dev->current_state != PCI_D0)
|
||||
return -EINVAL;
|
||||
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &msgctl);
|
||||
@ -902,7 +912,7 @@ void pci_msi_shutdown(struct pci_dev *dev)
|
||||
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &ctrl);
|
||||
mask = msi_capable_mask(ctrl);
|
||||
/* Keep cached state to be restored */
|
||||
__msi_mask_irq(desc, mask, ~mask);
|
||||
arch_msi_mask_irq(desc, mask, ~mask);
|
||||
|
||||
/* Restore dev->irq to its default pin-assertion irq */
|
||||
dev->irq = desc->msi_attrib.default_irq;
|
||||
@ -955,7 +965,7 @@ int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec)
|
||||
int status, nr_entries;
|
||||
int i, j;
|
||||
|
||||
if (!entries || !dev->msix_cap)
|
||||
if (!entries || !dev->msix_cap || dev->current_state != PCI_D0)
|
||||
return -EINVAL;
|
||||
|
||||
status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
|
||||
@ -998,7 +1008,7 @@ void pci_msix_shutdown(struct pci_dev *dev)
|
||||
/* Return the device with MSI-X masked as initial states */
|
||||
list_for_each_entry(entry, &dev->msi_list, list) {
|
||||
/* Keep cached states to be restored */
|
||||
__msix_mask_irq(entry, 1);
|
||||
arch_msix_mask_irq(entry, 1);
|
||||
}
|
||||
|
||||
msix_set_enable(dev, 0);
|
||||
|
@ -267,11 +267,19 @@ static long local_pci_probe(void *_ddi)
|
||||
pm_runtime_get_sync(dev);
|
||||
pci_dev->driver = pci_drv;
|
||||
rc = pci_drv->probe(pci_dev, ddi->id);
|
||||
if (rc) {
|
||||
if (!rc)
|
||||
return rc;
|
||||
if (rc < 0) {
|
||||
pci_dev->driver = NULL;
|
||||
pm_runtime_put_sync(dev);
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
/*
|
||||
* Probe function should return < 0 for failure, 0 for success
|
||||
* Treat values > 0 as success, but warn.
|
||||
*/
|
||||
dev_warn(dev, "Driver probe function unexpectedly returned %d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
|
||||
@ -602,18 +610,10 @@ static int pci_pm_prepare(struct device *dev)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void pci_pm_complete(struct device *dev)
|
||||
{
|
||||
struct device_driver *drv = dev->driver;
|
||||
|
||||
if (drv && drv->pm && drv->pm->complete)
|
||||
drv->pm->complete(dev);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
|
||||
#define pci_pm_prepare NULL
|
||||
#define pci_pm_complete NULL
|
||||
|
||||
#endif /* !CONFIG_PM_SLEEP */
|
||||
|
||||
@ -1124,9 +1124,8 @@ static int pci_pm_runtime_idle(struct device *dev)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
const struct dev_pm_ops pci_dev_pm_ops = {
|
||||
static const struct dev_pm_ops pci_dev_pm_ops = {
|
||||
.prepare = pci_pm_prepare,
|
||||
.complete = pci_pm_complete,
|
||||
.suspend = pci_pm_suspend,
|
||||
.resume = pci_pm_resume,
|
||||
.freeze = pci_pm_freeze,
|
||||
@ -1319,7 +1318,7 @@ struct bus_type pci_bus_type = {
|
||||
.probe = pci_device_probe,
|
||||
.remove = pci_device_remove,
|
||||
.shutdown = pci_device_shutdown,
|
||||
.dev_attrs = pci_dev_attrs,
|
||||
.dev_groups = pci_dev_groups,
|
||||
.bus_groups = pci_bus_groups,
|
||||
.drv_groups = pci_drv_groups,
|
||||
.pm = PCI_PM_OPS_PTR,
|
||||
|
@ -42,7 +42,8 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||
\
|
||||
pdev = to_pci_dev (dev); \
|
||||
return sprintf (buf, format_string, pdev->field); \
|
||||
}
|
||||
} \
|
||||
static DEVICE_ATTR_RO(field)
|
||||
|
||||
pci_config_attr(vendor, "0x%04x\n");
|
||||
pci_config_attr(device, "0x%04x\n");
|
||||
@ -73,43 +74,44 @@ static ssize_t broken_parity_status_store(struct device *dev,
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(broken_parity_status);
|
||||
|
||||
static ssize_t pci_dev_show_local_cpu(struct device *dev,
|
||||
int type,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
const struct cpumask *mask;
|
||||
int len;
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
mask = (dev_to_node(dev) == -1) ? cpu_online_mask :
|
||||
cpumask_of_node(dev_to_node(dev));
|
||||
#else
|
||||
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
|
||||
#endif
|
||||
len = type ?
|
||||
cpumask_scnprintf(buf, PAGE_SIZE-2, mask) :
|
||||
cpulist_scnprintf(buf, PAGE_SIZE-2, mask);
|
||||
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t local_cpus_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct cpumask *mask;
|
||||
int len;
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
mask = (dev_to_node(dev) == -1) ? cpu_online_mask :
|
||||
cpumask_of_node(dev_to_node(dev));
|
||||
#else
|
||||
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
|
||||
#endif
|
||||
len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
return pci_dev_show_local_cpu(dev, 1, attr, buf);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(local_cpus);
|
||||
|
||||
static ssize_t local_cpulist_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
const struct cpumask *mask;
|
||||
int len;
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
mask = (dev_to_node(dev) == -1) ? cpu_online_mask :
|
||||
cpumask_of_node(dev_to_node(dev));
|
||||
#else
|
||||
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
|
||||
#endif
|
||||
len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask);
|
||||
buf[len++] = '\n';
|
||||
buf[len] = '\0';
|
||||
return len;
|
||||
return pci_dev_show_local_cpu(dev, 0, attr, buf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(local_cpulist);
|
||||
|
||||
/*
|
||||
* PCI Bus Class Devices
|
||||
@ -170,6 +172,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
|
||||
}
|
||||
return (str - buf);
|
||||
}
|
||||
static DEVICE_ATTR_RO(resource);
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -181,10 +184,11 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
(u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
|
||||
(u8)(pci_dev->class));
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t is_enabled_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
static ssize_t enabled_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
unsigned long val;
|
||||
@ -208,14 +212,15 @@ static ssize_t is_enabled_store(struct device *dev,
|
||||
return result < 0 ? result : count;
|
||||
}
|
||||
|
||||
static ssize_t is_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct pci_dev *pdev;
|
||||
|
||||
pdev = to_pci_dev (dev);
|
||||
return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt));
|
||||
}
|
||||
static DEVICE_ATTR_RW(enabled);
|
||||
|
||||
#ifdef CONFIG_NUMA
|
||||
static ssize_t
|
||||
@ -223,6 +228,7 @@ numa_node_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf (buf, "%d\n", dev->numa_node);
|
||||
}
|
||||
static DEVICE_ATTR_RO(numa_node);
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
@ -232,6 +238,7 @@ dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
|
||||
return sprintf (buf, "%d\n", fls64(pdev->dma_mask));
|
||||
}
|
||||
static DEVICE_ATTR_RO(dma_mask_bits);
|
||||
|
||||
static ssize_t
|
||||
consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr,
|
||||
@ -239,6 +246,7 @@ consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask));
|
||||
}
|
||||
static DEVICE_ATTR_RO(consistent_dma_mask_bits);
|
||||
|
||||
static ssize_t
|
||||
msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@ -283,6 +291,7 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(msi_bus);
|
||||
|
||||
static DEFINE_MUTEX(pci_remove_rescan_mutex);
|
||||
static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
|
||||
@ -304,7 +313,7 @@ static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf,
|
||||
}
|
||||
static BUS_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store);
|
||||
|
||||
struct attribute *pci_bus_attrs[] = {
|
||||
static struct attribute *pci_bus_attrs[] = {
|
||||
&bus_attr_rescan.attr,
|
||||
NULL,
|
||||
};
|
||||
@ -335,8 +344,9 @@ dev_rescan_store(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
return count;
|
||||
}
|
||||
struct device_attribute dev_rescan_attr = __ATTR(rescan, (S_IWUSR|S_IWGRP),
|
||||
NULL, dev_rescan_store);
|
||||
static struct device_attribute dev_rescan_attr = __ATTR(rescan,
|
||||
(S_IWUSR|S_IWGRP),
|
||||
NULL, dev_rescan_store);
|
||||
|
||||
static void remove_callback(struct device *dev)
|
||||
{
|
||||
@ -366,8 +376,9 @@ remove_store(struct device *dev, struct device_attribute *dummy,
|
||||
count = ret;
|
||||
return count;
|
||||
}
|
||||
struct device_attribute dev_remove_attr = __ATTR(remove, (S_IWUSR|S_IWGRP),
|
||||
NULL, remove_store);
|
||||
static struct device_attribute dev_remove_attr = __ATTR(remove,
|
||||
(S_IWUSR|S_IWGRP),
|
||||
NULL, remove_store);
|
||||
|
||||
static ssize_t
|
||||
dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
|
||||
@ -414,6 +425,7 @@ static ssize_t d3cold_allowed_show(struct device *dev,
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
return sprintf (buf, "%u\n", pdev->d3cold_allowed);
|
||||
}
|
||||
static DEVICE_ATTR_RW(d3cold_allowed);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
@ -499,30 +511,38 @@ static struct device_attribute sriov_numvfs_attr =
|
||||
sriov_numvfs_show, sriov_numvfs_store);
|
||||
#endif /* CONFIG_PCI_IOV */
|
||||
|
||||
struct device_attribute pci_dev_attrs[] = {
|
||||
__ATTR_RO(resource),
|
||||
__ATTR_RO(vendor),
|
||||
__ATTR_RO(device),
|
||||
__ATTR_RO(subsystem_vendor),
|
||||
__ATTR_RO(subsystem_device),
|
||||
__ATTR_RO(class),
|
||||
__ATTR_RO(irq),
|
||||
__ATTR_RO(local_cpus),
|
||||
__ATTR_RO(local_cpulist),
|
||||
__ATTR_RO(modalias),
|
||||
static struct attribute *pci_dev_attrs[] = {
|
||||
&dev_attr_resource.attr,
|
||||
&dev_attr_vendor.attr,
|
||||
&dev_attr_device.attr,
|
||||
&dev_attr_subsystem_vendor.attr,
|
||||
&dev_attr_subsystem_device.attr,
|
||||
&dev_attr_class.attr,
|
||||
&dev_attr_irq.attr,
|
||||
&dev_attr_local_cpus.attr,
|
||||
&dev_attr_local_cpulist.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
#ifdef CONFIG_NUMA
|
||||
__ATTR_RO(numa_node),
|
||||
&dev_attr_numa_node.attr,
|
||||
#endif
|
||||
__ATTR_RO(dma_mask_bits),
|
||||
__ATTR_RO(consistent_dma_mask_bits),
|
||||
__ATTR(enable, 0600, is_enabled_show, is_enabled_store),
|
||||
__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
|
||||
broken_parity_status_show,broken_parity_status_store),
|
||||
__ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
|
||||
&dev_attr_dma_mask_bits.attr,
|
||||
&dev_attr_consistent_dma_mask_bits.attr,
|
||||
&dev_attr_enabled.attr,
|
||||
&dev_attr_broken_parity_status.attr,
|
||||
&dev_attr_msi_bus.attr,
|
||||
#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
|
||||
__ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store),
|
||||
&dev_attr_d3cold_allowed.attr,
|
||||
#endif
|
||||
__ATTR_NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group pci_dev_group = {
|
||||
.attrs = pci_dev_attrs,
|
||||
};
|
||||
|
||||
const struct attribute_group *pci_dev_groups[] = {
|
||||
&pci_dev_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *pcibus_attrs[] = {
|
||||
@ -554,7 +574,7 @@ boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
!!(pdev->resource[PCI_ROM_RESOURCE].flags &
|
||||
IORESOURCE_ROM_SHADOW));
|
||||
}
|
||||
struct device_attribute vga_attr = __ATTR_RO(boot_vga);
|
||||
static struct device_attribute vga_attr = __ATTR_RO(boot_vga);
|
||||
|
||||
static ssize_t
|
||||
pci_read_config(struct file *filp, struct kobject *kobj,
|
||||
|
@ -1148,18 +1148,16 @@ int pci_reenable_device(struct pci_dev *dev)
|
||||
|
||||
static void pci_enable_bridge(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *bridge;
|
||||
int retval;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
pci_enable_bridge(dev->bus->self);
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge)
|
||||
pci_enable_bridge(bridge);
|
||||
|
||||
if (pci_is_enabled(dev)) {
|
||||
if (!dev->is_busmaster) {
|
||||
dev_warn(&dev->dev, "driver skip pci_set_master, fix it!\n");
|
||||
if (!dev->is_busmaster)
|
||||
pci_set_master(dev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1172,6 +1170,7 @@ static void pci_enable_bridge(struct pci_dev *dev)
|
||||
|
||||
static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
|
||||
{
|
||||
struct pci_dev *bridge;
|
||||
int err;
|
||||
int i, bars = 0;
|
||||
|
||||
@ -1190,7 +1189,9 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
|
||||
if (atomic_inc_return(&dev->enable_cnt) > 1)
|
||||
return 0; /* already enabled */
|
||||
|
||||
pci_enable_bridge(dev->bus->self);
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge)
|
||||
pci_enable_bridge(bridge);
|
||||
|
||||
/* only skip sriov related */
|
||||
for (i = 0; i <= PCI_ROM_RESOURCE; i++)
|
||||
@ -1644,8 +1645,10 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
|
||||
if (enable) {
|
||||
pme_dev = kmalloc(sizeof(struct pci_pme_device),
|
||||
GFP_KERNEL);
|
||||
if (!pme_dev)
|
||||
goto out;
|
||||
if (!pme_dev) {
|
||||
dev_warn(&dev->dev, "can't enable PME#\n");
|
||||
return;
|
||||
}
|
||||
pme_dev->dev = dev;
|
||||
mutex_lock(&pci_pme_list_mutex);
|
||||
list_add(&pme_dev->list, &pci_pme_list);
|
||||
@ -1666,7 +1669,6 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
dev_dbg(&dev->dev, "PME# %s\n", enable ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
@ -2860,7 +2862,7 @@ void __weak pcibios_set_master(struct pci_dev *dev)
|
||||
lat = pcibios_max_latency;
|
||||
else
|
||||
return;
|
||||
dev_printk(KERN_DEBUG, &dev->dev, "setting latency timer to %d\n", lat);
|
||||
|
||||
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
|
||||
}
|
||||
|
||||
@ -3978,6 +3980,7 @@ int pcie_get_mps(struct pci_dev *dev)
|
||||
|
||||
return 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_get_mps);
|
||||
|
||||
/**
|
||||
* pcie_set_mps - set PCI Express maximum payload size
|
||||
@ -4002,6 +4005,7 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
|
||||
return pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_PAYLOAD, v);
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_set_mps);
|
||||
|
||||
/**
|
||||
* pcie_get_minimum_link - determine minimum link settings of a PCI device
|
||||
|
@ -153,7 +153,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
|
||||
return (dev->no_d1d2 || parent_dstates);
|
||||
|
||||
}
|
||||
extern struct device_attribute pci_dev_attrs[];
|
||||
extern const struct attribute_group *pci_dev_groups[];
|
||||
extern const struct attribute_group *pcibus_groups[];
|
||||
extern struct device_type pci_dev_type;
|
||||
extern const struct attribute_group *pci_bus_groups[];
|
||||
|
@ -260,13 +260,14 @@ static int get_port_device_capability(struct pci_dev *dev)
|
||||
if (pcie_ports_disabled)
|
||||
return 0;
|
||||
|
||||
err = pcie_port_platform_notify(dev, &cap_mask);
|
||||
if (!pcie_ports_auto) {
|
||||
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
|
||||
| PCIE_PORT_SERVICE_VC;
|
||||
if (pci_aer_available())
|
||||
cap_mask |= PCIE_PORT_SERVICE_AER;
|
||||
} else if (err) {
|
||||
cap_mask = PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP
|
||||
| PCIE_PORT_SERVICE_VC;
|
||||
if (pci_aer_available())
|
||||
cap_mask |= PCIE_PORT_SERVICE_AER;
|
||||
|
||||
if (pcie_ports_auto) {
|
||||
err = pcie_port_platform_notify(dev, &cap_mask);
|
||||
if (err)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -641,8 +641,7 @@ static void pci_set_bus_speed(struct pci_bus *bus)
|
||||
return;
|
||||
}
|
||||
|
||||
pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
|
||||
if (pos) {
|
||||
if (pci_is_pcie(bridge)) {
|
||||
u32 linkcap;
|
||||
u16 linksta;
|
||||
|
||||
@ -984,7 +983,6 @@ void set_pcie_port_type(struct pci_dev *pdev)
|
||||
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
|
||||
if (!pos)
|
||||
return;
|
||||
pdev->is_pcie = 1;
|
||||
pdev->pcie_cap = pos;
|
||||
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16);
|
||||
pdev->pcie_flags_reg = reg16;
|
||||
|
@ -2954,6 +2954,29 @@ static void disable_igfx_irq(struct pci_dev *dev)
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
|
||||
|
||||
/*
|
||||
* PCI devices which are on Intel chips can skip the 10ms delay
|
||||
* before entering D3 mode.
|
||||
*/
|
||||
static void quirk_remove_d3_delay(struct pci_dev *dev)
|
||||
{
|
||||
dev->d3_delay = 0;
|
||||
}
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c00, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0412, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0c0c, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c31, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3a, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c3d, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c2d, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c20, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c18, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c1c, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c26, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c4e, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c02, quirk_remove_d3_delay);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x8c22, quirk_remove_d3_delay);
|
||||
|
||||
/*
|
||||
* Some devices may pass our check in pci_intx_mask_supported if
|
||||
* PCI_COMMAND_INTX_DISABLE works though they actually do not properly
|
||||
|
@ -982,7 +982,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
|
||||
}
|
||||
|
||||
min_align = calculate_mem_align(aligns, max_order);
|
||||
min_align = max(min_align, window_alignment(bus, b_res->flags & mask));
|
||||
min_align = max(min_align, window_alignment(bus, b_res->flags));
|
||||
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
|
||||
if (children_add_size > add_size)
|
||||
add_size = children_add_size;
|
||||
@ -1136,7 +1136,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,
|
||||
}
|
||||
|
||||
/* The root bus? */
|
||||
if (!bus->self)
|
||||
if (pci_is_root_bus(bus))
|
||||
return;
|
||||
|
||||
switch (bus->self->class >> 8) {
|
||||
|
@ -766,49 +766,20 @@ bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
|
||||
bfad->pcidev = pdev;
|
||||
|
||||
/* Adjust PCIe Maximum Read Request Size */
|
||||
if (pcie_max_read_reqsz > 0) {
|
||||
int pcie_cap_reg;
|
||||
u16 pcie_dev_ctl;
|
||||
u16 mask = 0xffff;
|
||||
|
||||
switch (pcie_max_read_reqsz) {
|
||||
case 128:
|
||||
mask = 0x0;
|
||||
break;
|
||||
case 256:
|
||||
mask = 0x1000;
|
||||
break;
|
||||
case 512:
|
||||
mask = 0x2000;
|
||||
break;
|
||||
case 1024:
|
||||
mask = 0x3000;
|
||||
break;
|
||||
case 2048:
|
||||
mask = 0x4000;
|
||||
break;
|
||||
case 4096:
|
||||
mask = 0x5000;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pcie_cap_reg = pci_find_capability(pdev, PCI_CAP_ID_EXP);
|
||||
if (mask != 0xffff && pcie_cap_reg) {
|
||||
pcie_cap_reg += 0x08;
|
||||
pci_read_config_word(pdev, pcie_cap_reg, &pcie_dev_ctl);
|
||||
if ((pcie_dev_ctl & 0x7000) != mask) {
|
||||
printk(KERN_WARNING "BFA[%s]: "
|
||||
if (pci_is_pcie(pdev) && pcie_max_read_reqsz) {
|
||||
if (pcie_max_read_reqsz >= 128 &&
|
||||
pcie_max_read_reqsz <= 4096 &&
|
||||
is_power_of_2(pcie_max_read_reqsz)) {
|
||||
int max_rq = pcie_get_readrq(pdev);
|
||||
printk(KERN_WARNING "BFA[%s]: "
|
||||
"pcie_max_read_request_size is %d, "
|
||||
"reset to %d\n", bfad->pci_name,
|
||||
(1 << ((pcie_dev_ctl & 0x7000) >> 12)) << 7,
|
||||
"reset to %d\n", bfad->pci_name, max_rq,
|
||||
pcie_max_read_reqsz);
|
||||
|
||||
pcie_dev_ctl &= ~0x7000;
|
||||
pci_write_config_word(pdev, pcie_cap_reg,
|
||||
pcie_dev_ctl | mask);
|
||||
}
|
||||
pcie_set_readrq(pdev, pcie_max_read_reqsz);
|
||||
} else {
|
||||
printk(KERN_WARNING "BFA[%s]: invalid "
|
||||
"pcie_max_read_request_size %d ignored\n",
|
||||
bfad->pci_name, pcie_max_read_reqsz);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,22 +852,6 @@ csio_hw_get_flash_params(struct csio_hw *hw)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
csio_set_pcie_completion_timeout(struct csio_hw *hw, u8 range)
|
||||
{
|
||||
uint16_t val;
|
||||
int pcie_cap;
|
||||
|
||||
if (!csio_pci_capability(hw->pdev, PCI_CAP_ID_EXP, &pcie_cap)) {
|
||||
pci_read_config_word(hw->pdev,
|
||||
pcie_cap + PCI_EXP_DEVCTL2, &val);
|
||||
val &= 0xfff0;
|
||||
val |= range ;
|
||||
pci_write_config_word(hw->pdev,
|
||||
pcie_cap + PCI_EXP_DEVCTL2, val);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* HW State machine assists */
|
||||
/*****************************************************************************/
|
||||
@ -2069,8 +2053,10 @@ csio_hw_configure(struct csio_hw *hw)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Set pci completion timeout value to 4 seconds. */
|
||||
csio_set_pcie_completion_timeout(hw, 0xd);
|
||||
/* Set PCIe completion timeout to 4 seconds */
|
||||
if (pci_is_pcie(hw->pdev))
|
||||
pcie_capability_clear_and_set_word(hw->pdev, PCI_EXP_DEVCTL2,
|
||||
PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0xd);
|
||||
|
||||
hw->chip_ops->chip_set_mem_win(hw, MEMWIN_CSIOSTOR);
|
||||
|
||||
|
@ -507,7 +507,7 @@ qlafx00_pci_config(scsi_qla_host_t *vha)
|
||||
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
|
||||
|
||||
/* PCIe -- adjust Maximum Read Request Size (2048). */
|
||||
if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
|
||||
if (pci_is_pcie(ha->pdev))
|
||||
pcie_set_readrq(ha->pdev, 2048);
|
||||
|
||||
ha->chip_revision = ha->pdev->revision;
|
||||
@ -660,10 +660,8 @@ char *
|
||||
qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int pcie_reg;
|
||||
|
||||
pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
|
||||
if (pcie_reg) {
|
||||
if (pci_is_pcie(ha->pdev)) {
|
||||
strcpy(str, "PCIe iSA");
|
||||
return str;
|
||||
}
|
||||
|
@ -494,18 +494,14 @@ qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str)
|
||||
static char *pci_bus_modes[] = { "33", "66", "100", "133", };
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t pci_bus;
|
||||
int pcie_reg;
|
||||
|
||||
pcie_reg = pci_pcie_cap(ha->pdev);
|
||||
if (pcie_reg) {
|
||||
if (pci_is_pcie(ha->pdev)) {
|
||||
char lwstr[6];
|
||||
uint16_t pcie_lstat, lspeed, lwidth;
|
||||
uint32_t lstat, lspeed, lwidth;
|
||||
|
||||
pcie_reg += PCI_EXP_LNKCAP;
|
||||
pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat);
|
||||
lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3);
|
||||
lwidth = (pcie_lstat &
|
||||
(BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4;
|
||||
pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat);
|
||||
lspeed = lstat & PCI_EXP_LNKCAP_SLS;
|
||||
lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4;
|
||||
|
||||
strcpy(str, "PCIe (");
|
||||
switch (lspeed) {
|
||||
|
@ -3601,17 +3601,10 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Let's set up the PORT LOGIC Register. First we need to know what
|
||||
* the max_payload_size is
|
||||
*/
|
||||
if (pcie_capability_read_word(pdev, PCI_EXP_DEVCAP, &max_payload)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Could not read PCI config space for Max Payload Size\n");
|
||||
goto err_out;
|
||||
}
|
||||
/* Let's set up the PORT LOGIC Register. */
|
||||
|
||||
/* Program the Ack/Nak latency and replay timers */
|
||||
max_payload &= 0x07;
|
||||
max_payload = pdev->pcie_mpss;
|
||||
|
||||
if (max_payload < 2) {
|
||||
static const u16 acknak[2] = { 0x76, 0xD0 };
|
||||
@ -3641,8 +3634,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
|
||||
}
|
||||
|
||||
/* Change the max read size to 2k */
|
||||
if (pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
|
||||
PCI_EXP_DEVCTL_READRQ, 0x4 << 12)) {
|
||||
if (pcie_set_readrq(pdev, 2048)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Couldn't change PCI config space for Max read size\n");
|
||||
goto err_out;
|
||||
|
@ -294,59 +294,52 @@ void __init acpi_nvs_nosave_s3(void);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
struct acpi_osc_context {
|
||||
char *uuid_str; /* uuid string */
|
||||
char *uuid_str; /* UUID string */
|
||||
int rev;
|
||||
struct acpi_buffer cap; /* arg2/arg3 */
|
||||
struct acpi_buffer ret; /* free by caller if success */
|
||||
struct acpi_buffer cap; /* list of DWORD capabilities */
|
||||
struct acpi_buffer ret; /* free by caller if success */
|
||||
};
|
||||
|
||||
#define OSC_QUERY_TYPE 0
|
||||
#define OSC_SUPPORT_TYPE 1
|
||||
#define OSC_CONTROL_TYPE 2
|
||||
|
||||
/* _OSC DW0 Definition */
|
||||
#define OSC_QUERY_ENABLE 1
|
||||
#define OSC_REQUEST_ERROR 2
|
||||
#define OSC_INVALID_UUID_ERROR 4
|
||||
#define OSC_INVALID_REVISION_ERROR 8
|
||||
#define OSC_CAPABILITIES_MASK_ERROR 16
|
||||
|
||||
acpi_status acpi_str_to_uuid(char *str, u8 *uuid);
|
||||
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
|
||||
|
||||
/* platform-wide _OSC bits */
|
||||
#define OSC_SB_PAD_SUPPORT 1
|
||||
#define OSC_SB_PPC_OST_SUPPORT 2
|
||||
#define OSC_SB_PR3_SUPPORT 4
|
||||
#define OSC_SB_HOTPLUG_OST_SUPPORT 8
|
||||
#define OSC_SB_APEI_SUPPORT 16
|
||||
/* Indexes into _OSC Capabilities Buffer (DWORDs 2 & 3 are device-specific) */
|
||||
#define OSC_QUERY_DWORD 0 /* DWORD 1 */
|
||||
#define OSC_SUPPORT_DWORD 1 /* DWORD 2 */
|
||||
#define OSC_CONTROL_DWORD 2 /* DWORD 3 */
|
||||
|
||||
/* _OSC Capabilities DWORD 1: Query/Control and Error Returns (generic) */
|
||||
#define OSC_QUERY_ENABLE 0x00000001 /* input */
|
||||
#define OSC_REQUEST_ERROR 0x00000002 /* return */
|
||||
#define OSC_INVALID_UUID_ERROR 0x00000004 /* return */
|
||||
#define OSC_INVALID_REVISION_ERROR 0x00000008 /* return */
|
||||
#define OSC_CAPABILITIES_MASK_ERROR 0x00000010 /* return */
|
||||
|
||||
/* Platform-Wide Capabilities _OSC: Capabilities DWORD 2: Support Field */
|
||||
#define OSC_SB_PAD_SUPPORT 0x00000001
|
||||
#define OSC_SB_PPC_OST_SUPPORT 0x00000002
|
||||
#define OSC_SB_PR3_SUPPORT 0x00000004
|
||||
#define OSC_SB_HOTPLUG_OST_SUPPORT 0x00000008
|
||||
#define OSC_SB_APEI_SUPPORT 0x00000010
|
||||
#define OSC_SB_CPC_SUPPORT 0x00000020
|
||||
|
||||
extern bool osc_sb_apei_support_acked;
|
||||
|
||||
/* PCI defined _OSC bits */
|
||||
/* _OSC DW1 Definition (OS Support Fields) */
|
||||
#define OSC_EXT_PCI_CONFIG_SUPPORT 1
|
||||
#define OSC_ACTIVE_STATE_PWR_SUPPORT 2
|
||||
#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4
|
||||
#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8
|
||||
#define OSC_MSI_SUPPORT 16
|
||||
#define OSC_PCI_SUPPORT_MASKS 0x1f
|
||||
/* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */
|
||||
#define OSC_PCI_EXT_CONFIG_SUPPORT 0x00000001
|
||||
#define OSC_PCI_ASPM_SUPPORT 0x00000002
|
||||
#define OSC_PCI_CLOCK_PM_SUPPORT 0x00000004
|
||||
#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 0x00000008
|
||||
#define OSC_PCI_MSI_SUPPORT 0x00000010
|
||||
#define OSC_PCI_SUPPORT_MASKS 0x0000001f
|
||||
|
||||
/* _OSC DW1 Definition (OS Control Fields) */
|
||||
#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1
|
||||
#define OSC_SHPC_NATIVE_HP_CONTROL 2
|
||||
#define OSC_PCI_EXPRESS_PME_CONTROL 4
|
||||
#define OSC_PCI_EXPRESS_AER_CONTROL 8
|
||||
#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16
|
||||
|
||||
#define OSC_PCI_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
OSC_SHPC_NATIVE_HP_CONTROL | \
|
||||
OSC_PCI_EXPRESS_PME_CONTROL | \
|
||||
OSC_PCI_EXPRESS_AER_CONTROL | \
|
||||
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
|
||||
|
||||
#define OSC_PCI_NATIVE_HOTPLUG (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
OSC_SHPC_NATIVE_HP_CONTROL)
|
||||
/* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */
|
||||
#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001
|
||||
#define OSC_PCI_SHPC_NATIVE_HP_CONTROL 0x00000002
|
||||
#define OSC_PCI_EXPRESS_PME_CONTROL 0x00000004
|
||||
#define OSC_PCI_EXPRESS_AER_CONTROL 0x00000008
|
||||
#define OSC_PCI_EXPRESS_CAPABILITY_CONTROL 0x00000010
|
||||
#define OSC_PCI_CONTROL_MASKS 0x0000001f
|
||||
|
||||
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
|
||||
u32 *mask, u32 req);
|
||||
|
@ -241,6 +241,12 @@
|
||||
|
||||
#define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
|
||||
|
||||
#define IMX6Q_GPR8_TX_SWING_LOW (0x7f << 25)
|
||||
#define IMX6Q_GPR8_TX_SWING_FULL (0x7f << 18)
|
||||
#define IMX6Q_GPR8_TX_DEEMPH_GEN2_6DB (0x3f << 12)
|
||||
#define IMX6Q_GPR8_TX_DEEMPH_GEN2_3P5DB (0x3f << 6)
|
||||
#define IMX6Q_GPR8_TX_DEEMPH_GEN1 (0x3f << 0)
|
||||
|
||||
#define IMX6Q_GPR9_TZASC2_BYP BIT(1)
|
||||
#define IMX6Q_GPR9_TZASC1_BYP BIT(0)
|
||||
|
||||
@ -273,7 +279,9 @@
|
||||
#define IMX6Q_GPR12_ARMP_AHB_CLK_EN BIT(26)
|
||||
#define IMX6Q_GPR12_ARMP_ATB_CLK_EN BIT(25)
|
||||
#define IMX6Q_GPR12_ARMP_APB_CLK_EN BIT(24)
|
||||
#define IMX6Q_GPR12_DEVICE_TYPE (0xf << 12)
|
||||
#define IMX6Q_GPR12_PCIE_CTL_2 BIT(10)
|
||||
#define IMX6Q_GPR12_LOS_LEVEL (0x1f << 4)
|
||||
|
||||
#define IMX6Q_GPR13_SDMA_STOP_REQ BIT(30)
|
||||
#define IMX6Q_GPR13_CAN2_STOP_REQ BIT(29)
|
||||
|
@ -64,6 +64,8 @@ void arch_restore_msi_irqs(struct pci_dev *dev, int irq);
|
||||
|
||||
void default_teardown_msi_irqs(struct pci_dev *dev);
|
||||
void default_restore_msi_irqs(struct pci_dev *dev, int irq);
|
||||
u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
|
||||
u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag);
|
||||
|
||||
struct msi_chip {
|
||||
struct module *owner;
|
||||
|
@ -330,8 +330,6 @@ struct pci_dev {
|
||||
unsigned int msix_enabled:1;
|
||||
unsigned int ari_enabled:1; /* ARI forwarding */
|
||||
unsigned int is_managed:1;
|
||||
unsigned int is_pcie:1; /* Obsolete. Will be removed.
|
||||
Use pci_is_pcie() instead */
|
||||
unsigned int needs_freset:1; /* Dev requires fundamental reset */
|
||||
unsigned int state_saved:1;
|
||||
unsigned int is_physfn:1;
|
||||
@ -472,12 +470,25 @@ struct pci_bus {
|
||||
/*
|
||||
* Returns true if the pci bus is root (behind host-pci bridge),
|
||||
* false otherwise
|
||||
*
|
||||
* Some code assumes that "bus->self == NULL" means that bus is a root bus.
|
||||
* This is incorrect because "virtual" buses added for SR-IOV (via
|
||||
* virtfn_add_bus()) have "bus->self == NULL" but are not root buses.
|
||||
*/
|
||||
static inline bool pci_is_root_bus(struct pci_bus *pbus)
|
||||
{
|
||||
return !(pbus->parent);
|
||||
}
|
||||
|
||||
static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
|
||||
{
|
||||
dev = pci_physfn(dev);
|
||||
if (pci_is_root_bus(dev->bus))
|
||||
return NULL;
|
||||
|
||||
return dev->bus->self;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev)
|
||||
{
|
||||
@ -1749,11 +1760,11 @@ static inline int pci_pcie_cap(struct pci_dev *dev)
|
||||
* pci_is_pcie - check if the PCI device is PCI Express capable
|
||||
* @dev: PCI device
|
||||
*
|
||||
* Retrun true if the PCI device is PCI Express capable, false otherwise.
|
||||
* Returns: true if the PCI device is PCI Express capable, false otherwise.
|
||||
*/
|
||||
static inline bool pci_is_pcie(struct pci_dev *dev)
|
||||
{
|
||||
return !!pci_pcie_cap(dev);
|
||||
return pci_pcie_cap(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -319,7 +319,6 @@
|
||||
#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */
|
||||
#define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */
|
||||
#define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */
|
||||
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0) /* deprecated */
|
||||
#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */
|
||||
|
||||
/* MSI-X entry's format */
|
||||
@ -558,7 +557,8 @@
|
||||
#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */
|
||||
#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */
|
||||
#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */
|
||||
#define PCI_EXP_DEVCTL2_ARI 0x20 /* Alternative Routing-ID */
|
||||
#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */
|
||||
#define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */
|
||||
#define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */
|
||||
#define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */
|
||||
#define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */
|
||||
|
Loading…
Reference in New Issue
Block a user