Commit d7203748 authored by Steve French's avatar Steve French

Merge bk://linux.bkbits.net/linux-2.5

into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs
parents d5c7cd85 a60e227b
......@@ -1444,27 +1444,6 @@ as Alan Cox says, <quote>Lock data, not code</quote>.
</para>
</sect1>
<sect1 id="sparc">
<title>The Fucked Up Sparc</title>
<para>
Alan Cox says <quote>the irq disable/enable is in the register
window on a sparc</quote>. Andi Kleen says <quote>when you do
restore_flags in a different function you mess up all the
register windows</quote>.
</para>
<para>
So never pass the flags word set by
<function>spin_lock_irqsave()</function> and brethren to another
function (unless it's declared <type>inline</type>). Usually no-one
does this, but now you've been warned. Dave Miller can never do
anything in a straightforward manner (I can say that, because I have
pictures of him and a certain PowerPC maintainer in a compromising
position).
</para>
</sect1>
</chapter>
<chapter id="Efficiency">
......
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 3
EXTRAVERSION =-rc2
EXTRAVERSION =-rc3
NAME=Feisty Dunnart
# *DOCUMENTATION*
......
......@@ -50,7 +50,7 @@ static int amba_hotplug(struct device *dev, char **envp, int nr_env, char *buf,
if (nr_env < 2)
return -ENOMEM;
snprintf(buf, bufsz, "AMBA_ID=%08lx", pcdev->periphid);
snprintf(buf, bufsz, "AMBA_ID=%08x", pcdev->periphid);
*envp++ = buf;
*envp++ = NULL;
return 0;
......
......@@ -116,7 +116,7 @@ static inline void do_set_rtc(void)
return;
if (next_rtc_update &&
time_before(xtime.tv_sec, next_rtc_update))
time_before((unsigned long)xtime.tv_sec, next_rtc_update))
return;
if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
......
......@@ -159,9 +159,14 @@ static struct resource sa11x0mcp_resources[] = {
},
};
static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
static struct platform_device sa11x0mcp_device = {
.name = "sa11x0-mcp",
.id = 0,
.dev = {
.dma_mask = &sa11x0mcp_dma_mask,
},
.num_resources = ARRAY_SIZE(sa11x0mcp_resources),
.resource = sa11x0mcp_resources,
};
......
......@@ -291,8 +291,8 @@ config ARM_THUMB
depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM926T || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE
default y
help
Say Y if you want to have kernel support for ARM Thumb instructions,
fault handlers, and system calls.
Say Y if you want to include kernel support for running user space
Thumb binaries.
The Thumb instruction set is a compressed form of the standard ARM
instruction set resulting in smaller binaries at the expense of
......
......@@ -589,7 +589,7 @@ acpi_boot_init (void)
smp_boot_data.cpu_count = available_cpus;
smp_build_cpu_map();
# ifdef CONFIG_NUMA
# ifdef CONFIG_ACPI_NUMA
if (srat_num_cpus == 0) {
int cpu, i = 1;
for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++)
......
......@@ -465,8 +465,6 @@ unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs)
desc->handler->ack(irq);
action_ret = handle_IRQ_event(irq, regs, desc->action);
desc->handler->end(irq);
if (!noirqdebug)
note_interrupt(irq, desc, action_ret);
} else {
spin_lock(&desc->lock);
desc->handler->ack(irq);
......
......@@ -239,10 +239,9 @@ ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe)
* and wakes up any processes waiting for error records.
*
* Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT)
* called_from_init (1 for boot processing)
*/
static void
ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
ia64_mca_log_sal_error_record(int sal_info_type)
{
u8 *buffer;
u64 size;
......@@ -255,7 +254,7 @@ ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe);
if (irq_safe || called_from_init)
if (irq_safe)
printk(KERN_INFO "CPU %d: SAL log contains %s error record\n",
smp_processor_id(),
sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN");
......@@ -280,7 +279,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
local_irq_enable();
/* Get the CMC error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
return IRQ_HANDLED;
}
......@@ -469,32 +468,6 @@ init_handler_platform (pal_min_state_area_t *ms,
while (1); /* hang city if no debugger */
}
/*
* ia64_mca_check_errors
*
* External entry to check for error records which may have been posted by SAL
* for a prior failure which resulted in a machine shutdown before an the
* error could be logged. This function must be called after the filesystem
* is initialized.
*
* Inputs : None
*
* Outputs : None
*/
int
ia64_mca_check_errors (void)
{
/*
* If there is an MCA error record pending, get it and log it.
*/
printk(KERN_INFO "CPU %d: checking for saved MCA error records\n", smp_processor_id());
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
return 0;
}
device_initcall(ia64_mca_check_errors);
#ifdef CONFIG_ACPI
/*
* ia64_mca_register_cpev
......@@ -831,7 +804,7 @@ ia64_mca_ucmc_handler(void)
int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc);
/* Get the MCA error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);
/*
* Wakeup all the processors which are spinning in the rendezvous
......@@ -875,7 +848,7 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
local_irq_enable();
/* Get the CMC error record and log it */
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC, 0);
ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
spin_lock(&cmc_history_lock);
if (!cmc_polling_enabled) {
......
......@@ -18,10 +18,6 @@
* 10/13/00 Goutham Rao <goutham.rao@intel.com> Updated smp_call_function and
* smp_call_function_single to resend IPI on timeouts
*/
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......
......@@ -10,10 +10,6 @@
* smp_boot_cpus()/smp_commence() is replaced by
* smp_prepare_cpus()/__cpu_up()/smp_cpus_done().
*/
#define __KERNEL_SYSCALLS__
#include <linux/config.h>
#include <linux/module.h>
......@@ -306,7 +302,6 @@ smp_callin (void)
#ifdef CONFIG_IA64_MCA
ia64_mca_cmc_vector_setup(); /* Setup vector on AP & enable */
ia64_mca_check_errors(); /* For post-failure MCA error logging */
#endif
#ifdef CONFIG_PERFMON
......
......@@ -5,9 +5,14 @@
CPPFLAGS=""
CC=$1
OBJDUMP=$2
READELF=$3
dir=$(dirname $0)
tmp=${TMPDIR:-/tmp}
out=$tmp/out$$
# Check whether cross-segment segment-relative relocs work fine. We need
# that for building the gate DSO:
$CC -nostdlib -static -Wl,-T$dir/check-segrel.lds $dir/check-segrel.S -o $out
res=$($OBJDUMP --full --section .rodata $out | fgrep 000 | cut -f3 -d' ')
rm -f $out
......@@ -20,6 +25,16 @@ warning: your linker cannot handle cross-segment segment-relative relocations.
EOF
fi
# Check whether .align inside a function works as expected.
$CC -c $dir/check-text-align.S -o $out
$READELF -u $out | fgrep -q 'prologue(rlen=12)'
res=$?
rm -f $out
if [ $res -eq 0 ]; then
CPPFLAGS="$CPPFLAGS -DHAVE_WORKING_TEXT_ALIGN"
fi
if ! $CC -c $dir/check-model.c -o $out 2>&1 | grep __model__ | grep -q attrib
then
CPPFLAGS="$CPPFLAGS -DHAVE_MODEL_SMALL_ATTRIBUTE"
......
......@@ -71,6 +71,8 @@ u64 sn_partition_serial_number;
short physical_node_map[MAX_PHYSNODE_ID];
EXPORT_SYMBOL(physical_node_map);
int numionodes;
/*
* This is the address of the RRegs in the HSpace of the global
......
......@@ -6,7 +6,7 @@
* Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved.
*
*/
#include <linux/module.h>
#include <asm/pgalloc.h>
/**
......
......@@ -772,7 +772,7 @@ sn_sal_read_proc(char *page, char **start, off_t off, int count,
int len = 0;
off_t begin = 0;
len += sprintf(page, "sn_serial: nasid:%d irq:%d tx:%d rx:%d\n",
len += sprintf(page, "sn_serial: nasid:%ld irq:%d tx:%d rx:%d\n",
ia64_sn_get_console_nasid(), sn_sal_irq,
sn_total_tx_count, sn_total_rx_count);
*eof = 1;
......
......@@ -72,13 +72,6 @@
/* How many iterations between battery polls */
#define BATTERY_POLLING_COUNT 2
/* Some debugging tools */
#ifdef CONFIG_XMON
//#define LIVE_DEBUG(req) ((req) && (req)->data[0] == 0x7d)
#define LIVE_DEBUG(req) (0)
static int whacky_debug;
#endif /* CONFIG_XMON */
static volatile unsigned char *via;
/* VIA registers - spaced 0x200 bytes apart */
......@@ -1218,12 +1211,6 @@ pmu_start(void)
wait_for_ack();
/* set the shift register to shift out and send a byte */
send_byte(req->data[0]);
#ifdef CONFIG_XMON
if (LIVE_DEBUG(req))
xmon_printf("R");
else
whacky_debug = 0;
#endif /* CONFIG_XMON */
}
void __openfirmware
......@@ -1476,29 +1463,17 @@ pmu_sr_intr(struct pt_regs *regs)
case sending:
req = current_req;
if (data_len < 0) {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(req))
xmon_printf("s");
#endif /* CONFIG_XMON */
data_len = req->nbytes - 1;
send_byte(data_len);
break;
}
if (data_index <= data_len) {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(req))
xmon_printf("S");
#endif /* CONFIG_XMON */
send_byte(req->data[data_index++]);
break;
}
req->sent = 1;
data_len = pmu_data_len[req->data[0]][1];
if (data_len == 0) {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(req))
xmon_printf("D");
#endif /* CONFIG_XMON */
pmu_state = idle;
current_req = req->next;
if (req->reply_expected)
......@@ -1506,10 +1481,6 @@ pmu_sr_intr(struct pt_regs *regs)
else
return req;
} else {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(req))
xmon_printf("-");
#endif /* CONFIG_XMON */
pmu_state = reading;
data_index = 0;
reply_ptr = req->reply + req->reply_len;
......@@ -1532,18 +1503,10 @@ pmu_sr_intr(struct pt_regs *regs)
case reading:
case reading_intr:
if (data_len == -1) {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(current_req))
xmon_printf("r");
#endif /* CONFIG_XMON */
data_len = bite;
if (bite > 32)
printk(KERN_ERR "PMU: bad reply len %d\n", bite);
} else if (data_index < 32) {
#ifdef CONFIG_XMON
if (LIVE_DEBUG(current_req))
xmon_printf("R");
#endif /* CONFIG_XMON */
reply_ptr[data_index++] = bite;
}
if (data_index < data_len) {
......@@ -1551,12 +1514,6 @@ pmu_sr_intr(struct pt_regs *regs)
break;
}
#ifdef CONFIG_XMON
if (LIVE_DEBUG(current_req)) {
whacky_debug = 1;
xmon_printf("D");
}
#endif /* CONFIG_XMON */
if (pmu_state == reading_intr) {
pmu_state = idle;
int_data_state[int_data_last] = int_data_ready;
......@@ -1603,10 +1560,6 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
if (intr == 0)
break;
#ifdef CONFIG_XMON
if (whacky_debug)
xmon_printf("|%02x|", intr);
#endif /* CONFIG_XMON */
handled = 1;
if (++nloop > 1000) {
printk(KERN_DEBUG "PMU: stuck in intr loop, "
......@@ -1629,10 +1582,6 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
recheck:
if (pmu_state == idle) {
if (adb_int_pending) {
#ifdef CONFIG_XMON
if (whacky_debug)
xmon_printf("!A!");
#endif /* CONFIG_XMON */
if (int_data_state[0] == int_data_empty)
int_data_last = 0;
else if (int_data_state[1] == int_data_empty)
......
......@@ -13,6 +13,7 @@
*
* Benjamin Herrenschmidt
* - pmac-specific PM stuff
* - various fixes & cleanups
*
* Andreas Hundt <andi@convergence.de>
* - FB_ACTIVATE fixes
......@@ -24,6 +25,10 @@
* Paul Mundt
* - PCI hotplug
*
* Jon Smirl <jonsmirl@yahoo.com>
* - PCI ID update
* - replace ROM BIOS search
*
* Based off of Geert's atyfb.c and vfb.c.
*
* TODO:
......@@ -43,6 +48,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
......@@ -57,6 +63,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/console.h>
#include <asm/io.h>
#ifdef CONFIG_PPC_PMAC
......@@ -65,11 +72,6 @@
#include "../macmodes.h"
#endif
#ifdef CONFIG_ADB_PMU
#include <linux/adb.h>
#include <linux/pmu.h>
#endif
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
......@@ -136,8 +138,25 @@ static struct fb_videomode defaultmode __initdata = {
/* Chip generations */
enum {
rage_128,
rage_128_pci,
rage_128_pro,
rage_M3
rage_128_pro_pci,
rage_M3,
rage_M3_pci,
rage_M4,
rage_128_ultra,
};
/* Must match above enum */
static const char *r128_family[] __devinitdata = {
"AGP",
"PCI",
"PRO AGP",
"PRO PCI",
"M3 AGP",
"M3 PCI",
"M4 AGP",
"Ultra AGP",
};
/*
......@@ -146,35 +165,105 @@ enum {
static int aty128_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void aty128_remove(struct pci_dev *pdev);
static int aty128_pci_suspend(struct pci_dev *pdev, u32 state);
static int aty128_pci_resume(struct pci_dev *pdev);
/* supported Rage128 chipsets */
static struct pci_device_id aty128_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_Rage128_PD,
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U3,
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_U1,
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
{ 0, }
};
......@@ -185,6 +274,8 @@ static struct pci_driver aty128fb_driver = {
.id_table = aty128_pci_tbl,
.probe = aty128_probe,
.remove = __devexit_p(aty128_remove),
.suspend = aty128_pci_suspend,
.resume = aty128_pci_resume,
};
/* packed BIOS settings */
......@@ -250,13 +341,6 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = {
.accel = FB_ACCEL_ATI_RAGE128,
};
#ifdef MODULE
static char *mode __initdata = NULL;
#ifdef CONFIG_MTRR
static int nomtrr __initdata = 0;
#endif /* CONFIG_MTRR */
#endif /* MODULE */
static char *mode_option __initdata = NULL;
#ifdef CONFIG_PPC_PMAC
......@@ -275,7 +359,7 @@ static int mtrr = 1;
/* PLL constants */
struct aty128_constants {
u32 dotclock;
u32 ref_clk;
u32 ppll_min;
u32 ppll_max;
u32 ref_divider;
......@@ -322,26 +406,20 @@ struct aty128fb_par {
#endif
int blitter_may_be_busy;
int fifo_slots; /* free slots in FIFO (64 max) */
#ifdef CONFIG_PMAC_PBOOK
unsigned char *save_framebuffer;
int pm_reg;
int crt_on, lcd_on;
struct pci_dev *pdev;
struct fb_info *next;
#endif
int asleep;
int lock_blank;
u8 red[32]; /* see aty128fb_setcolreg */
u8 green[64];
u8 blue[32];
u32 pseudo_palette[16]; /* used for TRUECOLOR */
};
#ifdef CONFIG_PMAC_PBOOK
int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier aty128_sleep_notifier = {
aty128_sleep_notify, SLEEP_LEVEL_VIDEO,
};
static struct fb_info *aty128_fb = NULL;
#endif
#define round_div(n, d) ((n+(d/2))/d)
......@@ -349,7 +427,6 @@ static struct fb_info *aty128_fb = NULL;
* Interface used by the world
*/
int aty128fb_init(void);
int aty128fb_setup(char *options);
static int aty128fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
......@@ -371,10 +448,10 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par);
static int aty128_decode_var(struct fb_var_screeninfo *var,
struct aty128fb_par *par);
#if !defined(CONFIG_PPC) && !defined(__sparc__)
#if 0
static void __init aty128_get_pllinfo(struct aty128fb_par *par,
void *bios);
static void __init *aty128_map_ROM(struct pci_dev *pdev);
static void __init *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom);
#endif
static void aty128_timings(struct aty128fb_par *par);
......@@ -386,6 +463,15 @@ static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
static void wait_for_idle(struct aty128fb_par *par);
static u32 depth_to_dst(u32 depth);
#define BIOS_IN8(v) (readb(bios + (v)))
#define BIOS_IN16(v) (readb(bios + (v)) | \
(readb(bios + (v) + 1) << 8))
#define BIOS_IN32(v) (readb(bios + (v)) | \
(readb(bios + (v) + 1) << 8) | \
(readb(bios + (v) + 2) << 16) | \
(readb(bios + (v) + 3) << 24))
static struct fb_ops aty128fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = aty128fb_check_var,
......@@ -395,15 +481,9 @@ static struct fb_ops aty128fb_ops = {
.fb_blank = aty128fb_blank,
.fb_ioctl = aty128fb_ioctl,
.fb_sync = aty128fb_sync,
#if 0
.fb_fillrect = aty128fb_fillrect,
.fb_copyarea = aty128fb_copyarea,
.fb_imageblit = aty128fb_imageblit,
#else
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
#endif
.fb_cursor = soft_cursor,
};
......@@ -422,40 +502,26 @@ static struct backlight_controller aty128_backlight_controller = {
* - endian conversions may possibly be avoided by
* using the other register aperture. TODO.
*/
static inline u32
_aty_ld_le32(volatile unsigned int regindex, const struct aty128fb_par *par)
static inline u32 _aty_ld_le32(volatile unsigned int regindex,
const struct aty128fb_par *par)
{
u32 val;
#if defined(__powerpc__)
asm("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b"(regindex), "r"(par->regbase));
#else
val = readl (par->regbase + regindex);
#endif
return val;
return readl (par->regbase + regindex);
}
static inline void
_aty_st_le32(volatile unsigned int regindex, u32 val,
static inline void _aty_st_le32(volatile unsigned int regindex, u32 val,
const struct aty128fb_par *par)
{
#if defined(__powerpc__)
asm("stwbrx %0,%1,%2;eieio" : : "r"(val), "b"(regindex),
"r"(par->regbase) : "memory");
#else
writel (val, par->regbase + regindex);
#endif
}
static inline u8
_aty_ld_8(unsigned int regindex, const struct aty128fb_par *par)
static inline u8 _aty_ld_8(unsigned int regindex,
const struct aty128fb_par *par)
{
return readb (par->regbase + regindex);
}
static inline void
_aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par)
static inline void _aty_st_8(unsigned int regindex, u8 val,
const struct aty128fb_par *par)
{
writeb (val, par->regbase + regindex);
}
......@@ -473,8 +539,7 @@ _aty_st_8(unsigned int regindex, u8 val, const struct aty128fb_par *par)
#define aty_st_pll(pll_index, val) _aty_st_pll(pll_index, val, par)
static u32
_aty_ld_pll(unsigned int pll_index,
static u32 _aty_ld_pll(unsigned int pll_index,
const struct aty128fb_par *par)
{
aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
......@@ -482,8 +547,7 @@ _aty_ld_pll(unsigned int pll_index,
}
static void
_aty_st_pll(unsigned int pll_index, u32 val,
static void _aty_st_pll(unsigned int pll_index, u32 val,
const struct aty128fb_par *par)
{
aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);
......@@ -492,15 +556,13 @@ _aty_st_pll(unsigned int pll_index, u32 val,
/* return true when the PLL has completed an atomic update */
static int
aty_pll_readupdate(const struct aty128fb_par *par)
static int aty_pll_readupdate(const struct aty128fb_par *par)
{
return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
}
static void
aty_pll_wait_readupdate(const struct aty128fb_par *par)
static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
{
unsigned long timeout = jiffies + HZ/100; // should be more than enough
int reset = 1;
......@@ -517,8 +579,7 @@ aty_pll_wait_readupdate(const struct aty128fb_par *par)
/* tell PLL to update */
static void
aty_pll_writeupdate(const struct aty128fb_par *par)
static void aty_pll_writeupdate(const struct aty128fb_par *par)
{
aty_pll_wait_readupdate(par);
......@@ -528,8 +589,7 @@ aty_pll_writeupdate(const struct aty128fb_par *par)
/* write to the scratch register to test r/w functionality */
static int __init
register_test(const struct aty128fb_par *par)
static int __init register_test(const struct aty128fb_par *par)
{
u32 val;
int flag = 0;
......@@ -552,8 +612,7 @@ register_test(const struct aty128fb_par *par)
/*
* Accelerator engine functions
*/
static void
do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
{
int i;
......@@ -568,8 +627,7 @@ do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
}
static void
wait_for_idle(struct aty128fb_par *par)
static void wait_for_idle(struct aty128fb_par *par)
{
int i;
......@@ -588,8 +646,7 @@ wait_for_idle(struct aty128fb_par *par)
}
static void
wait_for_fifo(u16 entries, struct aty128fb_par *par)
static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
{
if (par->fifo_slots < entries)
do_wait_for_fifo(64, par);
......@@ -597,8 +654,7 @@ wait_for_fifo(u16 entries, struct aty128fb_par *par)
}
static void
aty128_flush_pixel_cache(const struct aty128fb_par *par)
static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
{
int i;
u32 tmp;
......@@ -614,8 +670,7 @@ aty128_flush_pixel_cache(const struct aty128fb_par *par)
}
static void
aty128_reset_engine(const struct aty128fb_par *par)
static void aty128_reset_engine(const struct aty128fb_par *par)
{
u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
......@@ -643,8 +698,7 @@ aty128_reset_engine(const struct aty128fb_par *par)
}
static void
aty128_init_engine(struct aty128fb_par *par)
static void aty128_init_engine(struct aty128fb_par *par)
{
u32 pitch_value;
......@@ -712,8 +766,7 @@ aty128_init_engine(struct aty128fb_par *par)
/* convert depth values to their register representation */
static u32
depth_to_dst(u32 depth)
static u32 depth_to_dst(u32 depth)
{
if (depth <= 8)
return DST_8BPP;
......@@ -729,14 +782,246 @@ depth_to_dst(u32 depth)
return -EINVAL;
}
/*
* PLL informations retreival
*/
#ifndef __sparc__
static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
{
struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
iounmap(rom);
/* Release the ROM resource if we used it in the first place */
if (r->parent && r->flags & PCI_ROM_ADDRESS_ENABLE) {
release_resource(r);
r->flags &= ~PCI_ROM_ADDRESS_ENABLE;
r->end -= r->start;
r->start = 0;
}
/* This will disable and set address to unassigned */
pci_write_config_dword(dev, dev->rom_base_reg, 0);
}
static void * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
{
struct resource *r;
u16 dptr;
u8 rom_type;
void *bios;
/* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
unsigned int temp;
temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
temp &= 0x00ffffffu;
temp |= 0x04 << 24;
aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);
temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
/* no need to search for the ROM, just ask the card where it is. */
r = &dev->resource[PCI_ROM_RESOURCE];
/* assign the ROM an address if it doesn't have one */
if (r->parent == NULL)
pci_assign_resource(dev, PCI_ROM_RESOURCE);
/* enable if needed */
if (!(r->flags & PCI_ROM_ADDRESS_ENABLE)) {
pci_write_config_dword(dev, dev->rom_base_reg,
r->start | PCI_ROM_ADDRESS_ENABLE);
r->flags |= PCI_ROM_ADDRESS_ENABLE;
}
bios = ioremap(r->start, r->end - r->start + 1);
if (!bios) {
printk(KERN_ERR "aty128fb: ROM failed to map\n");
return NULL;
}
/* Very simple test to make sure it appeared */
if (BIOS_IN16(0) != 0xaa55) {
printk(KERN_ERR "aty128fb: Invalid ROM signature %x should be 0xaa55\n",
BIOS_IN16(0));
goto failed;
}
/* Look for the PCI data to check the ROM type */
dptr = BIOS_IN16(0x18);
/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM
* for now, until I've verified this works everywhere. The goal here is more
* to phase out Open Firmware images.
*
* Currently, we only look at the first PCI data, we could iteratre and deal with
* them all, and we should use fb_bios_start relative to start of image and not
* relative start of ROM, but so far, I never found a dual-image ATI card
*
* typedef struct {
* u32 signature; + 0x00
* u16 vendor; + 0x04
* u16 device; + 0x06
* u16 reserved_1; + 0x08
* u16 dlen; + 0x0a
* u8 drevision; + 0x0c
* u8 class_hi; + 0x0d
* u16 class_lo; + 0x0e
* u16 ilen; + 0x10
* u16 irevision; + 0x12
* u8 type; + 0x14
* u8 indicator; + 0x15
* u16 reserved_2; + 0x16
* } pci_data_t;
*/
if (BIOS_IN32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",
BIOS_IN32(dptr));
goto anyway;
}
rom_type = BIOS_IN8(dptr + 0x14);
switch(rom_type) {
case 0:
printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");
break;
case 1:
printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");
goto failed;
case 2:
printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");
goto failed;
default:
printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type);
goto failed;
}
anyway:
return bios;
failed:
aty128_unmap_ROM(dev, bios);
return NULL;
}
static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char *bios)
{
unsigned int bios_hdr;
unsigned int bios_pll;
bios_hdr = BIOS_IN16(0x48);
bios_pll = BIOS_IN16(bios_hdr + 0x30);
par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);
par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);
par->constants.xclk = BIOS_IN16(bios_pll + 0x08);
par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);
par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);
DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",
par->constants.ppll_max, par->constants.ppll_min,
par->constants.xclk, par->constants.ref_divider,
par->constants.ref_clk);
}
#ifdef __i386__
static void * __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
{
/* I simplified this code as we used to miss the signatures in
* a lot of case. It's now closer to XFree, we just don't check
* for signatures at all... Something better will have to be done
* if we end up having conflicts
*/
u32 segstart;
unsigned char *rom_base = NULL;
for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
rom_base = (char *)ioremap(segstart, 0x10000);
if (rom_base == NULL)
return NULL;
if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa))
break;
iounmap(rom_base);
rom_base = NULL;
}
return rom_base;
}
#endif /* __i386__ */
#endif /* ndef(__sparc__) */
/* fill in known card constants if pll_block is not available */
static void __init aty128_timings(struct aty128fb_par *par)
{
#ifdef CONFIG_PPC_OF
/* instead of a table lookup, assume OF has properly
* setup the PLL registers and use their values
* to set the XCLK values and reference divider values */
u32 x_mpll_ref_fb_div;
u32 xclk_cntl;
u32 Nx, M;
unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
#endif
if (!par->constants.ref_clk)
par->constants.ref_clk = 2950;
#ifdef CONFIG_PPC_OF
x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
M = x_mpll_ref_fb_div & 0x0000ff;
par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),
(M * PostDivSet[xclk_cntl]));
par->constants.ref_divider =
aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
#endif
if (!par->constants.ref_divider) {
par->constants.ref_divider = 0x3b;
aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
aty_pll_writeupdate(par);
}
aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
aty_pll_writeupdate(par);
/* from documentation */
if (!par->constants.ppll_min)
par->constants.ppll_min = 12500;
if (!par->constants.ppll_max)
par->constants.ppll_max = 25000; /* 23000 on some cards? */
if (!par->constants.xclk)
par->constants.xclk = 0x1d4d; /* same as mclk */
par->constants.fifo_width = 128;
par->constants.fifo_depth = 32;
switch (aty_ld_le32(MEM_CNTL) & 0x3) {
case 0:
par->mem = &sdr_128;
break;
case 1:
par->mem = &sdr_sgram;
break;
case 2:
par->mem = &ddr_sgram;
break;
default:
par->mem = &sdr_sgram;
}
}
/*
* CRTC programming
*/
/* Program the CRTC registers */
static void
aty128_set_crtc(const struct aty128_crtc *crtc,
static void aty128_set_crtc(const struct aty128_crtc *crtc,
const struct aty128fb_par *par)
{
aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
......@@ -752,8 +1037,7 @@ aty128_set_crtc(const struct aty128_crtc *crtc,
}
static int
aty128_var_to_crtc(const struct fb_var_screeninfo *var,
static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
struct aty128_crtc *crtc,
const struct aty128fb_par *par)
{
......@@ -881,8 +1165,7 @@ aty128_var_to_crtc(const struct fb_var_screeninfo *var,
}
static int
aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
{
/* fill in pixel info */
......@@ -945,8 +1228,7 @@ aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
}
static int
aty128_crtc_to_var(const struct aty128_crtc *crtc,
static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
struct fb_var_screeninfo *var)
{
u32 xres, yres, left, right, upper, lower, hslen, vslen, sync;
......@@ -1003,8 +1285,7 @@ aty128_crtc_to_var(const struct aty128_crtc *crtc,
}
#ifdef CONFIG_PMAC_PBOOK
static void
aty128_set_crt_enable(struct aty128fb_par *par, int on)
static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
{
if (on) {
aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON);
......@@ -1013,8 +1294,7 @@ aty128_set_crt_enable(struct aty128fb_par *par, int on)
aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);
}
static void
aty128_set_lcd_enable(struct aty128fb_par *par, int on)
static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
{
u32 reg;
......@@ -1039,10 +1319,9 @@ aty128_set_lcd_enable(struct aty128fb_par *par, int on)
aty_st_le32(LVDS_GEN_CNTL, reg);
}
}
#endif
#endif /* CONFIG_PMAC_PBOOK */
static void
aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
{
u32 div3;
......@@ -1081,8 +1360,7 @@ aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
}
static int
aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
const struct aty128fb_par *par)
{
const struct aty128_constants c = par->constants;
......@@ -1109,7 +1387,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
/* calculate feedback divider */
n = c.ref_divider * output_freq;
d = c.dotclock;
d = c.ref_clk;
pll->post_divider = post_dividers[i];
pll->feedback_divider = round_div(n, d);
......@@ -1124,8 +1402,7 @@ aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
}
static int
aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
static int aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
{
var->pixclock = 100000000 / pll->vclk;
......@@ -1133,8 +1410,7 @@ aty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var)
}
static void
aty128_set_fifo(const struct aty128_ddafifo *dsp,
static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
const struct aty128fb_par *par)
{
aty_st_le32(DDA_CONFIG, dsp->dda_config);
......@@ -1142,8 +1418,7 @@ aty128_set_fifo(const struct aty128_ddafifo *dsp,
}
static int
aty128_ddafifo(struct aty128_ddafifo *dsp,
static int aty128_ddafifo(struct aty128_ddafifo *dsp,
const struct aty128_pll *pll,
u32 depth,
const struct aty128fb_par *par)
......@@ -1203,8 +1478,7 @@ aty128_ddafifo(struct aty128_ddafifo *dsp,
/*
* This actually sets the video mode.
*/
static int
aty128fb_set_par(struct fb_info *info)
static int aty128fb_set_par(struct fb_info *info)
{
struct aty128fb_par *par = info->par;
u32 config;
......@@ -1276,8 +1550,7 @@ aty128fb_set_par(struct fb_info *info)
* encode/decode the User Defined Part of the Display
*/
static int
aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
static int aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
{
int err;
struct aty128_crtc crtc;
......@@ -1302,8 +1575,7 @@ aty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par)
}
static int
aty128_encode_var(struct fb_var_screeninfo *var,
static int aty128_encode_var(struct fb_var_screeninfo *var,
const struct aty128fb_par *par)
{
int err;
......@@ -1325,8 +1597,7 @@ aty128_encode_var(struct fb_var_screeninfo *var,
}
static int
aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct aty128fb_par par;
int err;
......@@ -1342,8 +1613,7 @@ aty128fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
/*
* Pan or Wrap the Display
*/
static int
aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
static int aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
{
struct aty128fb_par *par = fb->par;
u32 xoffset, yoffset;
......@@ -1376,8 +1646,7 @@ aty128fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
/*
* Helper function to store a single palette register
*/
static void
aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
struct aty128fb_par *par)
{
if (par->chip_gen == rage_M3) {
......@@ -1400,8 +1669,7 @@ aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
}
static int
aty128fb_sync(struct fb_info *info)
static int aty128fb_sync(struct fb_info *info)
{
struct aty128fb_par *par = info->par;
......@@ -1410,8 +1678,7 @@ aty128fb_sync(struct fb_info *info)
return 0;
}
int __init
aty128fb_setup(char *options)
int __init aty128fb_setup(char *options)
{
char *this_opt;
......@@ -1470,13 +1737,12 @@ aty128fb_setup(char *options)
* Initialisation
*/
static int __init
aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
struct fb_var_screeninfo var;
char video_card[25];
char video_card[DEVICE_NAME_SIZE];
u8 chip_rev;
u32 dac;
......@@ -1486,43 +1752,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Get the chip revision */
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
switch (pdev->device) {
case PCI_DEVICE_ID_ATI_RAGE128_RE:
strcpy(video_card, "Rage128 RE (PCI)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_RF:
strcpy(video_card, "Rage128 RF (AGP)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_RK:
strcpy(video_card, "Rage128 RK (PCI)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_RL:
strcpy(video_card, "Rage128 RL (AGP)");
break;
case PCI_DEVICE_ID_ATI_Rage128_PD:
strcpy(video_card, "Rage128 Pro PD (PCI)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_PF:
strcpy(video_card, "Rage128 Pro PF (AGP)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_PR:
strcpy(video_card, "Rage128 Pro PR (PCI)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_U3:
strcpy(video_card, "Rage128 Pro TR (AGP)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_U1:
strcpy(video_card, "Rage128 Pro TF (AGP)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_LE:
strcpy(video_card, "Rage Mobility M3 (PCI)");
break;
case PCI_DEVICE_ID_ATI_RAGE128_LF:
strcpy(video_card, "Rage Mobility M3 (AGP)");
break;
default:
return -ENODEV;
}
strcpy(video_card, "Rage128 XX ");
video_card[8] = ent->device >> 8;
video_card[9] = ent->device & 0xFF;
/* range check to make sure */
if (ent->driver_data < (sizeof(r128_family)/sizeof(char *)))
strncat(video_card, r128_family[ent->driver_data], sizeof(video_card));
printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
......@@ -1575,7 +1811,11 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
if (machine_is_compatible("PowerBook3,2"))
default_vmode = VMODE_1152_768_60;
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
if (default_cmode > 16)
default_cmode = CMODE_32;
else if (default_cmode > 8)
default_cmode = CMODE_16;
else
default_cmode = CMODE_8;
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
......@@ -1584,8 +1824,9 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
} else
#endif /* CONFIG_PPC_PMAC */
{
if (fb_find_mode(&var, info, mode_option, NULL, 0,
&defaultmode, 8) == 0)
if (mode_option)
if (fb_find_mode(&var, info, mode_option, NULL,
0, &defaultmode, 8) == 0)
var = default_var;
}
......@@ -1623,15 +1864,11 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
if (par->chip_gen == rage_M3)
register_backlight_controller(&aty128_backlight_controller, par, "ati");
#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PMAC_PBOOK
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (aty128_fb == NULL) {
/* XXX can only put one chip to sleep */
aty128_fb = info;
} else
printk(KERN_WARNING "aty128fb: can only sleep one Rage 128\n");
par->pdev = pdev;
#endif
par->asleep = 0;
par->lock_blank = 0;
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card);
......@@ -1641,14 +1878,13 @@ aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PCI
/* register a card ++ajoshi */
static int __init
aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned long fb_addr, reg_addr;
struct aty128fb_par *par;
struct fb_info *info;
int err, size;
#if !defined(CONFIG_PPC) && !defined(__sparc__)
int err;
#ifndef __sparc__
void *bios = NULL;
#endif
......@@ -1675,17 +1911,14 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* We have the resources. Now virtualize them */
size = sizeof(struct fb_info) + sizeof(struct aty128fb_par);
if (!(info = kmalloc(size, GFP_ATOMIC))) {
info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
if (info == NULL) {
printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
goto err_free_mmio;
}
memset(info, 0, size);
par = info->par;
par = (struct aty128fb_par *)(info + 1);
info->pseudo_palette = par->pseudo_palette;
info->par = par;
info->fix = aty128fb_fix;
/* Virtualize mmio region */
......@@ -1715,16 +1948,21 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out;
}
#if !defined(CONFIG_PPC) && !defined(__sparc__)
if (!(bios = aty128_map_ROM(pdev)))
#ifndef __sparc__
bios = aty128_map_ROM(par, pdev);
#ifdef __i386__
if (bios == NULL)
bios = aty128_find_mem_vbios(par, pdev);
#endif
if (bios == NULL)
printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
else {
printk(KERN_INFO "aty128fb: Rage128 BIOS located at %lx\n",
pdev->resource[PCI_ROM_RESOURCE].start);
printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
aty128_get_pllinfo(par, bios);
aty128_unmap_ROM(pdev, bios);
}
#endif
#endif /* __sparc__ */
aty128_timings(par);
pci_set_drvdata(pdev, info);
......@@ -1747,7 +1985,7 @@ aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_unmap_out:
iounmap(par->regbase);
err_free_info:
kfree(info);
framebuffer_release(info);
err_free_mmio:
release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
......@@ -1780,170 +2018,23 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
pci_resource_len(pdev, 1));
release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
#ifdef CONFIG_PMAC_PBOOK
if (info == aty128_fb)
aty128_fb = NULL;
#endif
kfree(info);
framebuffer_release(info);
}
#endif /* CONFIG_PCI */
/* PPC and Sparc cannot read video ROM */
#if !defined(CONFIG_PPC) && !defined(__sparc__)
static void * __init aty128_map_ROM(struct pci_dev *dev)
{
// If this is a primary card, there is a shadow copy of the
// ROM somewhere in the first meg. We will just ignore the copy
// and use the ROM directly.
// no need to search for the ROM, just ask the card where it is.
struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
unsigned char *addr;
// assign the ROM an address if it doesn't have one
if (r->start == 0)
pci_assign_resource(dev, PCI_ROM_RESOURCE);
// enable if needed
if (!(r->flags & PCI_ROM_ADDRESS_ENABLE))
pci_write_config_dword(dev, dev->rom_base_reg, r->start | PCI_ROM_ADDRESS_ENABLE);
addr = ioremap(r->start, r->end - r->start + 1);
// Very simple test to make sure it appeared
if (addr && (*addr != 0x55)) {
printk("aty128fb: Invalid ROM signature %x\n", *addr);
iounmap(addr);
return NULL;
}
return (void *)addr;
}
static void __init aty128_unmap_ROM(struct pci_dev *dev, void * rom)
{
// leave it disabled and unassigned
struct resource *r = &dev->resource[PCI_ROM_RESOURCE];
iounmap(rom);
r->flags &= !PCI_ROM_ADDRESS_ENABLE;
r->end -= r->start;
r->start = 0;
pci_write_config_dword(dev, dev->rom_base_reg, 0);
}
static void __init
aty128_get_pllinfo(struct aty128fb_par *par, void *bios)
{
void *bios_header;
void *header_ptr;
u16 bios_header_offset, pll_info_offset;
PLL_BLOCK pll;
bios_header = (char *)bios + 0x48L;
header_ptr = bios_header;
bios_header_offset = readw(header_ptr);
bios_header = (char *)bios + bios_header_offset;
bios_header += 0x30;
header_ptr = bios_header;
pll_info_offset = readw(header_ptr);
header_ptr = (char *)bios + pll_info_offset;
memcpy_fromio(&pll, header_ptr, 50);
par->constants.ppll_max = pll.PCLK_max_freq;
par->constants.ppll_min = pll.PCLK_min_freq;
par->constants.xclk = (u32)pll.XCLK;
par->constants.ref_divider = (u32)pll.PCLK_ref_divider;
par->constants.dotclock = (u32)pll.PCLK_ref_freq;
DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n",
par->constants.ppll_max, par->constants.ppll_min,
par->constants.xclk, par->constants.ref_divider,
par->constants.dotclock);
}
#endif /* !CONFIG_PPC */
/* fill in known card constants if pll_block is not available */
static void __init
aty128_timings(struct aty128fb_par *par)
{
#ifdef CONFIG_PPC_OF
/* instead of a table lookup, assume OF has properly
* setup the PLL registers and use their values
* to set the XCLK values and reference divider values */
u32 x_mpll_ref_fb_div;
u32 xclk_cntl;
u32 Nx, M;
unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
#endif
if (!par->constants.dotclock)
par->constants.dotclock = 2950;
#ifdef CONFIG_PPC_OF
x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
M = x_mpll_ref_fb_div & 0x0000ff;
par->constants.xclk = round_div((2 * Nx * par->constants.dotclock),
(M * PostDivSet[xclk_cntl]));
par->constants.ref_divider =
aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
#endif
if (!par->constants.ref_divider) {
par->constants.ref_divider = 0x3b;
aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
aty_pll_writeupdate(par);
}
aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
aty_pll_writeupdate(par);
/* from documentation */
if (!par->constants.ppll_min)
par->constants.ppll_min = 12500;
if (!par->constants.ppll_max)
par->constants.ppll_max = 25000; /* 23000 on some cards? */
if (!par->constants.xclk)
par->constants.xclk = 0x1d4d; /* same as mclk */
par->constants.fifo_width = 128;
par->constants.fifo_depth = 32;
switch (aty_ld_le32(MEM_CNTL) & 0x3) {
case 0:
par->mem = &sdr_128;
break;
case 1:
par->mem = &sdr_sgram;
break;
case 2:
par->mem = &ddr_sgram;
break;
default:
par->mem = &sdr_sgram;
}
}
/*
* Blank the display.
*/
static int
aty128fb_blank(int blank, struct fb_info *fb)
static int aty128fb_blank(int blank, struct fb_info *fb)
{
struct aty128fb_par *par = fb->par;
u8 state = 0;
if (par->lock_blank || par->asleep)
return 0;
#ifdef CONFIG_PMAC_BACKLIGHT
if ((_machine == _MACH_Pmac) && blank)
set_backlight_enable(0);
......@@ -1976,8 +2067,7 @@ aty128fb_blank(int blank, struct fb_info *fb)
* rounded down to the hardware's capabilities (according to the
* entries in the var structure). Return != 0 for invalid regno.
*/
static int
aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
struct aty128fb_par *par = info->par;
......@@ -2041,9 +2131,9 @@ aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
#define ATY_MIRROR_CRT_ON 0x00000002
/* out param: u32* backlight value: 0 to 15 */
#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32*)
#define FBIO_ATY128_GET_MIRROR _IOR('@', 1, __u32)
/* in param: u32* backlight value: 0 to 15 */
#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32*)
#define FBIO_ATY128_SET_MIRROR _IOW('@', 2, __u32)
static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, struct fb_info *info)
......@@ -2091,8 +2181,7 @@ static int backlight_conv[] = {
/* That one prevents proper CRT output with LCD off */
#undef BACKLIGHT_DAC_OFF
static int
aty128_set_backlight_enable(int on, int level, void *data)
static int aty128_set_backlight_enable(int on, int level, void *data)
{
struct aty128fb_par *par = data;
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
......@@ -2139,8 +2228,7 @@ aty128_set_backlight_enable(int on, int level, void *data)
return 0;
}
static int
aty128_set_backlight_level(int level, void* data)
static int aty128_set_backlight_level(int level, void* data)
{
return aty128_set_backlight_enable(1, level, data);
}
......@@ -2151,8 +2239,7 @@ aty128_set_backlight_level(int level, void* data)
* Accelerated functions
*/
static inline void
aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
static inline void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
u_int width, u_int height,
struct fb_info_aty128 *par)
{
......@@ -2196,8 +2283,7 @@ aty128_rectcopy(int srcx, int srcy, int dstx, int dsty,
* Text mode accelerated functions
*/
static void
fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
sx *= fontwidth(p);
......@@ -2212,9 +2298,7 @@ fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx,
}
#endif /* 0 */
#ifdef CONFIG_PMAC_PBOOK
static void
aty128_set_suspend(struct aty128fb_par *par, int suspend)
static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
{
u32 pmgt;
u16 pwr_command;
......@@ -2257,95 +2341,122 @@ aty128_set_suspend(struct aty128fb_par *par, int suspend)
}
}
/*
* Save the contents of the frame buffer when we go to sleep,
* and restore it when we wake up again.
*/
int
aty128_sleep_notify(struct pmu_sleep_notifier *self, int when)
static int aty128_pci_suspend(struct pci_dev *pdev, u32 state)
{
int nb;
struct fb_info *info = aty128_fb;
struct aty128fb_par *par;
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
if (info == NULL)
return PBOOK_SLEEP_OK;
par = info->par;
nb = info->var.yres * info->fix.line_length;
/* We don't do anything but D2, for now we return 0, but
* we may want to change that. How do we know if the BIOS
* can properly take care of D3 ? Also, with swsusp, we
* know we'll be rebooted, ...
*/
#ifdef CONFIG_PPC_PMAC
/* HACK ALERT ! Once I find a proper way to say to each driver
* individually what will happen with it's PCI slot, I'll change
* that. On laptops, the AGP slot is just unclocked, so D2 is
* expected, while on desktops, the card is powered off
*/
if (state >= 3)
state = 2;
#endif /* CONFIG_PPC_PMAC */
switch (when) {
case PBOOK_SLEEP_REQUEST:
par->save_framebuffer = vmalloc(nb);
if (par->save_framebuffer == NULL)
return PBOOK_SLEEP_REFUSE;
break;
case PBOOK_SLEEP_REJECT:
if (par->save_framebuffer) {
vfree(par->save_framebuffer);
par->save_framebuffer = 0;
}
break;
case PBOOK_SLEEP_NOW:
if (state != 2 || state == pdev->dev.power_state)
return 0;
printk(KERN_DEBUG "aty128fb: suspending...\n");
acquire_console_sem();
fb_set_suspend(info, 1);
/* Make sure engine is reset */
wait_for_idle(par);
aty128_reset_engine(par);
wait_for_idle(par);
/* Backup fb content */
if (par->save_framebuffer)
memcpy_fromio(par->save_framebuffer,
info->screen_base, nb);
/* Blank display and LCD */
aty128fb_blank(VESA_POWERDOWN, info);
/* Sleep the chip */
/* Sleep */
par->asleep = 1;
par->lock_blank = 1;
/* We need a way to make sure the fbdev layer will _not_ touch the
* framebuffer before we put the chip to suspend state. On 2.4, I
* used dummy fb ops, 2.5 need proper support for this at the
* fbdev level
*/
if (state == 2)
aty128_set_suspend(par, 1);
break;
case PBOOK_WAKE:
/* Wake the chip */
release_console_sem();
pdev->dev.power_state = state;
return 0;
}
static int aty128_pci_resume(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
if (pdev->dev.power_state == 0)
return 0;
acquire_console_sem();
/* Wakeup chip */
if (pdev->dev.power_state == 2)
aty128_set_suspend(par, 0);
par->asleep = 0;
/* Restore display & engine */
aty128_reset_engine(par);
wait_for_idle(par);
aty128fb_set_par(info);
fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, 1, info);
/* Restore fb content */
if (par->save_framebuffer) {
memcpy_toio(info->screen_base,
par->save_framebuffer, nb);
vfree(par->save_framebuffer);
par->save_framebuffer = 0;
}
/* Refresh */
fb_set_suspend(info, 0);
/* Unblank */
par->lock_blank = 0;
aty128fb_blank(0, info);
break;
}
return PBOOK_SLEEP_OK;
release_console_sem();
pdev->dev.power_state = 0;
printk(KERN_DEBUG "aty128fb: resumed !\n");
return 0;
}
#endif /* CONFIG_PMAC_PBOOK */
int __init aty128fb_init(void)
{
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&aty128_sleep_notifier);
#endif
return pci_module_init(&aty128fb_driver);
}
static void __exit aty128fb_exit(void)
{
#ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&aty128_sleep_notifier);
#endif
pci_unregister_driver(&aty128fb_driver);
}
#ifdef MODULE
module_init(aty128fb_init);
module_exit(aty128fb_exit);
MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
MODULE_LICENSE("GPL");
MODULE_PARM(mode, "s");
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
#ifdef CONFIG_MTRR
MODULE_PARM(nomtrr, "i");
MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
module_param_named(nomtrr, mtrr, invbool, 0);
MODULE_PARM_DESC(mtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
#endif
#endif
......@@ -28,7 +28,7 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
struct fb_fillrect modded;
int vxres, vyres;
if (rinfo->asleep)
if (info->state != FBINFO_STATE_RUNNING)
return;
if (radeon_accel_disabled()) {
cfb_fillrect(info, region);
......@@ -81,7 +81,7 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
modded.width = area->width;
modded.height = area->height;
if (rinfo->asleep)
if (info->state != FBINFO_STATE_RUNNING)
return;
if (radeon_accel_disabled()) {
cfb_copyarea(info, area);
......@@ -108,7 +108,7 @@ void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep)
if (info->state != FBINFO_STATE_RUNNING)
return;
radeon_engine_idle();
......@@ -119,7 +119,7 @@ int radeonfb_sync(struct fb_info *info)
{
struct radeonfb_info *rinfo = info->par;
if (rinfo->asleep)
if (info->state != FBINFO_STATE_RUNNING)
return 0;
radeon_engine_idle();
......
......@@ -566,8 +566,9 @@ static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo)
break;
}
do_div(vclk, 1000);
xtal = (xtal * denom) / num;
vclk *= denom;
do_div(vclk, 1000 * num);
xtal = vclk;
if ((xtal > 26900) && (xtal < 27100))
xtal = 2700;
......
......@@ -346,6 +346,9 @@ void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
int dst_idx = 0, src_idx = 0, rev_copy = 0;
unsigned long *dst = NULL, *src = NULL;
if (p->state != FBINFO_STATE_RUNNING)
return;
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
......
......@@ -367,6 +367,9 @@ void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
unsigned long *dst;
int dst_idx, left;
if (p->state != FBINFO_STATE_RUNNING)
return;
/* We want rotation but lack hardware to do it for us. */
if (!p->fbops->fb_rotate && p->var.rotate) {
}
......
......@@ -275,6 +275,9 @@ void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
int x2, y2, vxres, vyres;
u8 *dst1;
if (p->state != FBINFO_STATE_RUNNING)
return;
vxres = p->var.xres_virtual;
vyres = p->var.yres_virtual;
/*
......
......@@ -195,11 +195,13 @@ static void fb_flashcursor(void *private)
{
struct fb_info *info = (struct fb_info *) private;
/* Test to see if the cursor is erased but still on */
if (!info || (info->cursor.rop == ROP_COPY))
if (!info || info->state != FBINFO_STATE_RUNNING ||
info->cursor.rop == ROP_COPY)
return;
acquire_console_sem();
info->cursor.enable ^= 1;
info->fbops->fb_cursor(info, &info->cursor);
release_console_sem();
}
#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)
......@@ -226,8 +228,7 @@ static void cursor_timer_handler(unsigned long dev_addr)
struct fb_info *info = (struct fb_info *) dev_addr;
schedule_work(&info->queue);
cursor_timer.expires = jiffies + HZ / 5;
add_timer(&cursor_timer);
mod_timer(&cursor_timer, jiffies + HZ/5);
}
int __init fb_console_setup(char *this_opt)
......@@ -353,8 +354,6 @@ static void putcs_unaligned(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
atomic_dec(&info->pixmap.count);
smp_mb__after_atomic_dec();
}
}
......@@ -393,8 +392,6 @@ static void putcs_aligned(struct vc_data *vc, struct fb_info *info,
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
atomic_dec(&info->pixmap.count);
smp_mb__after_atomic_dec();
}
}
......@@ -465,8 +462,6 @@ static void accel_putc(struct vc_data *vc, struct fb_info *info,
move_buf_aligned(info, dst, src, pitch, width, image.height);
info->fbops->fb_imageblit(info, &image);
atomic_dec(&info->pixmap.count);
smp_mb__after_atomic_dec();
}
void accel_putcs(struct vc_data *vc, struct fb_info *info,
......@@ -676,7 +671,7 @@ static const char *fbcon_startup(void)
if (!info->queue.func) {
INIT_WORK(&info->queue, fb_flashcursor, info);
cursor_timer.expires = jiffies + HZ / 50;
cursor_timer.expires = jiffies + HZ / 5;
cursor_timer.data = (unsigned long ) info;
add_timer(&cursor_timer);
}
......@@ -944,6 +939,8 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
if (!info->fbops->fb_blank && console_blanked)
return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (!height || !width)
return;
......@@ -968,6 +965,8 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
if (!info->fbops->fb_blank && console_blanked)
return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return;
......@@ -983,6 +982,8 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
if (!info->fbops->fb_blank && console_blanked)
return;
if (info->state != FBINFO_STATE_RUNNING)
return;
if (vt_cons[vc->vc_num]->vc_mode != KD_TEXT)
return;
......@@ -2265,6 +2266,39 @@ static int fbcon_set_origin(struct vc_data *vc)
return 0;
}
static void fbcon_suspended(struct fb_info *info)
{
/* Clear cursor, restore saved data */
info->cursor.enable = 0;
info->fbops->fb_cursor(info, &info->cursor);
}
static void fbcon_resumed(struct fb_info *info)
{
struct vc_data *vc;
if (info->currcon < 0)
return;
vc = vc_cons[info->currcon].d;
update_screen(vc->vc_num);
}
static int fbcon_event_notify(struct notifier_block *self,
unsigned long action, void *data)
{
struct fb_info *info = (struct fb_info *) data;
switch(action) {
case FB_EVENT_SUSPEND:
fbcon_suspended(info);
break;
case FB_EVENT_RESUME:
fbcon_resumed(info);
break;
}
return 0;
}
/*
* The console `switch' structure for the frame buffer based console
*/
......@@ -2291,16 +2325,35 @@ const struct consw fb_con = {
.con_resize = fbcon_resize,
};
static struct notifier_block fbcon_event_notifer = {
.notifier_call = fbcon_event_notify,
};
static int fbcon_event_notifier_registered;
int __init fb_console_init(void)
{
if (!num_registered_fb)
return -ENODEV;
take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default);
acquire_console_sem();
if (!fbcon_event_notifier_registered) {
fb_register_client(&fbcon_event_notifer);
fbcon_event_notifier_registered = 1;
}
release_console_sem();
return 0;
}
void __exit fb_console_exit(void)
{
acquire_console_sem();
if (fbcon_event_notifier_registered) {
fb_unregister_client(&fbcon_event_notifer);
fbcon_event_notifier_registered = 0;
}
release_console_sem();
give_up_console(&fb_con);
}
......
......@@ -27,6 +27,7 @@
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
#include <linux/console.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
......@@ -222,6 +223,9 @@ static struct {
#ifdef CONFIG_FB_RADEON
{ "radeonfb", radeonfb_init, radeonfb_setup },
#endif
#ifdef CONFIG_FB_RADEON_OLD
{ "radeonfb_old", radeonfb_init, radeonfb_setup },
#endif
#ifdef CONFIG_FB_CONTROL
{ "controlfb", control_init, control_setup },
#endif
......@@ -395,6 +399,7 @@ extern const char *global_mode_option;
static initcall_t pref_init_funcs[FB_MAX];
static int num_pref_init_funcs __initdata = 0;
static struct notifier_block *fb_notifier_list;
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
......@@ -463,23 +468,32 @@ void move_buf_unaligned(struct fb_info *info, u8 *dst, u8 *src, u32 d_pitch,
*/
u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
{
u32 align = info->pixmap.buf_align - 1;
u32 offset, count = 1000;
struct fb_pixmap *buf = &info->pixmap;
u32 align = buf->buf_align - 1, offset;
spin_lock(&info->pixmap.lock);
offset = info->pixmap.offset + align;
/* If IO mapped, we need to sync before access, no sharing of
* the pixmap is done
*/
if (buf->flags & FB_PIXMAP_IO) {
if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
info->fbops->fb_sync(info);
return 0;
}
/* See if we fit in the remaining pixmap space */
offset = buf->offset + align;
offset &= ~align;
if (offset + size > info->pixmap.size) {
while (atomic_read(&info->pixmap.count) && count--);
if (info->fbops->fb_sync &&
info->pixmap.flags & FB_PIXMAP_SYNC)
if (offset + size > buf->size) {
/* We do not fit. In order to be able to re-use the buffer,
* we must ensure no asynchronous DMA'ing or whatever operation
* is in progress, we sync for that.
*/
if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC))
info->fbops->fb_sync(info);
offset = 0;
}
info->pixmap.offset = offset + size;
atomic_inc(&info->pixmap.count);
smp_mb__after_atomic_inc();
spin_unlock(&info->pixmap.lock);
buf->offset = offset + size;
return offset;
}
......@@ -685,8 +699,8 @@ int fb_show_logo(struct fb_info *info)
struct fb_image image;
int x;
/* Return if the frame buffer is not mapped */
if (fb_logo.logo == NULL)
/* Return if the frame buffer is not mapped or suspended */
if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
return 0;
image.depth = fb_logo.depth;
......@@ -732,8 +746,6 @@ int fb_show_logo(struct fb_info *info)
x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) {
image.dx = x;
info->fbops->fb_imageblit(info, &image);
//atomic_dec(&info->pixmap.count);
//smp_mb__after_atomic_dec();
}
if (palette != NULL)
......@@ -780,6 +792,9 @@ fb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
if (!info || ! info->screen_base)
return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_read)
return info->fbops->fb_read(file, buf, count, ppos);
......@@ -815,6 +830,9 @@ fb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (!info || !info->screen_base)
return -ENODEV;
if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;
if (info->fbops->fb_write)
return info->fbops->fb_write(file, buf, count, ppos);
......@@ -941,6 +959,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_pan_display(info, &info->var);
fb_set_cmap(&info->cmap, 1, info);
notifier_call_chain(&fb_notifier_list, FB_EVENT_MODE_CHANGE, info);
}
}
return 0;
......@@ -979,7 +999,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct fb_con2fbmap con2fb;
#endif
struct fb_cmap cmap;
int i;
int i, rc;
if (!fb)
return -ENODEV;
......@@ -990,7 +1010,9 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case FBIOPUT_VSCREENINFO:
if (copy_from_user(&var, (void *) arg, sizeof(var)))
return -EFAULT;
acquire_console_sem();
i = fb_set_var(info, &var);
release_console_sem();
if (i) return i;
if (copy_to_user((void *) arg, &var, sizeof(var)))
return -EFAULT;
......@@ -1009,13 +1031,19 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case FBIOPAN_DISPLAY:
if (copy_from_user(&var, (void *) arg, sizeof(var)))
return -EFAULT;
if ((i = fb_pan_display(info, &var)))
acquire_console_sem();
i = fb_pan_display(info, &var);
release_console_sem();
if (i)
return i;
if (copy_to_user((void *) arg, &var, sizeof(var)))
return -EFAULT;
return 0;
case FBIO_CURSOR:
return (fb_cursor(info, (struct fb_cursor *) arg));
acquire_console_sem();
rc = fb_cursor(info, (struct fb_cursor *) arg);
release_console_sem();
return rc;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
case FBIOGET_CON2FBMAP:
if (copy_from_user(&con2fb, (void *)arg, sizeof(con2fb)))
......@@ -1045,7 +1073,10 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return 0;
#endif /* CONFIG_FRAMEBUFFER_CONSOLE */
case FBIOBLANK:
return fb_blank(info, arg);
acquire_console_sem();
i = fb_blank(info, arg);
release_console_sem();
return i;
default:
if (fb->fb_ioctl == NULL)
return -EINVAL;
......@@ -1242,7 +1273,6 @@ register_framebuffer(struct fb_info *fb_info)
fb_info->pixmap.outbuf = sys_outbuf;
if (fb_info->pixmap.inbuf == NULL)
fb_info->pixmap.inbuf = sys_inbuf;
spin_lock_init(&fb_info->pixmap.lock);
registered_fb[i] = fb_info;
......@@ -1279,8 +1309,42 @@ unregister_framebuffer(struct fb_info *fb_info)
return 0;
}
/**
* fb_register_client - register a client notifier
* @nb: notifier block to callback on events
*/
int fb_register_client(struct notifier_block *nb)
{
return notifier_chain_register(&fb_notifier_list, nb);
}
/**
* fb_unregister_client - unregister a client notifier
* @nb: notifier block to callback on events
*/
int fb_unregister_client(struct notifier_block *nb)
{
return notifier_chain_unregister(&fb_notifier_list, nb);
}
/**
* fb_set_suspend - low level driver signals suspend
* @info: framebuffer affected
* @state: 0 = resuming, !=0 = suspending
*
* This is meant to be used by low level drivers to
* signal suspend/resume to the core & clients.
* It must be called with the console semaphore held
*/
void fb_set_suspend(struct fb_info *info, int state)
{
if (state) {
notifier_call_chain(&fb_notifier_list, FB_EVENT_SUSPEND, info);
info->state = FBINFO_STATE_SUSPENDED;
} else {
info->state = FBINFO_STATE_RUNNING;
notifier_call_chain(&fb_notifier_list, FB_EVENT_RESUME, info);
}
}
/**
......@@ -1397,5 +1461,7 @@ EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(move_buf_unaligned);
EXPORT_SYMBOL(move_buf_aligned);
EXPORT_SYMBOL(fb_set_suspend);
EXPORT_SYMBOL(fb_register_client);
EXPORT_SYMBOL(fb_unregister_client);
MODULE_LICENSE("GPL");
......@@ -1615,8 +1615,9 @@ static int __devinit riva_set_fbinfo(struct fb_info *info)
}
#ifdef CONFIG_PPC_OF
static int riva_get_EDID_OF(struct riva_par *par, struct pci_dev *pd)
static int riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
{
struct riva_par *par = (struct riva_par *) info->par;
struct device_node *dp;
unsigned char *pedid = NULL;
......
......@@ -48,6 +48,9 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
info->cursor.image.depth = cursor->image.depth;
}
if (info->state != FBINFO_STATE_RUNNING)
return 0;
s_pitch = (info->cursor.image.width + 7) >> 3;
dsize = s_pitch * info->cursor.image.height;
d_pitch = (s_pitch + scan_align) & ~scan_align;
......@@ -74,8 +77,6 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
info->cursor.image.data = dst;
info->fbops->fb_imageblit(info, &info->cursor.image);
atomic_dec(&info->pixmap.count);
smp_mb__after_atomic_dec();
return 0;
}
......
......@@ -114,7 +114,6 @@ extern void ia64_mca_ucmc_handler(void);
extern void ia64_monarch_init_handler(void);
extern void ia64_slave_init_handler(void);
extern void ia64_mca_cmc_vector_setup(void);
extern int ia64_mca_check_errors(void);
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_IA64_MCA_H */
......@@ -339,6 +339,24 @@ struct fb_info;
struct device;
struct file;
/*
* Register/unregister for framebuffer events
*/
/* The resolution of the passed in fb_info about to change */
#define FB_EVENT_MODE_CHANGE 0x01
/* The display on this fb_info is beeing suspended, no access to the
* framebuffer is allowed any more after that call returns
*/
#define FB_EVENT_SUSPEND 0x02
/* The display on this fb_info was resumed, you can restore the display
* if you own it
*/
#define FB_EVENT_RESUME 0x03
extern int fb_register_client(struct notifier_block *nb);
extern int fb_unregister_client(struct notifier_block *nb);
/*
* Pixmap structure definition
*
......@@ -363,8 +381,6 @@ struct fb_pixmap {
/* access methods */
void (*outbuf)(u8 *dst, u8 *addr, unsigned int size);
u8 (*inbuf) (u8 *addr);
spinlock_t lock; /* spinlock */
atomic_t count;
};
/*
......@@ -449,6 +465,9 @@ struct fb_info {
struct vc_data *display_fg; /* Console visible on this display */
int currcon; /* Current VC. */
void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state; /* Hardware state i.e suspend */
/* From here on everything is device dependent */
void *par;
};
......
......@@ -216,28 +216,37 @@
/* Rage128 GL */
#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245
#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246
#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x534b
#define PCI_DEVICE_ID_ATI_RAGE128_RH 0x534c
#define PCI_DEVICE_ID_ATI_RAGE128_RI 0x534d
#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247
/* Rage128 VR */
#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b
#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c
#define PCI_DEVICE_ID_ATI_RAGE128_RM 0x5345
#define PCI_DEVICE_ID_ATI_RAGE128_RN 0x5346
#define PCI_DEVICE_ID_ATI_RAGE128_RO 0x5347
#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345
#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346
#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347
#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348
#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b
#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c
#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d
#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e
/* Rage128 Ultra */
#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446
#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c
#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452
#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453
#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454
#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455
/* Rage128 M3 */
#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45
#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46
/* Rage128 Pro Ultra */
#define PCI_DEVICE_ID_ATI_RAGE128_U1 0x5446
#define PCI_DEVICE_ID_ATI_RAGE128_U2 0x544C
#define PCI_DEVICE_ID_ATI_RAGE128_U3 0x5452
/* Rage128 M4 */
#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46
#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c
/* Rage128 Pro GL */
#define PCI_DEVICE_ID_ATI_Rage128_PA 0x5041
#define PCI_DEVICE_ID_ATI_Rage128_PB 0x5042
#define PCI_DEVICE_ID_ATI_Rage128_PC 0x5043
#define PCI_DEVICE_ID_ATI_Rage128_PD 0x5044
#define PCI_DEVICE_ID_ATI_Rage128_PE 0x5045
#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041
#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042
#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043
#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044
#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045
#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046
/* Rage128 Pro VR */
#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047
......
......@@ -416,4 +416,7 @@
#define PMI_PMSCR_REG 0x60
/* used by ATI bug fix for hardware ROM */
#define RAGE128_MPP_TB_CONFIG 0x01c0
#endif /* REG_RAGE128_H */
......@@ -97,10 +97,16 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
rfcomm_dlc_unlock(dlc);
rfcomm_dlc_put(dlc);
/* Refcount should only hit zero when called from rfcomm_dev_del()
which will have taken us off the list. Everything else are
refcounting bugs. */
BUG_ON(!list_empty(&dev->list));
kfree(dev);
/* It's safe to call module_put() here because socket still
holds refference to this module. */
holds reference to this module. */
module_put(THIS_MODULE);
}
......@@ -111,6 +117,13 @@ static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
{
/* The reason this isn't actually a race, as you no
doubt have a little voice screaming at you in your
head, is that the refcount should never actually
reach zero unless the device has already been taken
off the list, in rfcomm_dev_del(). And if that's not
true, we'll hit the BUG() in rfcomm_dev_destruct()
anyway. */
if (atomic_dec_and_test(&dev->refcnt))
rfcomm_dev_destruct(dev);
}
......@@ -134,10 +147,13 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
struct rfcomm_dev *dev;
read_lock(&rfcomm_dev_lock);
dev = __rfcomm_dev_get(id);
if (dev)
rfcomm_dev_hold(dev);
read_unlock(&rfcomm_dev_lock);
if (dev) rfcomm_dev_hold(dev);
return dev;
}
......@@ -214,8 +230,9 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
rfcomm_dlc_unlock(dlc);
/* It's safe to call __module_get() here because socket already
holds refference to this module. */
holds reference to this module. */
__module_get(THIS_MODULE);
out:
write_unlock_bh(&rfcomm_dev_lock);
......@@ -486,7 +503,8 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
rfcomm_dev_del(dev);
/* We have to drop DLC lock here, otherwise
* rfcomm_dev_put() will dead lock if it's the last refference */
rfcomm_dev_put() will dead lock if it's
the last reference. */
rfcomm_dlc_unlock(dlc);
rfcomm_dev_put(dev);
rfcomm_dlc_lock(dlc);
......@@ -541,6 +559,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
BT_DBG("tty %p id %d", tty, id);
/* We don't leak this refcount. For reasons which are not entirely
clear, the TTY layer will call our ->close() method even if the
open fails. We decrease the refcount there, and decreasing it
here too would cause breakage. */
dev = rfcomm_dev_get(id);
if (!dev)
return -ENODEV;
......@@ -561,10 +583,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
if (err < 0) {
rfcomm_dev_put(dev);
if (err < 0)
return err;
}
/* Wait for DLC to connect */
add_wait_queue(&dev->wait, &wait);
......@@ -589,9 +609,6 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
if (err < 0)
rfcomm_dev_put(dev);
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment