mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-09 01:15:16 +07:00
Merge branch 'upstream-fixes'
This commit is contained in:
commit
d22a8ccff7
@ -1338,8 +1338,7 @@ int __cpu_disable(void)
|
|||||||
if (cpu == 0)
|
if (cpu == 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
/* We enable the timer again on the exit path of the death loop */
|
clear_local_APIC();
|
||||||
disable_APIC_timer();
|
|
||||||
/* Allow any queued timer interrupts to get serviced */
|
/* Allow any queued timer interrupts to get serviced */
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
mdelay(1);
|
mdelay(1);
|
||||||
|
@ -223,9 +223,15 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ioremap_nocache);
|
EXPORT_SYMBOL(ioremap_nocache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iounmap - Free a IO remapping
|
||||||
|
* @addr: virtual address from ioremap_*
|
||||||
|
*
|
||||||
|
* Caller must ensure there is only one unmapping for the same pointer.
|
||||||
|
*/
|
||||||
void iounmap(volatile void __iomem *addr)
|
void iounmap(volatile void __iomem *addr)
|
||||||
{
|
{
|
||||||
struct vm_struct *p;
|
struct vm_struct *p, *o;
|
||||||
|
|
||||||
if ((void __force *)addr <= high_memory)
|
if ((void __force *)addr <= high_memory)
|
||||||
return;
|
return;
|
||||||
@ -239,22 +245,37 @@ void iounmap(volatile void __iomem *addr)
|
|||||||
addr < phys_to_virt(ISA_END_ADDRESS))
|
addr < phys_to_virt(ISA_END_ADDRESS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write_lock(&vmlist_lock);
|
addr = (volatile void *)(PAGE_MASK & (unsigned long __force)addr);
|
||||||
p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
|
|
||||||
|
/* Use the vm area unlocked, assuming the caller
|
||||||
|
ensures there isn't another iounmap for the same address
|
||||||
|
in parallel. Reuse of the virtual address is prevented by
|
||||||
|
leaving it in the global lists until we're done with it.
|
||||||
|
cpa takes care of the direct mappings. */
|
||||||
|
read_lock(&vmlist_lock);
|
||||||
|
for (p = vmlist; p; p = p->next) {
|
||||||
|
if (p->addr == addr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_unlock(&vmlist_lock);
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
printk(KERN_WARNING "iounmap: bad address %p\n", addr);
|
printk("iounmap: bad address %p\n", addr);
|
||||||
dump_stack();
|
dump_stack();
|
||||||
goto out_unlock;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the direct mapping. Can block */
|
||||||
if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
|
if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
|
||||||
change_page_attr(virt_to_page(__va(p->phys_addr)),
|
change_page_attr(virt_to_page(__va(p->phys_addr)),
|
||||||
p->size >> PAGE_SHIFT,
|
p->size >> PAGE_SHIFT,
|
||||||
PAGE_KERNEL);
|
PAGE_KERNEL);
|
||||||
global_flush_tlb();
|
global_flush_tlb();
|
||||||
}
|
}
|
||||||
out_unlock:
|
|
||||||
write_unlock(&vmlist_lock);
|
/* Finally remove it */
|
||||||
|
o = remove_vm_area((void *)addr);
|
||||||
|
BUG_ON(p != o || o == NULL);
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iounmap);
|
EXPORT_SYMBOL(iounmap);
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
|
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
|
||||||
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
|
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
|
||||||
|
|
||||||
static int pci_conf1_read(unsigned int seg, unsigned int bus,
|
int pci_conf1_read(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 *value)
|
unsigned int devfn, int reg, int len, u32 *value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -42,7 +42,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_conf1_write(unsigned int seg, unsigned int bus,
|
int pci_conf1_write(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 value)
|
unsigned int devfn, int reg, int len, u32 value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -19,21 +19,25 @@
|
|||||||
/* The base address of the last MMCONFIG device accessed */
|
/* The base address of the last MMCONFIG device accessed */
|
||||||
static u32 mmcfg_last_accessed_device;
|
static u32 mmcfg_last_accessed_device;
|
||||||
|
|
||||||
|
static DECLARE_BITMAP(fallback_slots, 32);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions for accessing PCI configuration space with MMCONFIG accesses
|
* Functions for accessing PCI configuration space with MMCONFIG accesses
|
||||||
*/
|
*/
|
||||||
static u32 get_base_addr(unsigned int seg, int bus)
|
static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
|
||||||
{
|
{
|
||||||
int cfg_num = -1;
|
int cfg_num = -1;
|
||||||
struct acpi_table_mcfg_config *cfg;
|
struct acpi_table_mcfg_config *cfg;
|
||||||
|
|
||||||
|
if (seg == 0 && bus == 0 &&
|
||||||
|
test_bit(PCI_SLOT(devfn), fallback_slots))
|
||||||
|
return 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
++cfg_num;
|
++cfg_num;
|
||||||
if (cfg_num >= pci_mmcfg_config_num) {
|
if (cfg_num >= pci_mmcfg_config_num) {
|
||||||
/* something bad is going on, no cfg table is found. */
|
/* Not found - fallback to type 1 */
|
||||||
/* so we fall back to the old way we used to do this */
|
return 0;
|
||||||
/* and just rely on the first entry to be correct. */
|
|
||||||
return pci_mmcfg_config[0].base_address;
|
|
||||||
}
|
}
|
||||||
cfg = &pci_mmcfg_config[cfg_num];
|
cfg = &pci_mmcfg_config[cfg_num];
|
||||||
if (cfg->pci_segment_group_number != seg)
|
if (cfg->pci_segment_group_number != seg)
|
||||||
@ -44,9 +48,9 @@ static u32 get_base_addr(unsigned int seg, int bus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn)
|
static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
|
||||||
{
|
{
|
||||||
u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12);
|
u32 dev_base = base | (bus << 20) | (devfn << 12);
|
||||||
if (dev_base != mmcfg_last_accessed_device) {
|
if (dev_base != mmcfg_last_accessed_device) {
|
||||||
mmcfg_last_accessed_device = dev_base;
|
mmcfg_last_accessed_device = dev_base;
|
||||||
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
|
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
|
||||||
@ -57,13 +61,18 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
|
|||||||
unsigned int devfn, int reg, int len, u32 *value)
|
unsigned int devfn, int reg, int len, u32 *value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 base;
|
||||||
|
|
||||||
if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
|
if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
base = get_base_addr(seg, bus, devfn);
|
||||||
|
if (!base)
|
||||||
|
return pci_conf1_read(seg,bus,devfn,reg,len,value);
|
||||||
|
|
||||||
spin_lock_irqsave(&pci_config_lock, flags);
|
spin_lock_irqsave(&pci_config_lock, flags);
|
||||||
|
|
||||||
pci_exp_set_dev_base(seg, bus, devfn);
|
pci_exp_set_dev_base(base, bus, devfn);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -86,13 +95,18 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
|||||||
unsigned int devfn, int reg, int len, u32 value)
|
unsigned int devfn, int reg, int len, u32 value)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u32 base;
|
||||||
|
|
||||||
if ((bus > 255) || (devfn > 255) || (reg > 4095))
|
if ((bus > 255) || (devfn > 255) || (reg > 4095))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
base = get_base_addr(seg, bus, devfn);
|
||||||
|
if (!base)
|
||||||
|
return pci_conf1_write(seg,bus,devfn,reg,len,value);
|
||||||
|
|
||||||
spin_lock_irqsave(&pci_config_lock, flags);
|
spin_lock_irqsave(&pci_config_lock, flags);
|
||||||
|
|
||||||
pci_exp_set_dev_base(seg, bus, devfn);
|
pci_exp_set_dev_base(base, bus, devfn);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -116,6 +130,37 @@ static struct pci_raw_ops pci_mmcfg = {
|
|||||||
.write = pci_mmcfg_write,
|
.write = pci_mmcfg_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* K8 systems have some devices (typically in the builtin northbridge)
|
||||||
|
that are only accessible using type1
|
||||||
|
Normally this can be expressed in the MCFG by not listing them
|
||||||
|
and assigning suitable _SEGs, but this isn't implemented in some BIOS.
|
||||||
|
Instead try to discover all devices on bus 0 that are unreachable using MM
|
||||||
|
and fallback for them.
|
||||||
|
We only do this for bus 0/seg 0 */
|
||||||
|
static __init void unreachable_devices(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
u32 val1;
|
||||||
|
u32 addr;
|
||||||
|
|
||||||
|
pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
|
||||||
|
if (val1 == 0xffffffff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Locking probably not needed, but safer */
|
||||||
|
spin_lock_irqsave(&pci_config_lock, flags);
|
||||||
|
addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
|
||||||
|
if (addr != 0)
|
||||||
|
pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
|
||||||
|
if (addr == 0 || readl((u32 *)addr) != val1)
|
||||||
|
set_bit(i, fallback_slots);
|
||||||
|
spin_unlock_irqrestore(&pci_config_lock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __init pci_mmcfg_init(void)
|
static int __init pci_mmcfg_init(void)
|
||||||
{
|
{
|
||||||
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
|
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
|
||||||
@ -131,6 +176,8 @@ static int __init pci_mmcfg_init(void)
|
|||||||
raw_pci_ops = &pci_mmcfg;
|
raw_pci_ops = &pci_mmcfg;
|
||||||
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
|
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
|
||||||
|
|
||||||
|
unreachable_devices();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -74,3 +74,10 @@ extern spinlock_t pci_config_lock;
|
|||||||
|
|
||||||
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
|
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
|
||||||
extern void (*pcibios_disable_irq)(struct pci_dev *dev);
|
extern void (*pcibios_disable_irq)(struct pci_dev *dev);
|
||||||
|
|
||||||
|
extern int pci_conf1_write(unsigned int seg, unsigned int bus,
|
||||||
|
unsigned int devfn, int reg, int len, u32 value);
|
||||||
|
extern int pci_conf1_read(unsigned int seg, unsigned int bus,
|
||||||
|
unsigned int devfn, int reg, int len, u32 *value);
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,8 +217,7 @@ elf_core_copy_task_fpregs(struct task_struct *tsk, struct pt_regs *regs, elf_fpr
|
|||||||
if (!tsk_used_math(tsk))
|
if (!tsk_used_math(tsk))
|
||||||
return 0;
|
return 0;
|
||||||
if (!regs)
|
if (!regs)
|
||||||
regs = (struct pt_regs *)tsk->thread.rsp0;
|
regs = ((struct pt_regs *)tsk->thread.rsp0) - 1;
|
||||||
--regs;
|
|
||||||
if (tsk == current)
|
if (tsk == current)
|
||||||
unlazy_fpu(tsk);
|
unlazy_fpu(tsk);
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
|
@ -1181,7 +1181,7 @@ int __cpu_disable(void)
|
|||||||
if (cpu == 0)
|
if (cpu == 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
disable_APIC_timer();
|
clear_local_APIC();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HACK:
|
* HACK:
|
||||||
|
@ -59,7 +59,7 @@ static int notsc __initdata = 0;
|
|||||||
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
|
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
|
||||||
static unsigned long hpet_period; /* fsecs / HPET clock */
|
static unsigned long hpet_period; /* fsecs / HPET clock */
|
||||||
unsigned long hpet_tick; /* HPET clocks / interrupt */
|
unsigned long hpet_tick; /* HPET clocks / interrupt */
|
||||||
static int hpet_use_timer;
|
static int hpet_use_timer; /* Use counter of hpet for time keeping, otherwise PIT */
|
||||||
unsigned long vxtime_hz = PIT_TICK_RATE;
|
unsigned long vxtime_hz = PIT_TICK_RATE;
|
||||||
int report_lost_ticks; /* command line option */
|
int report_lost_ticks; /* command line option */
|
||||||
unsigned long long monotonic_base;
|
unsigned long long monotonic_base;
|
||||||
@ -908,12 +908,14 @@ void __init time_init(void)
|
|||||||
if (!hpet_init())
|
if (!hpet_init())
|
||||||
vxtime_hz = (1000000000000000L + hpet_period / 2) /
|
vxtime_hz = (1000000000000000L + hpet_period / 2) /
|
||||||
hpet_period;
|
hpet_period;
|
||||||
|
else
|
||||||
|
vxtime.hpet_address = 0;
|
||||||
|
|
||||||
if (hpet_use_timer) {
|
if (hpet_use_timer) {
|
||||||
cpu_khz = hpet_calibrate_tsc();
|
cpu_khz = hpet_calibrate_tsc();
|
||||||
timename = "HPET";
|
timename = "HPET";
|
||||||
#ifdef CONFIG_X86_PM_TIMER
|
#ifdef CONFIG_X86_PM_TIMER
|
||||||
} else if (pmtmr_ioport) {
|
} else if (pmtmr_ioport && !vxtime.hpet_address) {
|
||||||
vxtime_hz = PM_TIMER_FREQUENCY;
|
vxtime_hz = PM_TIMER_FREQUENCY;
|
||||||
timename = "PM";
|
timename = "PM";
|
||||||
pit_init();
|
pit_init();
|
||||||
|
@ -247,9 +247,15 @@ void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
|
|||||||
return __ioremap(phys_addr, size, _PAGE_PCD);
|
return __ioremap(phys_addr, size, _PAGE_PCD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iounmap - Free a IO remapping
|
||||||
|
* @addr: virtual address from ioremap_*
|
||||||
|
*
|
||||||
|
* Caller must ensure there is only one unmapping for the same pointer.
|
||||||
|
*/
|
||||||
void iounmap(volatile void __iomem *addr)
|
void iounmap(volatile void __iomem *addr)
|
||||||
{
|
{
|
||||||
struct vm_struct *p;
|
struct vm_struct *p, *o;
|
||||||
|
|
||||||
if (addr <= high_memory)
|
if (addr <= high_memory)
|
||||||
return;
|
return;
|
||||||
@ -257,12 +263,31 @@ void iounmap(volatile void __iomem *addr)
|
|||||||
addr < phys_to_virt(ISA_END_ADDRESS))
|
addr < phys_to_virt(ISA_END_ADDRESS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
write_lock(&vmlist_lock);
|
addr = (volatile void *)(PAGE_MASK & (unsigned long __force)addr);
|
||||||
p = __remove_vm_area((void *)((unsigned long)addr & PAGE_MASK));
|
/* Use the vm area unlocked, assuming the caller
|
||||||
if (!p)
|
ensures there isn't another iounmap for the same address
|
||||||
|
in parallel. Reuse of the virtual address is prevented by
|
||||||
|
leaving it in the global lists until we're done with it.
|
||||||
|
cpa takes care of the direct mappings. */
|
||||||
|
read_lock(&vmlist_lock);
|
||||||
|
for (p = vmlist; p; p = p->next) {
|
||||||
|
if (p->addr == addr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_unlock(&vmlist_lock);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
printk("iounmap: bad address %p\n", addr);
|
printk("iounmap: bad address %p\n", addr);
|
||||||
else if (p->flags >> 20)
|
dump_stack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset the direct mapping. Can block */
|
||||||
|
if (p->flags >> 20)
|
||||||
ioremap_change_attr(p->phys_addr, p->size, 0);
|
ioremap_change_attr(p->phys_addr, p->size, 0);
|
||||||
write_unlock(&vmlist_lock);
|
|
||||||
|
/* Finally remove it */
|
||||||
|
o = remove_vm_area((void *)addr);
|
||||||
|
BUG_ON(p != o || o == NULL);
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,8 @@ static int __init populate_memnodemap(
|
|||||||
int res = -1;
|
int res = -1;
|
||||||
unsigned long addr, end;
|
unsigned long addr, end;
|
||||||
|
|
||||||
|
if (shift >= 64)
|
||||||
|
return -1;
|
||||||
memset(memnodemap, 0xff, sizeof(memnodemap));
|
memset(memnodemap, 0xff, sizeof(memnodemap));
|
||||||
for (i = 0; i < numnodes; i++) {
|
for (i = 0; i < numnodes; i++) {
|
||||||
addr = nodes[i].start;
|
addr = nodes[i].start;
|
||||||
@ -65,7 +67,7 @@ static int __init populate_memnodemap(
|
|||||||
if (memnodemap[addr >> shift] != 0xff)
|
if (memnodemap[addr >> shift] != 0xff)
|
||||||
return -1;
|
return -1;
|
||||||
memnodemap[addr >> shift] = i;
|
memnodemap[addr >> shift] = i;
|
||||||
addr += (1 << shift);
|
addr += (1UL << shift);
|
||||||
} while (addr < end);
|
} while (addr < end);
|
||||||
res = 1;
|
res = 1;
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,13 @@
|
|||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
#define MMCONFIG_APER_SIZE (256*1024*1024)
|
#define MMCONFIG_APER_SIZE (256*1024*1024)
|
||||||
|
|
||||||
|
static DECLARE_BITMAP(fallback_slots, 32);
|
||||||
|
|
||||||
/* Static virtual mapping of the MMCONFIG aperture */
|
/* Static virtual mapping of the MMCONFIG aperture */
|
||||||
struct mmcfg_virt {
|
struct mmcfg_virt {
|
||||||
struct acpi_table_mcfg_config *cfg;
|
struct acpi_table_mcfg_config *cfg;
|
||||||
@ -19,7 +22,7 @@ struct mmcfg_virt {
|
|||||||
};
|
};
|
||||||
static struct mmcfg_virt *pci_mmcfg_virt;
|
static struct mmcfg_virt *pci_mmcfg_virt;
|
||||||
|
|
||||||
static char *get_virt(unsigned int seg, int bus)
|
static char *get_virt(unsigned int seg, unsigned bus)
|
||||||
{
|
{
|
||||||
int cfg_num = -1;
|
int cfg_num = -1;
|
||||||
struct acpi_table_mcfg_config *cfg;
|
struct acpi_table_mcfg_config *cfg;
|
||||||
@ -27,10 +30,9 @@ static char *get_virt(unsigned int seg, int bus)
|
|||||||
while (1) {
|
while (1) {
|
||||||
++cfg_num;
|
++cfg_num;
|
||||||
if (cfg_num >= pci_mmcfg_config_num) {
|
if (cfg_num >= pci_mmcfg_config_num) {
|
||||||
/* something bad is going on, no cfg table is found. */
|
/* Not found - fall back to type 1. This happens
|
||||||
/* so we fall back to the old way we used to do this */
|
e.g. on the internal devices of a K8 northbridge. */
|
||||||
/* and just rely on the first entry to be correct. */
|
return NULL;
|
||||||
return pci_mmcfg_virt[0].virt;
|
|
||||||
}
|
}
|
||||||
cfg = pci_mmcfg_virt[cfg_num].cfg;
|
cfg = pci_mmcfg_virt[cfg_num].cfg;
|
||||||
if (cfg->pci_segment_group_number != seg)
|
if (cfg->pci_segment_group_number != seg)
|
||||||
@ -41,20 +43,30 @@ static char *get_virt(unsigned int seg, int bus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
|
static char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
|
||||||
{
|
{
|
||||||
|
char *addr;
|
||||||
return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
|
if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
|
||||||
|
return NULL;
|
||||||
|
addr = get_virt(seg, bus);
|
||||||
|
if (!addr)
|
||||||
|
return NULL;
|
||||||
|
return addr + ((bus << 20) | (devfn << 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
|
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 *value)
|
unsigned int devfn, int reg, int len, u32 *value)
|
||||||
{
|
{
|
||||||
char *addr = pci_dev_base(seg, bus, devfn);
|
char *addr;
|
||||||
|
|
||||||
|
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
|
||||||
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
|
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
addr = pci_dev_base(seg, bus, devfn);
|
||||||
|
if (!addr)
|
||||||
|
return pci_conf1_read(seg,bus,devfn,reg,len,value);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
*value = readb(addr + reg);
|
*value = readb(addr + reg);
|
||||||
@ -73,11 +85,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
|
|||||||
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
|
||||||
unsigned int devfn, int reg, int len, u32 value)
|
unsigned int devfn, int reg, int len, u32 value)
|
||||||
{
|
{
|
||||||
char *addr = pci_dev_base(seg, bus, devfn);
|
char *addr;
|
||||||
|
|
||||||
|
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
|
||||||
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
|
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
addr = pci_dev_base(seg, bus, devfn);
|
||||||
|
if (!addr)
|
||||||
|
return pci_conf1_write(seg,bus,devfn,reg,len,value);
|
||||||
|
|
||||||
switch (len) {
|
switch (len) {
|
||||||
case 1:
|
case 1:
|
||||||
writeb(value, addr + reg);
|
writeb(value, addr + reg);
|
||||||
@ -98,6 +115,30 @@ static struct pci_raw_ops pci_mmcfg = {
|
|||||||
.write = pci_mmcfg_write,
|
.write = pci_mmcfg_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* K8 systems have some devices (typically in the builtin northbridge)
|
||||||
|
that are only accessible using type1
|
||||||
|
Normally this can be expressed in the MCFG by not listing them
|
||||||
|
and assigning suitable _SEGs, but this isn't implemented in some BIOS.
|
||||||
|
Instead try to discover all devices on bus 0 that are unreachable using MM
|
||||||
|
and fallback for them.
|
||||||
|
We only do this for bus 0/seg 0 */
|
||||||
|
static __init void unreachable_devices(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
u32 val1;
|
||||||
|
char *addr;
|
||||||
|
|
||||||
|
pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
|
||||||
|
if (val1 == 0xffffffff)
|
||||||
|
continue;
|
||||||
|
addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
|
||||||
|
if (addr == NULL|| readl(addr) != val1) {
|
||||||
|
set_bit(i, &fallback_slots);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int __init pci_mmcfg_init(void)
|
static int __init pci_mmcfg_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -128,6 +169,8 @@ static int __init pci_mmcfg_init(void)
|
|||||||
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
|
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unreachable_devices();
|
||||||
|
|
||||||
raw_pci_ops = &pci_mmcfg;
|
raw_pci_ops = &pci_mmcfg;
|
||||||
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
|
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
|
||||||
|
|
||||||
|
@ -1464,8 +1464,10 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
|
|||||||
request_queue_t *q = disk->queue;
|
request_queue_t *q = disk->queue;
|
||||||
if (disk->flags & GENHD_FL_UP)
|
if (disk->flags & GENHD_FL_UP)
|
||||||
del_gendisk(disk);
|
del_gendisk(disk);
|
||||||
if (q)
|
if (q) {
|
||||||
blk_cleanup_queue(q);
|
blk_cleanup_queue(q);
|
||||||
|
drv->queue = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1522,7 +1522,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
|
|||||||
|
|
||||||
dev_priv->gart_size = init->gart_size;
|
dev_priv->gart_size = init->gart_size;
|
||||||
dev_priv->gart_vm_start = dev_priv->fb_location
|
dev_priv->gart_vm_start = dev_priv->fb_location
|
||||||
+ RADEON_READ(RADEON_CONFIG_APER_SIZE);
|
+ RADEON_READ(RADEON_CONFIG_APER_SIZE) * 2;
|
||||||
|
|
||||||
#if __OS_HAS_AGP
|
#if __OS_HAS_AGP
|
||||||
if (!dev_priv->is_pci)
|
if (!dev_priv->is_pci)
|
||||||
|
@ -2280,7 +2280,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
|
if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
|
||||||
if (!netif_stopped(dev)) {
|
if (!netif_queue_stopped(dev)) {
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
|
|
||||||
printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
|
printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
|
||||||
|
@ -2443,7 +2443,7 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
|
|||||||
struct scatterlist *psg = &qc->pad_sgent;
|
struct scatterlist *psg = &qc->pad_sgent;
|
||||||
void *addr = kmap_atomic(psg->page, KM_IRQ0);
|
void *addr = kmap_atomic(psg->page, KM_IRQ0);
|
||||||
memcpy(addr + psg->offset, pad_buf, qc->pad_len);
|
memcpy(addr + psg->offset, pad_buf, qc->pad_len);
|
||||||
kunmap_atomic(psg->page, KM_IRQ0);
|
kunmap_atomic(addr, KM_IRQ0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (sg_dma_len(&sg[0]) > 0)
|
if (sg_dma_len(&sg[0]) > 0)
|
||||||
@ -2717,7 +2717,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|||||||
if (qc->tf.flags & ATA_TFLAG_WRITE) {
|
if (qc->tf.flags & ATA_TFLAG_WRITE) {
|
||||||
void *addr = kmap_atomic(psg->page, KM_IRQ0);
|
void *addr = kmap_atomic(psg->page, KM_IRQ0);
|
||||||
memcpy(pad_buf, addr + psg->offset, qc->pad_len);
|
memcpy(pad_buf, addr + psg->offset, qc->pad_len);
|
||||||
kunmap_atomic(psg->page, KM_IRQ0);
|
kunmap_atomic(addr, KM_IRQ0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
|
sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ);
|
||||||
|
@ -64,8 +64,8 @@ bitcpy(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem *src
|
|||||||
int const shift = dst_idx-src_idx;
|
int const shift = dst_idx-src_idx;
|
||||||
int left, right;
|
int left, right;
|
||||||
|
|
||||||
first = ~0UL >> dst_idx;
|
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||||
|
|
||||||
if (!shift) {
|
if (!shift) {
|
||||||
// Same alignment for source and dest
|
// Same alignment for source and dest
|
||||||
@ -216,8 +216,8 @@ bitcpy_rev(unsigned long __iomem *dst, int dst_idx, const unsigned long __iomem
|
|||||||
|
|
||||||
shift = dst_idx-src_idx;
|
shift = dst_idx-src_idx;
|
||||||
|
|
||||||
first = ~0UL << (bits - 1 - dst_idx);
|
first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
|
||||||
last = ~(~0UL << (bits - 1 - ((dst_idx-n) % bits)));
|
last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
|
||||||
|
|
||||||
if (!shift) {
|
if (!shift) {
|
||||||
// Same alignment for source and dest
|
// Same alignment for source and dest
|
||||||
|
@ -110,8 +110,8 @@ bitfill_aligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat, unsi
|
|||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first = ~0UL >> dst_idx;
|
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||||
|
|
||||||
if (dst_idx+n <= bits) {
|
if (dst_idx+n <= bits) {
|
||||||
// Single word
|
// Single word
|
||||||
@ -167,8 +167,8 @@ bitfill_unaligned(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
|
|||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first = ~0UL >> dst_idx;
|
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||||
|
|
||||||
if (dst_idx+n <= bits) {
|
if (dst_idx+n <= bits) {
|
||||||
// Single word
|
// Single word
|
||||||
@ -221,8 +221,8 @@ bitfill_aligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat,
|
|||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first = ~0UL >> dst_idx;
|
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||||
|
|
||||||
if (dst_idx+n <= bits) {
|
if (dst_idx+n <= bits) {
|
||||||
// Single word
|
// Single word
|
||||||
@ -290,8 +290,8 @@ bitfill_unaligned_rev(unsigned long __iomem *dst, int dst_idx, unsigned long pat
|
|||||||
if (!n)
|
if (!n)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
first = ~0UL >> dst_idx;
|
first = FB_SHIFT_HIGH(~0UL, dst_idx);
|
||||||
last = ~(~0UL >> ((dst_idx+n) % bits));
|
last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
|
||||||
|
|
||||||
if (dst_idx+n <= bits) {
|
if (dst_idx+n <= bits) {
|
||||||
// Single word
|
// Single word
|
||||||
|
@ -76,18 +76,6 @@ static u32 cfb_tab32[] = {
|
|||||||
#define FB_WRITEL fb_writel
|
#define FB_WRITEL fb_writel
|
||||||
#define FB_READL fb_readl
|
#define FB_READL fb_readl
|
||||||
|
|
||||||
#if defined (__BIG_ENDIAN)
|
|
||||||
#define LEFT_POS(bpp) (32 - bpp)
|
|
||||||
#define SHIFT_HIGH(val, bits) ((val) >> (bits))
|
|
||||||
#define SHIFT_LOW(val, bits) ((val) << (bits))
|
|
||||||
#define BIT_NR(b) (7 - (b))
|
|
||||||
#else
|
|
||||||
#define LEFT_POS(bpp) (0)
|
|
||||||
#define SHIFT_HIGH(val, bits) ((val) << (bits))
|
|
||||||
#define SHIFT_LOW(val, bits) ((val) >> (bits))
|
|
||||||
#define BIT_NR(b) (b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void color_imageblit(const struct fb_image *image,
|
static inline void color_imageblit(const struct fb_image *image,
|
||||||
struct fb_info *p, u8 __iomem *dst1,
|
struct fb_info *p, u8 __iomem *dst1,
|
||||||
u32 start_index,
|
u32 start_index,
|
||||||
@ -109,7 +97,7 @@ static inline void color_imageblit(const struct fb_image *image,
|
|||||||
val = 0;
|
val = 0;
|
||||||
|
|
||||||
if (start_index) {
|
if (start_index) {
|
||||||
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
|
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0, start_index));
|
||||||
val = FB_READL(dst) & start_mask;
|
val = FB_READL(dst) & start_mask;
|
||||||
shift = start_index;
|
shift = start_index;
|
||||||
}
|
}
|
||||||
@ -119,20 +107,20 @@ static inline void color_imageblit(const struct fb_image *image,
|
|||||||
color = palette[*src];
|
color = palette[*src];
|
||||||
else
|
else
|
||||||
color = *src;
|
color = *src;
|
||||||
color <<= LEFT_POS(bpp);
|
color <<= FB_LEFT_POS(bpp);
|
||||||
val |= SHIFT_HIGH(color, shift);
|
val |= FB_SHIFT_HIGH(color, shift);
|
||||||
if (shift >= null_bits) {
|
if (shift >= null_bits) {
|
||||||
FB_WRITEL(val, dst++);
|
FB_WRITEL(val, dst++);
|
||||||
|
|
||||||
val = (shift == null_bits) ? 0 :
|
val = (shift == null_bits) ? 0 :
|
||||||
SHIFT_LOW(color, 32 - shift);
|
FB_SHIFT_LOW(color, 32 - shift);
|
||||||
}
|
}
|
||||||
shift += bpp;
|
shift += bpp;
|
||||||
shift &= (32 - 1);
|
shift &= (32 - 1);
|
||||||
src++;
|
src++;
|
||||||
}
|
}
|
||||||
if (shift) {
|
if (shift) {
|
||||||
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
|
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
|
||||||
|
|
||||||
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
||||||
}
|
}
|
||||||
@ -162,6 +150,8 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||||||
u32 i, j, l;
|
u32 i, j, l;
|
||||||
|
|
||||||
dst2 = (u32 __iomem *) dst1;
|
dst2 = (u32 __iomem *) dst1;
|
||||||
|
fgcolor <<= FB_LEFT_POS(bpp);
|
||||||
|
bgcolor <<= FB_LEFT_POS(bpp);
|
||||||
|
|
||||||
for (i = image->height; i--; ) {
|
for (i = image->height; i--; ) {
|
||||||
shift = val = 0;
|
shift = val = 0;
|
||||||
@ -172,22 +162,21 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||||||
|
|
||||||
/* write leading bits */
|
/* write leading bits */
|
||||||
if (start_index) {
|
if (start_index) {
|
||||||
u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
|
u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
|
||||||
val = FB_READL(dst) & start_mask;
|
val = FB_READL(dst) & start_mask;
|
||||||
shift = start_index;
|
shift = start_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (j--) {
|
while (j--) {
|
||||||
l--;
|
l--;
|
||||||
color = (*s & 1 << (BIT_NR(l))) ? fgcolor : bgcolor;
|
color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor;
|
||||||
color <<= LEFT_POS(bpp);
|
val |= FB_SHIFT_HIGH(color, shift);
|
||||||
val |= SHIFT_HIGH(color, shift);
|
|
||||||
|
|
||||||
/* Did the bitshift spill bits to the next long? */
|
/* Did the bitshift spill bits to the next long? */
|
||||||
if (shift >= null_bits) {
|
if (shift >= null_bits) {
|
||||||
FB_WRITEL(val, dst++);
|
FB_WRITEL(val, dst++);
|
||||||
val = (shift == null_bits) ? 0 :
|
val = (shift == null_bits) ? 0 :
|
||||||
SHIFT_LOW(color,32 - shift);
|
FB_SHIFT_LOW(color,32 - shift);
|
||||||
}
|
}
|
||||||
shift += bpp;
|
shift += bpp;
|
||||||
shift &= (32 - 1);
|
shift &= (32 - 1);
|
||||||
@ -196,7 +185,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info *
|
|||||||
|
|
||||||
/* write trailing bits */
|
/* write trailing bits */
|
||||||
if (shift) {
|
if (shift) {
|
||||||
u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
|
u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
|
||||||
|
|
||||||
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
|
||||||
}
|
}
|
||||||
|
@ -2048,7 +2048,7 @@ static int fbcon_switch(struct vc_data *vc)
|
|||||||
struct fbcon_ops *ops;
|
struct fbcon_ops *ops;
|
||||||
struct display *p = &fb_display[vc->vc_num];
|
struct display *p = &fb_display[vc->vc_num];
|
||||||
struct fb_var_screeninfo var;
|
struct fb_var_screeninfo var;
|
||||||
int i, prev_console;
|
int i, prev_console, charcnt = 256;
|
||||||
|
|
||||||
info = registered_fb[con2fb_map[vc->vc_num]];
|
info = registered_fb[con2fb_map[vc->vc_num]];
|
||||||
ops = info->fbcon_par;
|
ops = info->fbcon_par;
|
||||||
@ -2103,7 +2103,8 @@ static int fbcon_switch(struct vc_data *vc)
|
|||||||
fb_set_var(info, &var);
|
fb_set_var(info, &var);
|
||||||
ops->var = info->var;
|
ops->var = info->var;
|
||||||
|
|
||||||
if (old_info != NULL && old_info != info) {
|
if (old_info != NULL && (old_info != info ||
|
||||||
|
info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
|
||||||
if (info->fbops->fb_set_par)
|
if (info->fbops->fb_set_par)
|
||||||
info->fbops->fb_set_par(info);
|
info->fbops->fb_set_par(info);
|
||||||
fbcon_del_cursor_timer(old_info);
|
fbcon_del_cursor_timer(old_info);
|
||||||
@ -2120,6 +2121,13 @@ static int fbcon_switch(struct vc_data *vc)
|
|||||||
|
|
||||||
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
|
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
|
||||||
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
|
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
|
||||||
|
|
||||||
|
if (p->userfont)
|
||||||
|
charcnt = FNTCHARCNT(vc->vc_font.data);
|
||||||
|
|
||||||
|
if (charcnt > 256)
|
||||||
|
vc->vc_complement_mask <<= 1;
|
||||||
|
|
||||||
updatescrollmode(p, info, vc);
|
updatescrollmode(p, info, vc);
|
||||||
|
|
||||||
switch (p->scrollmode) {
|
switch (p->scrollmode) {
|
||||||
@ -2139,8 +2147,12 @@ static int fbcon_switch(struct vc_data *vc)
|
|||||||
|
|
||||||
scrollback_max = 0;
|
scrollback_max = 0;
|
||||||
scrollback_current = 0;
|
scrollback_current = 0;
|
||||||
|
|
||||||
|
if (!fbcon_is_inactive(vc, info)) {
|
||||||
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
|
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
|
||||||
ops->update_start(info);
|
ops->update_start(info);
|
||||||
|
}
|
||||||
|
|
||||||
fbcon_set_palette(vc, color_table);
|
fbcon_set_palette(vc, color_table);
|
||||||
fbcon_clear_margins(vc, 0);
|
fbcon_clear_margins(vc, 0);
|
||||||
|
|
||||||
@ -2184,11 +2196,14 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|||||||
ops->graphics = 1;
|
ops->graphics = 1;
|
||||||
|
|
||||||
if (!blank) {
|
if (!blank) {
|
||||||
|
if (info->fbops->fb_save_state)
|
||||||
|
info->fbops->fb_save_state(info);
|
||||||
var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
|
var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
|
||||||
fb_set_var(info, &var);
|
fb_set_var(info, &var);
|
||||||
ops->graphics = 0;
|
ops->graphics = 0;
|
||||||
ops->var = info->var;
|
ops->var = info->var;
|
||||||
}
|
} else if (info->fbops->fb_restore_state)
|
||||||
|
info->fbops->fb_restore_state(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fbcon_is_inactive(vc, info)) {
|
if (!fbcon_is_inactive(vc, info)) {
|
||||||
@ -2736,8 +2751,12 @@ static void fbcon_modechanged(struct fb_info *info)
|
|||||||
updatescrollmode(p, info, vc);
|
updatescrollmode(p, info, vc);
|
||||||
scrollback_max = 0;
|
scrollback_max = 0;
|
||||||
scrollback_current = 0;
|
scrollback_current = 0;
|
||||||
|
|
||||||
|
if (!fbcon_is_inactive(vc, info)) {
|
||||||
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
|
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
|
||||||
ops->update_start(info);
|
ops->update_start(info);
|
||||||
|
}
|
||||||
|
|
||||||
fbcon_set_palette(vc, color_table);
|
fbcon_set_palette(vc, color_table);
|
||||||
update_screen(vc);
|
update_screen(vc);
|
||||||
if (softback_buf)
|
if (softback_buf)
|
||||||
@ -2774,8 +2793,13 @@ static void fbcon_set_all_vcs(struct fb_info *info)
|
|||||||
updatescrollmode(p, info, vc);
|
updatescrollmode(p, info, vc);
|
||||||
scrollback_max = 0;
|
scrollback_max = 0;
|
||||||
scrollback_current = 0;
|
scrollback_current = 0;
|
||||||
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
|
|
||||||
|
if (!fbcon_is_inactive(vc, info)) {
|
||||||
|
ops->var.xoffset = ops->var.yoffset =
|
||||||
|
p->yscroll = 0;
|
||||||
ops->update_start(info);
|
ops->update_start(info);
|
||||||
|
}
|
||||||
|
|
||||||
fbcon_set_palette(vc, color_table);
|
fbcon_set_palette(vc, color_table);
|
||||||
update_screen(vc);
|
update_screen(vc);
|
||||||
if (softback_buf)
|
if (softback_buf)
|
||||||
|
@ -722,14 +722,30 @@ static void try_to_load(int fb)
|
|||||||
int
|
int
|
||||||
fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
|
fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||||
{
|
{
|
||||||
|
struct fb_fix_screeninfo *fix = &info->fix;
|
||||||
int xoffset = var->xoffset;
|
int xoffset = var->xoffset;
|
||||||
int yoffset = var->yoffset;
|
int yoffset = var->yoffset;
|
||||||
int err;
|
int err = 0, yres = info->var.yres;
|
||||||
|
|
||||||
if (xoffset < 0 || yoffset < 0 || !info->fbops->fb_pan_display ||
|
if (var->yoffset > 0) {
|
||||||
xoffset + info->var.xres > info->var.xres_virtual ||
|
if (var->vmode & FB_VMODE_YWRAP) {
|
||||||
yoffset + info->var.yres > info->var.yres_virtual)
|
if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep))
|
||||||
|
err = -EINVAL;
|
||||||
|
else
|
||||||
|
yres = 0;
|
||||||
|
} else if (!fix->ypanstep || (var->yoffset % fix->ypanstep))
|
||||||
|
err = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var->xoffset > 0 && (!fix->xpanstep ||
|
||||||
|
(var->xoffset % fix->xpanstep)))
|
||||||
|
err = -EINVAL;
|
||||||
|
|
||||||
|
if (err || !info->fbops->fb_pan_display || xoffset < 0 ||
|
||||||
|
yoffset < 0 || var->yoffset + yres > info->var.yres_virtual ||
|
||||||
|
var->xoffset + info->var.xres > info->var.xres_virtual)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if ((err = info->fbops->fb_pan_display(var, info)))
|
if ((err = info->fbops->fb_pan_display(var, info)))
|
||||||
return err;
|
return err;
|
||||||
info->var.xoffset = var->xoffset;
|
info->var.xoffset = var->xoffset;
|
||||||
|
@ -617,6 +617,12 @@ struct fb_ops {
|
|||||||
|
|
||||||
/* perform fb specific mmap */
|
/* perform fb specific mmap */
|
||||||
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
|
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
|
||||||
|
|
||||||
|
/* save current hardware state */
|
||||||
|
void (*fb_save_state)(struct fb_info *info);
|
||||||
|
|
||||||
|
/* restore saved state */
|
||||||
|
void (*fb_restore_state)(struct fb_info *info);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_FB_TILEBLITTING
|
#ifdef CONFIG_FB_TILEBLITTING
|
||||||
@ -726,6 +732,18 @@ struct fb_tile_ops {
|
|||||||
from userspace */
|
from userspace */
|
||||||
#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */
|
#define FBINFO_MISC_TILEBLITTING 0x20000 /* use tile blitting */
|
||||||
|
|
||||||
|
/* A driver may set this flag to indicate that it does want a set_par to be
|
||||||
|
* called every time when fbcon_switch is executed. The advantage is that with
|
||||||
|
* this flag set you can really be shure that set_par is always called before
|
||||||
|
* any of the functions dependant on the correct hardware state or altering
|
||||||
|
* that state, even if you are using some broken X releases. The disadvantage
|
||||||
|
* is that it introduces unwanted delays to every console switch if set_par
|
||||||
|
* is slow. It is a good idea to try this flag in the drivers initialization
|
||||||
|
* code whenever there is a bug report related to switching between X and the
|
||||||
|
* framebuffer console.
|
||||||
|
*/
|
||||||
|
#define FBINFO_MISC_ALWAYS_SETPAR 0x40000
|
||||||
|
|
||||||
struct fb_info {
|
struct fb_info {
|
||||||
int node;
|
int node;
|
||||||
int flags;
|
int flags;
|
||||||
@ -815,6 +833,18 @@ struct fb_info {
|
|||||||
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
|
#define fb_writeq(b,addr) (*(volatile u64 *) (addr) = (b))
|
||||||
#define fb_memset memset
|
#define fb_memset memset
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__BIG_ENDIAN)
|
||||||
|
#define FB_LEFT_POS(bpp) (32 - bpp)
|
||||||
|
#define FB_SHIFT_HIGH(val, bits) ((val) >> (bits))
|
||||||
|
#define FB_SHIFT_LOW(val, bits) ((val) << (bits))
|
||||||
|
#define FB_BIT_NR(b) (7 - (b))
|
||||||
|
#else
|
||||||
|
#define FB_LEFT_POS(bpp) (0)
|
||||||
|
#define FB_SHIFT_HIGH(val, bits) ((val) << (bits))
|
||||||
|
#define FB_SHIFT_LOW(val, bits) ((val) >> (bits))
|
||||||
|
#define FB_BIT_NR(b) (b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user