aboutsummaryrefslogtreecommitdiff
path: root/kernel/printk
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/printk')
-rw-r--r--kernel/printk/printk.c347
1 files changed, 224 insertions, 123 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index b1d255f0413..13e839dbca0 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -54,20 +54,16 @@
#include "console_cmdline.h"
#include "braille.h"
-/* printk's without a loglevel use this.. */
-#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
-
-/* We show everything that is MORE important than this.. */
-#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
-#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
-
int console_printk[4] = {
- DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
+ CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
- MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
- DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
+ CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
+ CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
};
+/* Deferred messaged from sched code are marked by this special level */
+#define SCHED_MESSAGE_LOGLEVEL -2
+
/*
* Low level drivers may need that to know if they can schedule in
* their unblank() callback or not. So let's export it.
@@ -91,6 +87,29 @@ static struct lockdep_map console_lock_dep_map = {
#endif
/*
+ * Helper macros to handle lockdep when locking/unlocking console_sem. We use
+ * macros instead of functions so that _RET_IP_ contains useful information.
+ */
+#define down_console_sem() do { \
+ down(&console_sem);\
+ mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);\
+} while (0)
+
+static int __down_trylock_console_sem(unsigned long ip)
+{
+ if (down_trylock(&console_sem))
+ return 1;
+ mutex_acquire(&console_lock_dep_map, 0, 1, ip);
+ return 0;
+}
+#define down_trylock_console_sem() __down_trylock_console_sem(_RET_IP_)
+
+#define up_console_sem() do { \
+ mutex_release(&console_lock_dep_map, 1, _RET_IP_);\
+ up(&console_sem);\
+} while (0)
+
+/*
* This is used for debugging the mess that is the VT code by
* keeping track if we have the console semaphore held. It's
* definitely not the perfect debug tool (we don't know if _WE_
@@ -206,8 +225,9 @@ struct printk_log {
};
/*
- * The logbuf_lock protects kmsg buffer, indices, counters. It is also
- * used in interesting ways to provide interlocking in console_unlock();
+ * The logbuf_lock protects kmsg buffer, indices, counters. This can be taken
+ * within the scheduler's rq lock. It must be released before calling
+ * console_unlock() or anything else that might wake up a process.
*/
static DEFINE_RAW_SPINLOCK(logbuf_lock);
@@ -250,9 +270,6 @@ static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
static char *log_buf = __log_buf;
static u32 log_buf_len = __LOG_BUF_LEN;
-/* cpu currently holding logbuf_lock */
-static volatile unsigned int logbuf_cpu = UINT_MAX;
-
/* human readable text of the record */
static char *log_text(const struct printk_log *msg)
{
@@ -297,37 +314,109 @@ static u32 log_next(u32 idx)
return idx + msg->len;
}
-/* insert record into the buffer, discard old ones, update heads */
-static void log_store(int facility, int level,
- enum log_flags flags, u64 ts_nsec,
- const char *dict, u16 dict_len,
- const char *text, u16 text_len)
+/*
+ * Check whether there is enough free space for the given message.
+ *
+ * The same values of first_idx and next_idx mean that the buffer
+ * is either empty or full.
+ *
+ * If the buffer is empty, we must respect the position of the indexes.
+ * They cannot be reset to the beginning of the buffer.
+ */
+static int logbuf_has_space(u32 msg_size, bool empty)
{
- struct printk_log *msg;
- u32 size, pad_len;
+ u32 free;
- /* number of '\0' padding bytes to next message */
- size = sizeof(struct printk_log) + text_len + dict_len;
- pad_len = (-size) & (LOG_ALIGN - 1);
- size += pad_len;
+ if (log_next_idx > log_first_idx || empty)
+ free = max(log_buf_len - log_next_idx, log_first_idx);
+ else
+ free = log_first_idx - log_next_idx;
+
+ /*
+ * We need space also for an empty header that signalizes wrapping
+ * of the buffer.
+ */
+ return free >= msg_size + sizeof(struct printk_log);
+}
+static int log_make_free_space(u32 msg_size)
+{
while (log_first_seq < log_next_seq) {
- u32 free;
+ if (logbuf_has_space(msg_size, false))
+ return 0;
+ /* drop old messages until we have enough continuous space */
+ log_first_idx = log_next(log_first_idx);
+ log_first_seq++;
+ }
- if (log_next_idx > log_first_idx)
- free = max(log_buf_len - log_next_idx, log_first_idx);
- else
- free = log_first_idx - log_next_idx;
+ /* sequence numbers are equal, so the log buffer is empty */
+ if (logbuf_has_space(msg_size, true))
+ return 0;
- if (free > size + sizeof(struct printk_log))
- break;
+ return -ENOMEM;
+}
- /* drop old messages until we have enough contiuous space */
- log_first_idx = log_next(log_first_idx);
- log_first_seq++;
+/* compute the message size including the padding bytes */
+static u32 msg_used_size(u16 text_len, u16 dict_len, u32 *pad_len)
+{
+ u32 size;
+
+ size = sizeof(struct printk_log) + text_len + dict_len;
+ *pad_len = (-size) & (LOG_ALIGN - 1);
+ size += *pad_len;
+
+ return size;
+}
+
+/*
+ * Define how much of the log buffer we could take at maximum. The value
+ * must be greater than two. Note that only half of the buffer is available
+ * when the index points to the middle.
+ */
+#define MAX_LOG_TAKE_PART 4
+static const char trunc_msg[] = "<truncated>";
+
+static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len,
+ u16 *dict_len, u32 *pad_len)
+{
+ /*
+ * The message should not take the whole buffer. Otherwise, it might
+ * get removed too soon.
+ */
+ u32 max_text_len = log_buf_len / MAX_LOG_TAKE_PART;
+ if (*text_len > max_text_len)
+ *text_len = max_text_len;
+ /* enable the warning message */
+ *trunc_msg_len = strlen(trunc_msg);
+ /* disable the "dict" completely */
+ *dict_len = 0;
+ /* compute the size again, count also the warning message */
+ return msg_used_size(*text_len + *trunc_msg_len, 0, pad_len);
+}
+
+/* insert record into the buffer, discard old ones, update heads */
+static int log_store(int facility, int level,
+ enum log_flags flags, u64 ts_nsec,
+ const char *dict, u16 dict_len,
+ const char *text, u16 text_len)
+{
+ struct printk_log *msg;
+ u32 size, pad_len;
+ u16 trunc_msg_len = 0;
+
+ /* number of '\0' padding bytes to next message */
+ size = msg_used_size(text_len, dict_len, &pad_len);
+
+ if (log_make_free_space(size)) {
+ /* truncate the message if it is too long for empty buffer */
+ size = truncate_msg(&text_len, &trunc_msg_len,
+ &dict_len, &pad_len);
+ /* survive when the log buffer is too small for trunc_msg */
+ if (log_make_free_space(size))
+ return 0;
}
- if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
+ if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) {
/*
* This message + an additional empty header does not fit
* at the end of the buffer. Add an empty header with len == 0
@@ -341,6 +430,10 @@ static void log_store(int facility, int level,
msg = (struct printk_log *)(log_buf + log_next_idx);
memcpy(log_text(msg), text, text_len);
msg->text_len = text_len;
+ if (trunc_msg_len) {
+ memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len);
+ msg->text_len += trunc_msg_len;
+ }
memcpy(log_dict(msg), dict, dict_len);
msg->dict_len = dict_len;
msg->facility = facility;
@@ -351,11 +444,13 @@ static void log_store(int facility, int level,
else
msg->ts_nsec = local_clock();
memset(log_dict(msg) + dict_len, 0, pad_len);
- msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
+ msg->len = size;
/* insert message */
log_next_idx += msg->len;
log_next_seq++;
+
+ return msg->text_len;
}
#ifdef CONFIG_SECURITY_DMESG_RESTRICT
@@ -1076,7 +1171,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
next_seq = log_next_seq;
len = 0;
- prev = 0;
while (len >= 0 && seq < next_seq) {
struct printk_log *msg = log_from_idx(idx);
int textlen;
@@ -1304,7 +1398,10 @@ static void zap_locks(void)
sema_init(&console_sem, 1);
}
-/* Check if we have any console registered that can be called early in boot. */
+/*
+ * Check if we have any console that is capable of printing while cpu is
+ * booting or shutting down. Requires console_sem.
+ */
static int have_callable_console(void)
{
struct console *con;
@@ -1334,36 +1431,22 @@ static inline int can_use_console(unsigned int cpu)
* messages from a 'printk'. Return true (and with the
* console_lock held, and 'console_locked' set) if it
* is successful, false otherwise.
- *
- * This gets called with the 'logbuf_lock' spinlock held and
- * interrupts disabled. It should return with 'lockbuf_lock'
- * released but interrupts still disabled.
*/
static int console_trylock_for_printk(unsigned int cpu)
- __releases(&logbuf_lock)
{
- int retval = 0, wake = 0;
-
- if (console_trylock()) {
- retval = 1;
-
- /*
- * If we can't use the console, we need to release
- * the console semaphore by hand to avoid flushing
- * the buffer. We need to hold the console semaphore
- * in order to do this test safely.
- */
- if (!can_use_console(cpu)) {
- console_locked = 0;
- wake = 1;
- retval = 0;
- }
+ if (!console_trylock())
+ return 0;
+ /*
+ * If we can't use the console, we need to release the console
+ * semaphore by hand to avoid flushing the buffer. We need to hold the
+ * console semaphore in order to do this test safely.
+ */
+ if (!can_use_console(cpu)) {
+ console_locked = 0;
+ up_console_sem();
+ return 0;
}
- logbuf_cpu = UINT_MAX;
- raw_spin_unlock(&logbuf_lock);
- if (wake)
- up(&console_sem);
- return retval;
+ return 1;
}
int printk_delay_msec __read_mostly;
@@ -1491,11 +1574,19 @@ asmlinkage int vprintk_emit(int facility, int level,
static int recursion_bug;
static char textbuf[LOG_LINE_MAX];
char *text = textbuf;
- size_t text_len;
+ size_t text_len = 0;
enum log_flags lflags = 0;
unsigned long flags;
int this_cpu;
int printed_len = 0;
+ bool in_sched = false;
+ /* cpu currently holding logbuf_lock in this function */
+ static volatile unsigned int logbuf_cpu = UINT_MAX;
+
+ if (level == SCHED_MESSAGE_LOGLEVEL) {
+ level = -1;
+ in_sched = true;
+ }
boot_delay_msec(level);
printk_delay();
@@ -1531,17 +1622,22 @@ asmlinkage int vprintk_emit(int facility, int level,
"BUG: recent printk recursion!";
recursion_bug = 0;
- printed_len += strlen(recursion_msg);
+ text_len = strlen(recursion_msg);
/* emit KERN_CRIT message */
- log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
- NULL, 0, recursion_msg, printed_len);
+ printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
+ NULL, 0, recursion_msg, text_len);
}
/*
* The printf needs to come first; we need the syslog
* prefix which might be passed-in as a parameter.
*/
- text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
+ if (in_sched)
+ text_len = scnprintf(text, sizeof(textbuf),
+ KERN_WARNING "[sched_delayed] ");
+
+ text_len += vscnprintf(text + text_len,
+ sizeof(textbuf) - text_len, fmt, args);
/* mark and strip a trailing newline */
if (text_len && text[text_len-1] == '\n') {
@@ -1561,9 +1657,12 @@ asmlinkage int vprintk_emit(int facility, int level,
level = kern_level - '0';
case 'd': /* KERN_DEFAULT */
lflags |= LOG_PREFIX;
- case 'c': /* KERN_CONT */
- break;
}
+ /*
+ * No need to check length here because vscnprintf
+ * put '\0' at the end of the string. Only valid and
+ * newly printed level is detected.
+ */
text_len -= end_of_header - text;
text = (char *)end_of_header;
}
@@ -1584,9 +1683,12 @@ asmlinkage int vprintk_emit(int facility, int level,
cont_flush(LOG_NEWLINE);
/* buffer line if possible, otherwise store it right away */
- if (!cont_add(facility, level, text, text_len))
- log_store(facility, level, lflags | LOG_CONT, 0,
- dict, dictlen, text, text_len);
+ if (cont_add(facility, level, text, text_len))
+ printed_len += text_len;
+ else
+ printed_len += log_store(facility, level,
+ lflags | LOG_CONT, 0,
+ dict, dictlen, text, text_len);
} else {
bool stored = false;
@@ -1605,27 +1707,30 @@ asmlinkage int vprintk_emit(int facility, int level,
cont_flush(LOG_NEWLINE);
}
- if (!stored)
- log_store(facility, level, lflags, 0,
- dict, dictlen, text, text_len);
+ if (stored)
+ printed_len += text_len;
+ else
+ printed_len += log_store(facility, level, lflags, 0,
+ dict, dictlen, text, text_len);
}
- printed_len += text_len;
- /*
- * Try to acquire and then immediately release the console semaphore.
- * The release will print out buffers and wake up /dev/kmsg and syslog()
- * users.
- *
- * The console_trylock_for_printk() function will release 'logbuf_lock'
- * regardless of whether it actually gets the console semaphore or not.
- */
- if (console_trylock_for_printk(this_cpu))
- console_unlock();
+ logbuf_cpu = UINT_MAX;
+ raw_spin_unlock(&logbuf_lock);
+
+ /* If called from the scheduler, we can not call up(). */
+ if (!in_sched) {
+ /*
+ * Try to acquire and then immediately release the console
+ * semaphore. The release will print out buffers and wake up
+ * /dev/kmsg and syslog() users.
+ */
+ if (console_trylock_for_printk(this_cpu))
+ console_unlock();
+ }
lockdep_on();
out_restore_irqs:
local_irq_restore(flags);
-
return printed_len;
}
EXPORT_SYMBOL(vprintk_emit);
@@ -1672,7 +1777,7 @@ EXPORT_SYMBOL(printk_emit);
*
* See the vsnprintf() documentation for format string extensions over C99.
*/
-asmlinkage int printk(const char *fmt, ...)
+asmlinkage __visible int printk(const char *fmt, ...)
{
va_list args;
int r;
@@ -1735,7 +1840,7 @@ void early_vprintk(const char *fmt, va_list ap)
}
}
-asmlinkage void early_printk(const char *fmt, ...)
+asmlinkage __visible void early_printk(const char *fmt, ...)
{
va_list ap;
@@ -1880,14 +1985,14 @@ void suspend_console(void)
printk("Suspending console(s) (use no_console_suspend to debug)\n");
console_lock();
console_suspended = 1;
- up(&console_sem);
+ up_console_sem();
}
void resume_console(void)
{
if (!console_suspend_enabled)
return;
- down(&console_sem);
+ down_console_sem();
console_suspended = 0;
console_unlock();
}
@@ -1929,12 +2034,11 @@ void console_lock(void)
{
might_sleep();
- down(&console_sem);
+ down_console_sem();
if (console_suspended)
return;
console_locked = 1;
console_may_schedule = 1;
- mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
}
EXPORT_SYMBOL(console_lock);
@@ -1948,15 +2052,14 @@ EXPORT_SYMBOL(console_lock);
*/
int console_trylock(void)
{
- if (down_trylock(&console_sem))
+ if (down_trylock_console_sem())
return 0;
if (console_suspended) {
- up(&console_sem);
+ up_console_sem();
return 0;
}
console_locked = 1;
console_may_schedule = 0;
- mutex_acquire(&console_lock_dep_map, 0, 1, _RET_IP_);
return 1;
}
EXPORT_SYMBOL(console_trylock);
@@ -2018,7 +2121,7 @@ void console_unlock(void)
bool retry;
if (console_suspended) {
- up(&console_sem);
+ up_console_sem();
return;
}
@@ -2039,10 +2142,15 @@ again:
}
if (console_seq < log_first_seq) {
+ len = sprintf(text, "** %u printk messages dropped ** ",
+ (unsigned)(log_first_seq - console_seq));
+
/* messages are gone, move to first one */
console_seq = log_first_seq;
console_idx = log_first_idx;
console_prev = 0;
+ } else {
+ len = 0;
}
skip:
if (console_seq == log_next_seq)
@@ -2067,8 +2175,8 @@ skip:
}
level = msg->level;
- len = msg_print_text(msg, console_prev, false,
- text, sizeof(text));
+ len += msg_print_text(msg, console_prev, false,
+ text + len, sizeof(text) - len);
console_idx = log_next(console_idx);
console_seq++;
console_prev = msg->flags;
@@ -2080,7 +2188,6 @@ skip:
local_irq_restore(flags);
}
console_locked = 0;
- mutex_release(&console_lock_dep_map, 1, _RET_IP_);
/* Release the exclusive_console once it is used */
if (unlikely(exclusive_console))
@@ -2088,7 +2195,7 @@ skip:
raw_spin_unlock(&logbuf_lock);
- up(&console_sem);
+ up_console_sem();
/*
* Someone could have filled up the buffer again, so re-check if there's
@@ -2133,7 +2240,7 @@ void console_unblank(void)
* oops_in_progress is set to 1..
*/
if (oops_in_progress) {
- if (down_trylock(&console_sem) != 0)
+ if (down_trylock_console_sem() != 0)
return;
} else
console_lock();
@@ -2409,6 +2516,7 @@ int unregister_console(struct console *console)
if (console_drivers != NULL && console->flags & CON_CONSDEV)
console_drivers->flags |= CON_CONSDEV;
+ console->flags &= ~CON_ENABLED;
console_unlock();
console_sysfs_notify();
return res;
@@ -2433,21 +2541,19 @@ late_initcall(printk_late_init);
/*
* Delayed printk version, for scheduler-internal messages:
*/
-#define PRINTK_BUF_SIZE 512
-
#define PRINTK_PENDING_WAKEUP 0x01
-#define PRINTK_PENDING_SCHED 0x02
+#define PRINTK_PENDING_OUTPUT 0x02
static DEFINE_PER_CPU(int, printk_pending);
-static DEFINE_PER_CPU(char [PRINTK_BUF_SIZE], printk_sched_buf);
static void wake_up_klogd_work_func(struct irq_work *irq_work)
{
int pending = __this_cpu_xchg(printk_pending, 0);
- if (pending & PRINTK_PENDING_SCHED) {
- char *buf = __get_cpu_var(printk_sched_buf);
- pr_warn("[sched_delayed] %s", buf);
+ if (pending & PRINTK_PENDING_OUTPUT) {
+ /* If trylock fails, someone else is doing the printing */
+ if (console_trylock())
+ console_unlock();
}
if (pending & PRINTK_PENDING_WAKEUP)
@@ -2469,23 +2575,19 @@ void wake_up_klogd(void)
preempt_enable();
}
-int printk_sched(const char *fmt, ...)
+int printk_deferred(const char *fmt, ...)
{
- unsigned long flags;
va_list args;
- char *buf;
int r;
- local_irq_save(flags);
- buf = __get_cpu_var(printk_sched_buf);
-
+ preempt_disable();
va_start(args, fmt);
- r = vsnprintf(buf, PRINTK_BUF_SIZE, fmt, args);
+ r = vprintk_emit(0, SCHED_MESSAGE_LOGLEVEL, NULL, 0, fmt, args);
va_end(args);
- __this_cpu_or(printk_pending, PRINTK_PENDING_SCHED);
+ __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
irq_work_queue(&__get_cpu_var(wake_up_klogd_work));
- local_irq_restore(flags);
+ preempt_enable();
return r;
}
@@ -2788,7 +2890,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
next_idx = idx;
l = 0;
- prev = 0;
while (seq < dumper->next_seq) {
struct printk_log *msg = log_from_idx(idx);
style='width: 17.3%;'/> -rw-r--r--drivers/char/tpm/tpm_tis.c49
-rw-r--r--drivers/char/tpm/xen-tpmfront.c88
-rw-r--r--drivers/char/ttyprintk.c17
-rw-r--r--drivers/char/virtio_console.c36
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c3
87 files changed, 3658 insertions, 2434 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 14219972c74..6e9f74a5c09 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -40,7 +40,7 @@ config SGI_MBCS
source "drivers/tty/serial/Kconfig"
config TTY_PRINTK
- bool "TTY driver to output user messages via printk"
+ tristate "TTY driver to output user messages via printk"
depends on EXPERT && TTY
default n
---help---
@@ -408,7 +408,7 @@ config APPLICOM
config SONYPI
tristate "Sony Vaio Programmable I/O Control Device support"
- depends on X86 && PCI && INPUT && !64BIT
+ depends on X86_32 && PCI && INPUT
---help---
This driver enables access to the Sony Programmable I/O Control
Device which can be found in many (all ?) Sony Vaio laptops.
@@ -499,6 +499,7 @@ config RAW_DRIVER
config MAX_RAW_DEVS
int "Maximum number of RAW devices to support (1-65536)"
depends on RAW_DRIVER
+ range 1 65536
default "256"
help
The maximum number of RAW devices that are supported.
@@ -522,10 +523,16 @@ config HPET_MMAP
If you say Y here, user applications will be able to mmap
the HPET registers.
+config HPET_MMAP_DEFAULT
+ bool "Enable HPET MMAP access by default"
+ default y
+ depends on HPET_MMAP
+ help
In some hardware implementations, the page containing HPET
registers may also contain other things that shouldn't be
- exposed to the user. If this applies to your hardware,
- say N here.
+ exposed to the user. This option selects the default (if
+ kernel parameter hpet_mmap is not set) user access to the
+ registers for applications that require it.
config HANGCHECK_TIMER
tristate "Hangcheck timer"
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7ff1d0d208a..a324f9303e3 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o
obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
-obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_IBM_BSR) += bsr.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o
obj-$(CONFIG_BFIN_OTP) += bfin-otp.o
@@ -50,7 +49,7 @@ obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
obj-$(CONFIG_MWAVE) += mwave/
-obj-$(CONFIG_AGP) += agp/
+obj-y += agp/
obj-$(CONFIG_PCMCIA) += pcmcia/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index d8b1b576556..c528f96ee20 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -68,6 +68,7 @@ config AGP_AMD64
config AGP_INTEL
tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
depends on AGP && X86
+ select INTEL_GTT
help
This option gives you AGP support for the GLX component of X
on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
@@ -155,3 +156,7 @@ config AGP_SGI_TIOCA
This option gives you AGP GART support for the SGI TIO chipset
for IA64 processors.
+config INTEL_GTT
+ tristate
+ depends on X86 && PCI
+
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 8eb56e273e7..604489bcdbf 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
-obj-$(CONFIG_AGP_INTEL) += intel-gtt.o
+obj-$(CONFIG_INTEL_GTT) += intel-gtt.o
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o
obj-$(CONFIG_AGP_SIS) += sis-agp.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 923f99df4f1..b709749c863 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -239,6 +239,7 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
/* Chipset independent registers (from AGP Spec) */
#define AGP_APBASE 0x10
+#define AGP_APERTURE_BAR 0
#define AGPSTAT 0x4
#define AGPCMD 0x8
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 443cd6751ca..19db0366765 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -85,8 +85,8 @@ static int ali_configure(void)
pci_write_config_dword(agp_bridge->dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010));
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
#if 0
if (agp_bridge->type == ALI_M1541) {
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 779f0ab845a..3661a51e93e 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -11,7 +11,7 @@
#include <linux/slab.h>
#include "agp.h"
-#define AMD_MMBASE 0x14
+#define AMD_MMBASE_BAR 1
#define AMD_APSIZE 0xac
#define AMD_MODECNTL 0xb0
#define AMD_MODECNTL2 0xb2
@@ -126,7 +126,6 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
unsigned long __iomem *cur_gatt;
unsigned long addr;
int retval;
- u32 temp;
int i;
value = A_SIZE_LVL2(agp_bridge->current_size);
@@ -149,8 +148,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge)
* used to program the agp master not the cpu
*/
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
agp_bridge->gart_bus_addr = addr;
/* Calculate the agp offset */
@@ -207,6 +205,7 @@ static int amd_irongate_fetch_size(void)
static int amd_irongate_configure(void)
{
struct aper_size_info_lvl2 *current_size;
+ phys_addr_t reg;
u32 temp;
u16 enable_reg;
@@ -214,9 +213,8 @@ static int amd_irongate_configure(void)
if (!amd_irongate_private.registers) {
/* Get the memory mapped registers */
- pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp);
- temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
+ reg = pci_resource_start(agp_bridge->dev, AMD_MMBASE_BAR);
+ amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);
if (!amd_irongate_private.registers)
return -ENOMEM;
}
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index d79d692d05b..3b47ed0310e 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -269,7 +269,6 @@ static int agp_aperture_valid(u64 aper, u32 size)
*/
static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
{
- u32 aper_low, aper_hi;
u64 aper, nb_aper;
int order = 0;
u32 nb_order, nb_base;
@@ -295,9 +294,7 @@ static int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, u16 cap)
apsize |= 0xf00;
order = 7 - hweight16(apsize);
- pci_read_config_dword(agp, 0x10, &aper_low);
- pci_read_config_dword(agp, 0x14, &aper_hi);
- aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
+ aper = pci_bus_address(agp, AGP_APERTURE_BAR);
/*
* On some sick chips APSIZE is 0. This means it wants 4G
@@ -735,7 +732,7 @@ static struct pci_device_id agp_amd64_pci_table[] = {
MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table);
-static DEFINE_PCI_DEVICE_TABLE(agp_amd64_pci_promisc_table) = {
+static const struct pci_device_id agp_amd64_pci_promisc_table[] = {
{ PCI_DEVICE_CLASS(0, 0) },
{ }
};
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 03c1dc1ab55..18a7a6baa30 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -12,7 +12,7 @@
#include <asm/agp.h>
#include "agp.h"
-#define ATI_GART_MMBASE_ADDR 0x14
+#define ATI_GART_MMBASE_BAR 1
#define ATI_RS100_APSIZE 0xac
#define ATI_RS100_IG_AGPMODE 0xb0
#define ATI_RS300_APSIZE 0xf8
@@ -196,12 +196,12 @@ static void ati_cleanup(void)
static int ati_configure(void)
{
+ phys_addr_t reg;
u32 temp;
/* Get the memory mapped registers */
- pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp);
- temp = (temp & 0xfffff000);
- ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
+ reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR);
+ ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);
if (!ati_generic_private.registers)
return -ENOMEM;
@@ -211,18 +211,18 @@ static int ati_configure(void)
else
pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
- /* address to map too */
+ /* address to map to */
/*
- pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
- agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev,
+ AGP_APERTURE_BAR);
printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
*/
writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/
/* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
- pci_read_config_dword(agp_bridge->dev, 4, &temp);
- pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14));
+ pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp);
+ pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14));
/* Write out the address of the gatt table */
writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
@@ -385,8 +385,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge)
* This is a bus address even on the alpha, b/c its
* used to program the agp master not the cpu
*/
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
agp_bridge->gart_bus_addr = addr;
/* Calculate the agp offset */
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 6974d503205..533cb6d229b 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -128,7 +128,6 @@ static void efficeon_cleanup(void)
static int efficeon_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_lvl2 *current_size;
@@ -141,8 +140,8 @@ static int efficeon_configure(void)
current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* agpctrl */
pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 1b192395a90..b29703324e9 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/mman.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/agp_backend.h>
#include <linux/agpgart.h>
@@ -731,6 +730,7 @@ static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg)
agp_copy_info(agp_bridge, &kerninfo);
+ memset(&userinfo, 0, sizeof(userinfo));
userinfo.version.major = kerninfo.version.major;
userinfo.version.minor = kerninfo.version.minor;
userinfo.bridge_id = kerninfo.device->vendor |
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index a0df182f6f7..0fbccce1cee 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -29,7 +29,6 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
@@ -1396,8 +1395,8 @@ int agp3_generic_configure(void)
current_size = A_SIZE_16(agp_bridge->current_size);
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* set aperture size */
pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value);
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index a426ee1f57a..f9b9ca5d31b 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -14,9 +14,6 @@
#include "intel-agp.h"
#include <drm/intel-gtt.h>
-int intel_agp_enabled;
-EXPORT_SYMBOL(intel_agp_enabled);
-
static int intel_fetch_size(void)
{
int i;
@@ -118,7 +115,6 @@ static void intel_8xx_cleanup(void)
static int intel_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_16 *current_size;
@@ -128,8 +124,8 @@ static int intel_configure(void)
pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -148,7 +144,7 @@ static int intel_configure(void)
static int intel_815_configure(void)
{
- u32 temp, addr;
+ u32 addr;
u8 temp2;
struct aper_size_info_8 *current_size;
@@ -167,8 +163,8 @@ static int intel_815_configure(void)
current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);
addr &= INTEL_815_ATTBASE_MASK;
@@ -208,7 +204,6 @@ static void intel_820_cleanup(void)
static int intel_820_configure(void)
{
- u32 temp;
u8 temp2;
struct aper_size_info_8 *current_size;
@@ -218,8 +213,8 @@ static int intel_820_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -239,7 +234,6 @@ static int intel_820_configure(void)
static int intel_840_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_8 *current_size;
@@ -249,8 +243,8 @@ static int intel_840_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -268,7 +262,6 @@ static int intel_840_configure(void)
static int intel_845_configure(void)
{
- u32 temp;
u8 temp2;
struct aper_size_info_8 *current_size;
@@ -282,9 +275,9 @@ static int intel_845_configure(void)
agp_bridge->apbase_config);
} else {
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
- agp_bridge->apbase_config = temp;
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
+ agp_bridge->apbase_config = agp_bridge->gart_bus_addr;
}
/* attbase - aperture base */
@@ -303,7 +296,6 @@ static int intel_845_configure(void)
static int intel_850_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_8 *current_size;
@@ -313,8 +305,8 @@ static int intel_850_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -332,7 +324,6 @@ static int intel_850_configure(void)
static int intel_860_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_8 *current_size;
@@ -342,8 +333,8 @@ static int intel_860_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -361,7 +352,6 @@ static int intel_860_configure(void)
static int intel_830mp_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_8 *current_size;
@@ -371,8 +361,8 @@ static int intel_830mp_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -390,7 +380,6 @@ static int intel_830mp_configure(void)
static int intel_7505_configure(void)
{
- u32 temp;
u16 temp2;
struct aper_size_info_8 *current_size;
@@ -400,8 +389,8 @@ static int intel_7505_configure(void)
pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
/* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture base */
pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
@@ -814,8 +803,6 @@ static int agp_intel_probe(struct pci_dev *pdev,
found_gmch:
pci_set_drvdata(pdev, bridge);
err = agp_add_bridge(bridge);
- if (!err)
- intel_agp_enabled = 1;
return err;
}
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 1042c1b9037..fda073dcd96 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -55,8 +55,8 @@
#define INTEL_I860_ERRSTS 0xc8
/* Intel i810 registers */
-#define I810_GMADDR 0x10
-#define I810_MMADDR 0x14
+#define I810_GMADR_BAR 0
+#define I810_MMADR_BAR 1
#define I810_PTE_BASE 0x10000
#define I810_PTE_MAIN_UNCACHED 0x00000000
#define I810_PTE_LOCAL 0x00000002
@@ -113,9 +113,9 @@
#define INTEL_I850_ERRSTS 0xc8
/* intel 915G registers */
-#define I915_GMADDR 0x18
-#define I915_MMADDR 0x10
-#define I915_PTEADDR 0x1C
+#define I915_GMADR_BAR 2
+#define I915_MMADR_BAR 0
+#define I915_PTE_BAR 3
#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index b8e2014cb9c..9a024f899dd 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/agp_backend.h>
@@ -64,7 +63,7 @@ static struct _intel_private {
struct pci_dev *pcidev; /* device one */
struct pci_dev *bridge_dev;
u8 __iomem *registers;
- phys_addr_t gtt_bus_addr;
+ phys_addr_t gtt_phys_addr;
u32 PGETBL_save;
u32 __iomem *gtt; /* I915G */
bool clear_fake_agp; /* on first access via agp, fill with scratch */
@@ -94,6 +93,7 @@ static struct _intel_private {
#define IS_IRONLAKE intel_private.driver->is_ironlake
#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static int intel_gtt_map_memory(struct page **pages,
unsigned int num_entries,
struct sg_table *st)
@@ -168,11 +168,12 @@ static void i8xx_destroy_pages(struct page *page)
__free_pages(page, 2);
atomic_dec(&agp_bridge->current_memory_agp);
}
+#endif
#define I810_GTT_ORDER 4
static int i810_setup(void)
{
- u32 reg_addr;
+ phys_addr_t reg_addr;
char *gtt_table;
/* i81x does not preallocate the gtt. It's always 64kb in size. */
@@ -181,8 +182,7 @@ static int i810_setup(void)
return -ENOMEM;
intel_private.i81x_gtt_table = gtt_table;
- pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
- reg_addr &= 0xfff80000;
+ reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);
intel_private.registers = ioremap(reg_addr, KB(64));
if (!intel_private.registers)
@@ -191,7 +191,7 @@ static int i810_setup(void)
writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED,
intel_private.registers+I810_PGETBL_CTL);
- intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+ intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;
if ((readl(intel_private.registers+I810_DRAM_CTL)
& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
@@ -209,6 +209,7 @@ static void i810_cleanup(void)
free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER);
}
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,
int type)
{
@@ -289,6 +290,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
}
kfree(curr);
}
+#endif
static int intel_gtt_setup_scratch_page(void)
{
@@ -608,9 +610,8 @@ static bool intel_gtt_can_wc(void)
static int intel_gtt_init(void)
{
- u32 gma_addr;
u32 gtt_map_size;
- int ret;
+ int ret, bar;
ret = intel_private.driver->setup();
if (ret != 0)
@@ -636,10 +637,10 @@ static int intel_gtt_init(void)
intel_private.gtt = NULL;
if (intel_gtt_can_wc())
- intel_private.gtt = ioremap_wc(intel_private.gtt_bus_addr,
+ intel_private.gtt = ioremap_wc(intel_private.gtt_phys_addr,
gtt_map_size);
if (intel_private.gtt == NULL)
- intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+ intel_private.gtt = ioremap(intel_private.gtt_phys_addr,
gtt_map_size);
if (intel_private.gtt == NULL) {
intel_private.driver->cleanup();
@@ -647,7 +648,9 @@ static int intel_gtt_init(void)
return -ENOMEM;
}
+#if IS_ENABLED(CONFIG_AGP_INTEL)
global_cache_flush(); /* FIXME: ? */
+#endif
intel_private.stolen_size = intel_gtt_stolen_size();
@@ -660,17 +663,15 @@ static int intel_gtt_init(void)
}
if (INTEL_GTT_GEN <= 2)
- pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
- &gma_addr);
+ bar = I810_GMADR_BAR;
else
- pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
- &gma_addr);
-
- intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
+ bar = I915_GMADR_BAR;
+ intel_private.gma_bus_addr = pci_bus_address(intel_private.pcidev, bar);
return 0;
}
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static int intel_fake_agp_fetch_size(void)
{
int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
@@ -689,6 +690,7 @@ static int intel_fake_agp_fetch_size(void)
return 0;
}
+#endif
static void i830_cleanup(void)
{
@@ -787,20 +789,20 @@ EXPORT_SYMBOL(intel_enable_gtt);
static int i830_setup(void)
{
- u32 reg_addr;
+ phys_addr_t reg_addr;
- pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
- reg_addr &= 0xfff80000;
+ reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR);
intel_private.registers = ioremap(reg_addr, KB(64));
if (!intel_private.registers)
return -ENOMEM;
- intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+ intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE;
return 0;
}
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
{
agp_bridge->gatt_table_real = NULL;
@@ -825,6 +827,7 @@ static int intel_fake_agp_configure(void)
return 0;
}
+#endif
static bool i830_check_flags(unsigned int flags)
{
@@ -863,6 +866,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
}
EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static void intel_gtt_insert_pages(unsigned int first_entry,
unsigned int num_entries,
struct page **pages,
@@ -928,6 +932,7 @@ out_err:
mem->is_flushed = true;
return ret;
}
+#endif
void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
{
@@ -941,6 +946,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
}
EXPORT_SYMBOL(intel_gtt_clear_range);
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static int intel_fake_agp_remove_entries(struct agp_memory *mem,
off_t pg_start, int type)
{
@@ -982,6 +988,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
/* always return NULL for other allocation types for now */
return NULL;
}
+#endif
static int intel_alloc_chipset_flush_resource(void)
{
@@ -1108,12 +1115,10 @@ static void i965_write_entry(dma_addr_t addr,
static int i9xx_setup(void)
{
- u32 reg_addr, gtt_addr;
+ phys_addr_t reg_addr;
int size = KB(512);
- pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
-
- reg_addr &= 0xfff80000;
+ reg_addr = pci_resource_start(intel_private.pcidev, I915_MMADR_BAR);
intel_private.registers = ioremap(reg_addr, size);
if (!intel_private.registers)
@@ -1121,15 +1126,14 @@ static int i9xx_setup(void)
switch (INTEL_GTT_GEN) {
case 3:
- pci_read_config_dword(intel_private.pcidev,
- I915_PTEADDR, &gtt_addr);
- intel_private.gtt_bus_addr = gtt_addr;
+ intel_private.gtt_phys_addr =
+ pci_resource_start(intel_private.pcidev, I915_PTE_BAR);
break;
case 5:
- intel_private.gtt_bus_addr = reg_addr + MB(2);
+ intel_private.gtt_phys_addr = reg_addr + MB(2);
break;
default:
- intel_private.gtt_bus_addr = reg_addr + KB(512);
+ intel_private.gtt_phys_addr = reg_addr + KB(512);
break;
}
@@ -1138,6 +1142,7 @@ static int i9xx_setup(void)
return 0;
}
+#if IS_ENABLED(CONFIG_AGP_INTEL)
static const struct agp_bridge_driver intel_fake_agp_driver = {
.owner = THIS_MODULE,
.size_type = FIXED_APER_SIZE,
@@ -1159,6 +1164,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = {
.agp_destroy_page = agp_generic_destroy_page,
.agp_destroy_pages = agp_generic_destroy_pages,
};
+#endif
static const struct intel_gtt_driver i81x_gtt_driver = {
.gen = 1,
@@ -1376,11 +1382,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
intel_private.refcount++;
+#if IS_ENABLED(CONFIG_AGP_INTEL)
if (bridge) {
bridge->driver = &intel_fake_agp_driver;
bridge->dev_private_data = &intel_private;
bridge->dev = bridge_pdev;
}
+#endif
intel_private.bridge_dev = pci_dev_get(bridge_pdev);
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index be42a2312dc..a1861b75eb3 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -106,6 +106,7 @@ static int nvidia_configure(void)
{
int i, rc, num_dirs;
u32 apbase, aplimit;
+ phys_addr_t apbase_phys;
struct aper_size_info_8 *current_size;
u32 temp;
@@ -115,9 +116,8 @@ static int nvidia_configure(void)
pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE,
current_size->size_value);
- /* address to map to */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &apbase);
- apbase &= PCI_BASE_ADDRESS_MEM_MASK;
+ /* address to map to */
+ apbase = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
agp_bridge->gart_bus_addr = apbase;
aplimit = apbase + (current_size->size * 1024 * 1024) - 1;
pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase);
@@ -153,8 +153,9 @@ static int nvidia_configure(void)
pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100);
/* map aperture */
+ apbase_phys = pci_resource_start(agp_bridge->dev, AGP_APERTURE_BAR);
nvidia_private.aperture =
- (volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE);
+ (volatile u32 __iomem *) ioremap(apbase_phys, 33 * PAGE_SIZE);
if (!nvidia_private.aperture)
return -ENOMEM;
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index 05b8d0241bd..3051c73bc38 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/agp_backend.h>
#include <asm/sn/addrs.h>
#include <asm/sn/io.h>
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 79c838c434b..2c74038da45 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -50,13 +50,12 @@ static void sis_tlbflush(struct agp_memory *mem)
static int sis_configure(void)
{
- u32 temp;
struct aper_size_info_8 *current_size;
current_size = A_SIZE_8(agp_bridge->current_size);
pci_write_config_byte(agp_bridge->dev, SIS_TLBCNTRL, 0x05);
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
pci_write_config_dword(agp_bridge->dev, SIS_ATTBASE,
agp_bridge->gatt_bus_addr);
pci_write_config_byte(agp_bridge->dev, SIS_APSIZE,
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 74d3aa3773b..228f20cddc0 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -43,16 +43,15 @@ static int via_fetch_size(void)
static int via_configure(void)
{
- u32 temp;
struct aper_size_info_8 *current_size;
current_size = A_SIZE_8(agp_bridge->current_size);
/* aperture size */
pci_write_config_byte(agp_bridge->dev, VIA_APSIZE,
current_size->size_value);
- /* address to map too */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ /* address to map to */
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* GART control register */
pci_write_config_dword(agp_bridge->dev, VIA_GARTCTRL, 0x0000000f);
@@ -132,9 +131,9 @@ static int via_configure_agp3(void)
current_size = A_SIZE_16(agp_bridge->current_size);
- /* address to map too */
- pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
- agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ /* address to map to */
+ agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev,
+ AGP_APERTURE_BAR);
/* attbase - aperture GATT base */
pci_write_config_dword(agp_bridge->dev, VIA_AGP3_ATTBASE,
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 46118f84594..dd9dfa15e9d 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -531,6 +531,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
{
struct apm_user *as;
int err;
+ unsigned long apm_event;
/* short-cut emergency suspends */
if (atomic_read(&userspace_notification_inhibit))
@@ -538,6 +539,9 @@ static int apm_suspend_notifier(struct notifier_block *nb,
switch (event) {
case PM_SUSPEND_PREPARE:
+ case PM_HIBERNATION_PREPARE:
+ apm_event = (event == PM_SUSPEND_PREPARE) ?
+ APM_USER_SUSPEND : APM_USER_HIBERNATION;
/*
* Queue an event to all "writer" users that we want
* to suspend and need their ack.
@@ -550,7 +554,7 @@ static int apm_suspend_notifier(struct notifier_block *nb,
as->writer && as->suser) {
as->suspend_state = SUSPEND_PENDING;
atomic_inc(&suspend_acks_pending);
- queue_add_event(&as->queue, APM_USER_SUSPEND);
+ queue_add_event(&as->queue, apm_event);
}
}
@@ -601,11 +605,14 @@ static int apm_suspend_notifier(struct notifier_block *nb,
return notifier_from_errno(err);
case PM_POST_SUSPEND:
+ case PM_POST_HIBERNATION:
+ apm_event = (event == PM_POST_SUSPEND) ?
+ APM_NORMAL_RESUME : APM_HIBERNATION_RESUME;
/*
* Anyone on the APM queues will think we're still suspended.
* Send a message so everyone knows we're now awake again.
*/
- queue_event(APM_NORMAL_RESUME);
+ queue_event(apm_event);
/*
* Finally, wake up anyone who is sleeping on the suspend.
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 974321a2508..14790304b84 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -345,7 +345,6 @@ out:
free_irq(apbs[i].irq, &dummy);
iounmap(apbs[i].RamIO);
}
- pci_disable_device(dev);
return ret;
}
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 0671e45daa5..8fedbc25041 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/fs.h>
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 448ce5e29c5..d5d4cd82b9f 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -34,15 +34,12 @@
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/io.h>
-
+#include <linux/acpi.h>
+#include <linux/hpet.h>
#include <asm/current.h>
#include <asm/irq.h>
#include <asm/div64.h>
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <linux/hpet.h>
-
/*
* The High Precision Event Timer driver.
* This driver is closely modelled after the rtc.c driver.
@@ -367,12 +364,29 @@ static unsigned int hpet_poll(struct file *file, poll_table * wait)
return 0;
}
+#ifdef CONFIG_HPET_MMAP
+#ifdef CONFIG_HPET_MMAP_DEFAULT
+static int hpet_mmap_enabled = 1;
+#else
+static int hpet_mmap_enabled = 0;
+#endif
+
+static __init int hpet_mmap_enable(char *str)
+{
+ get_option(&str, &hpet_mmap_enabled);
+ pr_info("HPET mmap %s\n", hpet_mmap_enabled ? "enabled" : "disabled");
+ return 1;
+}
+__setup("hpet_mmap", hpet_mmap_enable);
+
static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
{
-#ifdef CONFIG_HPET_MMAP
struct hpet_dev *devp;
unsigned long addr;
+ if (!hpet_mmap_enabled)
+ return -EACCES;
+
devp = file->private_data;
addr = devp->hd_hpets->hp_hpet_phys;
@@ -381,10 +395,13 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return vm_iomap_memory(vma, addr, PAGE_SIZE);
+}
#else
+static int hpet_mmap(struct file *file, struct vm_area_struct *vma)
+{
return -ENOSYS;
-#endif
}
+#endif
static int hpet_fasync(int fd, struct file *file, int on)
{
@@ -486,8 +503,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
}
sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
- irq_flags = devp->hd_flags & HPET_SHARED_IRQ
- ? IRQF_SHARED : IRQF_DISABLED;
+ irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0;
if (request_irq(irq, hpet_interrupt, irq_flags,
devp->hd_name, (void *)devp)) {
printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
@@ -971,8 +987,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
struct acpi_resource_fixed_memory32 *fixmem32;
fixmem32 = &res->data.fixed_memory32;
- if (!fixmem32)
- return AE_NO_MEMORY;
hdp->hd_phys_address = fixmem32->address;
hdp->hd_address = ioremap(fixmem32->address,
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 0aa9d91daef..836b061ced3 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -2,7 +2,7 @@
# Hardware Random Number Generator (RNG) configuration
#
-config HW_RANDOM
+menuconfig HW_RANDOM
tristate "Hardware Random Number Generator Core support"
default m
---help---
@@ -20,9 +20,11 @@ config HW_RANDOM
If unsure, say Y.
+if HW_RANDOM
+
config HW_RANDOM_TIMERIOMEM
tristate "Timer IOMEM HW Random Number Generator support"
- depends on HW_RANDOM && HAS_IOMEM
+ depends on HAS_IOMEM
---help---
This driver provides kernel-side support for a generic Random
Number Generator used by reading a 'dumb' iomem address that
@@ -36,7 +38,7 @@ config HW_RANDOM_TIMERIOMEM
config HW_RANDOM_INTEL
tristate "Intel HW Random Number Generator support"
- depends on HW_RANDOM && (X86 || IA64) && PCI
+ depends on (X86 || IA64) && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -49,7 +51,7 @@ config HW_RANDOM_INTEL
config HW_RANDOM_AMD
tristate "AMD HW Random Number Generator support"
- depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI
+ depends on (X86 || PPC_MAPLE) && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -62,8 +64,8 @@ config HW_RANDOM_AMD
config HW_RANDOM_ATMEL
tristate "Atmel Random Number Generator support"
- depends on HW_RANDOM && HAVE_CLK
- default (HW_RANDOM && ARCH_AT91)
+ depends on ARCH_AT91 && HAVE_CLK
+ default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Atmel AT91 devices.
@@ -75,7 +77,7 @@ config HW_RANDOM_ATMEL
config HW_RANDOM_BCM63XX
tristate "Broadcom BCM63xx Random Number Generator support"
- depends on HW_RANDOM && BCM63XX
+ depends on BCM63XX
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -88,7 +90,7 @@ config HW_RANDOM_BCM63XX
config HW_RANDOM_BCM2835
tristate "Broadcom BCM2835 Random Number Generator support"
- depends on HW_RANDOM && ARCH_BCM2835
+ depends on ARCH_BCM2835
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -101,7 +103,7 @@ config HW_RANDOM_BCM2835
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
- depends on HW_RANDOM && X86_32 && PCI
+ depends on X86_32 && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -114,7 +116,7 @@ config HW_RANDOM_GEODE
config HW_RANDOM_N2RNG
tristate "Niagara2 Random Number Generator support"
- depends on HW_RANDOM && SPARC64
+ depends on SPARC64
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -127,7 +129,7 @@ config HW_RANDOM_N2RNG
config HW_RANDOM_VIA
tristate "VIA HW Random Number Generator support"
- depends on HW_RANDOM && X86
+ depends on X86
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -140,7 +142,7 @@ config HW_RANDOM_VIA
config HW_RANDOM_IXP4XX
tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
- depends on HW_RANDOM && ARCH_IXP4XX
+ depends on ARCH_IXP4XX
default HW_RANDOM
---help---
This driver provides kernel-side support for the Pseudo-Random
@@ -153,7 +155,7 @@ config HW_RANDOM_IXP4XX
config HW_RANDOM_OMAP
tristate "OMAP Random Number Generator support"
- depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP2PLUS)
+ depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -165,9 +167,22 @@ config HW_RANDOM_OMAP
If unsure, say Y.
+config HW_RANDOM_OMAP3_ROM
+ tristate "OMAP3 ROM Random Number Generator support"
+ depends on ARCH_OMAP3
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on OMAP34xx processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap3-rom-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_OCTEON
tristate "Octeon Random Number Generator support"
- depends on HW_RANDOM && CAVIUM_OCTEON_SOC
+ depends on CAVIUM_OCTEON_SOC
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -180,7 +195,7 @@ config HW_RANDOM_OCTEON
config HW_RANDOM_PASEMI
tristate "PA Semi HW Random Number Generator support"
- depends on HW_RANDOM && PPC_PASEMI
+ depends on PPC_PASEMI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -193,7 +208,7 @@ config HW_RANDOM_PASEMI
config HW_RANDOM_VIRTIO
tristate "VirtIO Random Number Generator support"
- depends on HW_RANDOM && VIRTIO
+ depends on VIRTIO
---help---
This driver provides kernel-side support for the virtual Random Number
Generator hardware.
@@ -203,7 +218,7 @@ config HW_RANDOM_VIRTIO
config HW_RANDOM_TX4939
tristate "TX4939 Random Number Generator support"
- depends on HW_RANDOM && SOC_TX4939
+ depends on SOC_TX4939
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -216,7 +231,8 @@ config HW_RANDOM_TX4939
config HW_RANDOM_MXC_RNGA
tristate "Freescale i.MX RNGA Random Number Generator"
- depends on HW_RANDOM && ARCH_HAS_RNGA
+ depends on ARCH_HAS_RNGA
+ default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Freescale i.MX processors.
@@ -228,7 +244,8 @@ config HW_RANDOM_MXC_RNGA
config HW_RANDOM_NOMADIK
tristate "ST-Ericsson Nomadik Random Number Generator support"
- depends on HW_RANDOM && ARCH_NOMADIK
+ depends on ARCH_NOMADIK
+ default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on ST-Ericsson SoCs (8815 and 8500).
@@ -238,21 +255,10 @@ config HW_RANDOM_NOMADIK
If unsure, say Y.
-config HW_RANDOM_PICOXCELL
- tristate "Picochip picoXcell true random number generator support"
- depends on HW_RANDOM && ARCH_PICOXCELL && PICOXCELL_PC3X3
- ---help---
- This driver provides kernel-side support for the Random Number
- Generator hardware found on Picochip PC3x3 and later devices.
-
- To compile this driver as a module, choose M here: the
- module will be called picoxcell-rng.
-
- If unsure, say Y.
-
config HW_RANDOM_PPC4XX
tristate "PowerPC 4xx generic true random number generator support"
- depends on HW_RANDOM && PPC && 4xx
+ depends on PPC && 4xx
+ default HW_RANDOM
---help---
This driver provides the kernel-side support for the TRNG hardware
found in the security function of some PowerPC 4xx SoCs.
@@ -262,24 +268,9 @@ config HW_RANDOM_PPC4XX
If unsure, say N.
-config UML_RANDOM
- depends on UML
- tristate "Hardware random number generator"
- help
- This option enables UML's "hardware" random number generator. It
- attaches itself to the host's /dev/random, supplying as much entropy
- as the host has, rather than the small amount the UML gets from its
- own drivers. It registers itself as a standard hardware random number
- generator, major 10, minor 183, and the canonical device name is
- /dev/hwrng.
- The way to make use of this is to install the rng-tools package
- (check your distro, or download from
- http://sourceforge.net/projects/gkernel/). rngd periodically reads
- /dev/hwrng and injects the entropy into /dev/random.
-
config HW_RANDOM_PSERIES
tristate "pSeries HW Random Number Generator support"
- depends on HW_RANDOM && PPC64 && IBMVIO
+ depends on PPC64 && IBMVIO
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -290,9 +281,23 @@ config HW_RANDOM_PSERIES
If unsure, say Y.
+config HW_RANDOM_POWERNV
+ tristate "PowerNV Random Number Generator support"
+ depends on PPC_POWERNV
+ default HW_RANDOM
+ ---help---
+ This is the driver for Random Number Generator hardware found
+ in POWER7+ and above machines for PowerNV platform.
+
+ To compile this driver as a module, choose M here: the
+ module will be called powernv-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_EXYNOS
tristate "EXYNOS HW random number generator support"
- depends on HW_RANDOM && HAS_IOMEM && HAVE_CLK
+ depends on ARCH_EXYNOS
+ default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on EXYNOS SOCs.
@@ -304,7 +309,7 @@ config HW_RANDOM_EXYNOS
config HW_RANDOM_TPM
tristate "TPM HW Random Number Generator support"
- depends on HW_RANDOM && TCG_TPM
+ depends on TCG_TPM
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -314,3 +319,33 @@ config HW_RANDOM_TPM
module will be called tpm-rng.
If unsure, say Y.
+
+config HW_RANDOM_MSM
+ tristate "Qualcomm SoCs Random Number Generator support"
+ depends on HW_RANDOM && ARCH_QCOM
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Qualcomm SoCs.
+
+ To compile this driver as a module, choose M here. the
+ module will be called msm-rng.
+
+ If unsure, say Y.
+
+endif # HW_RANDOM
+
+config UML_RANDOM
+ depends on UML
+ tristate "Hardware random number generator"
+ help
+ This option enables UML's "hardware" random number generator. It
+ attaches itself to the host's /dev/random, supplying as much entropy
+ as the host has, rather than the small amount the UML gets from its
+ own drivers. It registers itself as a standard hardware random number
+ generator, major 10, minor 183, and the canonical device name is
+ /dev/hwrng.
+ The way to make use of this is to install the rng-tools package
+ (check your distro, or download from
+ http://sourceforge.net/projects/gkernel/). rngd periodically reads
+ /dev/hwrng and injects the entropy into /dev/random.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index bed467c9300..199ed283e14 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -15,15 +15,17 @@ n2-rng-y := n2-drv.o n2-asm.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
-obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
+obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
index bf9fc6b7932..851bc7e20ad 100644
--- a/drivers/char/hw_random/atmel-rng.c
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -54,29 +54,22 @@ static int atmel_trng_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
-
trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name))
- return -EBUSY;
-
- trng->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!trng->base)
- return -EBUSY;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ trng->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(trng->base))
+ return PTR_ERR(trng->base);
- trng->clk = clk_get(&pdev->dev, NULL);
+ trng->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(trng->clk))
return PTR_ERR(trng->clk);
ret = clk_enable(trng->clk);
if (ret)
- goto err_enable;
+ return ret;
writel(TRNG_KEY | 1, trng->base + TRNG_CR);
trng->rng.name = pdev->name;
@@ -92,9 +85,6 @@ static int atmel_trng_probe(struct platform_device *pdev)
err_register:
clk_disable(trng->clk);
-err_enable:
- clk_put(trng->clk);
-
return ret;
}
@@ -106,7 +96,6 @@ static int atmel_trng_remove(struct platform_device *pdev)
writel(TRNG_KEY, trng->base + TRNG_CR);
clk_disable(trng->clk);
- clk_put(trng->clk);
return 0;
}
diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c
index 43577ca780e..e900961cdd2 100644
--- a/drivers/char/hw_random/bcm2835-rng.c
+++ b/drivers/char/hw_random/bcm2835-rng.c
@@ -8,7 +8,6 @@
*/
#include <linux/hw_random.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -62,18 +61,18 @@ static int bcm2835_rng_probe(struct platform_device *pdev)
}
bcm2835_rng_ops.priv = (unsigned long)rng_base;
+ /* set warm-up count & enable */
+ __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
+ __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
+
/* register driver */
err = hwrng_register(&bcm2835_rng_ops);
if (err) {
dev_err(dev, "hwrng registration failed\n");
iounmap(rng_base);
- } else {
+ } else
dev_info(dev, "hwrng registered\n");
- /* set warm-up count & enable */
- __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
- __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
- }
return err;
}
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index a0f7724852e..c4419ea1ab0 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/random.h>
#include <asm/uaccess.h>
@@ -55,16 +55,41 @@ static DEFINE_MUTEX(rng_mutex);
static int data_avail;
static u8 *rng_buffer;
+static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
+ int wait);
+
static size_t rng_buffer_size(void)
{
return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES;
}
+static void add_early_randomness(struct hwrng *rng)
+{
+ unsigned char bytes[16];
+ int bytes_read;
+
+ /*
+ * Currently only virtio-rng cannot return data during device
+ * probe, and that's handled in virtio-rng.c itself. If there
+ * are more such devices, this call to rng_get_data can be
+ * made conditional here instead of doing it per-device.
+ */
+ bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+ if (bytes_read > 0)
+ add_device_randomness(bytes, bytes_read);
+}
+
static inline int hwrng_init(struct hwrng *rng)
{
- if (!rng->init)
- return 0;
- return rng->init(rng);
+ if (rng->init) {
+ int ret;
+
+ ret = rng->init(rng);
+ if (ret)
+ return ret;
+ }
+ add_early_randomness(rng);
+ return 0;
}
static inline void hwrng_cleanup(struct hwrng *rng)
@@ -302,7 +327,6 @@ err_misc_dereg:
int hwrng_register(struct hwrng *rng)
{
- int must_register_misc;
int err = -EINVAL;
struct hwrng *old_rng, *tmp;
@@ -327,7 +351,6 @@ int hwrng_register(struct hwrng *rng)
goto out_unlock;
}
- must_register_misc = (current_rng == NULL);
old_rng = current_rng;
if (!old_rng) {
err = hwrng_init(rng);
@@ -336,18 +359,28 @@ int hwrng_register(struct hwrng *rng)
current_rng = rng;
}
err = 0;
- if (must_register_misc) {
+ if (!old_rng) {
err = register_miscdev();
if (err) {
- if (!old_rng) {
- hwrng_cleanup(rng);
- current_rng = NULL;
- }
+ hwrng_cleanup(rng);
+ current_rng = NULL;
goto out_unlock;
}
}
INIT_LIST_HEAD(&rng->list);
list_add_tail(&rng->list, &rng_list);
+
+ if (old_rng && !rng->init) {
+ /*
+ * Use a new device's input to add some randomness to
+ * the system. If this rng device isn't going to be
+ * used right away, its init function hasn't been
+ * called yet; so only use the randomness from devices
+ * that don't need an init callback.
+ */
+ add_early_randomness(rng);
+ }
+
out_unlock:
mutex_unlock(&rng_mutex);
out:
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 402ccfb625c..9f8277cc44b 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -22,7 +22,6 @@
#include <linux/hw_random.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c
new file mode 100644
index 00000000000..148521e51dc
--- /dev/null
+++ b/drivers/char/hw_random/msm-rng.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hw_random.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+/* Device specific register offsets */
+#define PRNG_DATA_OUT 0x0000
+#define PRNG_STATUS 0x0004
+#define PRNG_LFSR_CFG 0x0100
+#define PRNG_CONFIG 0x0104
+
+/* Device specific register masks and config values */
+#define PRNG_LFSR_CFG_MASK 0x0000ffff
+#define PRNG_LFSR_CFG_CLOCKS 0x0000dddd
+#define PRNG_CONFIG_HW_ENABLE BIT(1)
+#define PRNG_STATUS_DATA_AVAIL BIT(0)
+
+#define MAX_HW_FIFO_DEPTH 16
+#define MAX_HW_FIFO_SIZE (MAX_HW_FIFO_DEPTH * 4)
+#define WORD_SZ 4
+
+struct msm_rng {
+ void __iomem *base;
+ struct clk *clk;
+ struct hwrng hwrng;
+};
+
+#define to_msm_rng(p) container_of(p, struct msm_rng, hwrng)
+
+static int msm_rng_enable(struct hwrng *hwrng, int enable)
+{
+ struct msm_rng *rng = to_msm_rng(hwrng);
+ u32 val;
+ int ret;
+
+ ret = clk_prepare_enable(rng->clk);
+ if (ret)
+ return ret;
+
+ if (enable) {
+ /* Enable PRNG only if it is not already enabled */
+ val = readl_relaxed(rng->base + PRNG_CONFIG);
+ if (val & PRNG_CONFIG_HW_ENABLE)
+ goto already_enabled;
+
+ val = readl_relaxed(rng->base + PRNG_LFSR_CFG);
+ val &= ~PRNG_LFSR_CFG_MASK;
+ val |= PRNG_LFSR_CFG_CLOCKS;
+ writel(val, rng->base + PRNG_LFSR_CFG);
+
+ val = readl_relaxed(rng->base + PRNG_CONFIG);
+ val |= PRNG_CONFIG_HW_ENABLE;
+ writel(val, rng->base + PRNG_CONFIG);
+ } else {
+ val = readl_relaxed(rng->base + PRNG_CONFIG);
+ val &= ~PRNG_CONFIG_HW_ENABLE;
+ writel(val, rng->base + PRNG_CONFIG);
+ }
+
+already_enabled:
+ clk_disable_unprepare(rng->clk);
+ return 0;
+}
+
+static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait)
+{
+ struct msm_rng *rng = to_msm_rng(hwrng);
+ size_t currsize = 0;
+ u32 *retdata = data;
+ size_t maxsize;
+ int ret;
+ u32 val;
+
+ /* calculate max size bytes to transfer back to caller */
+ maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max);
+
+ /* no room for word data */
+ if (maxsize < WORD_SZ)
+ return 0;
+
+ ret = clk_prepare_enable(rng->clk);
+ if (ret)
+ return ret;
+
+ /* read random data from hardware */
+ do {
+ val = readl_relaxed(rng->base + PRNG_STATUS);
+ if (!(val & PRNG_STATUS_DATA_AVAIL))
+ break;
+
+ val = readl_relaxed(rng->base + PRNG_DATA_OUT);
+ if (!val)
+ break;
+
+ *retdata++ = val;
+ currsize += WORD_SZ;
+
+ /* make sure we stay on 32bit boundary */
+ if ((maxsize - currsize) < WORD_SZ)
+ break;
+ } while (currsize < maxsize);
+
+ clk_disable_unprepare(rng->clk);
+
+ return currsize;
+}
+
+static int msm_rng_init(struct hwrng *hwrng)
+{
+ return msm_rng_enable(hwrng, 1);
+}
+
+static void msm_rng_cleanup(struct hwrng *hwrng)
+{
+ msm_rng_enable(hwrng, 0);
+}
+
+static int msm_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct msm_rng *rng;
+ int ret;
+
+ rng = devm_kzalloc(&pdev->dev, sizeof(*rng), GFP_KERNEL);
+ if (!rng)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, rng);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rng->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rng->base))
+ return PTR_ERR(rng->base);
+
+ rng->clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(rng->clk))
+ return PTR_ERR(rng->clk);
+
+ rng->hwrng.name = KBUILD_MODNAME,
+ rng->hwrng.init = msm_rng_init,
+ rng->hwrng.cleanup = msm_rng_cleanup,
+ rng->hwrng.read = msm_rng_read,
+
+ ret = hwrng_register(&rng->hwrng);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register hwrng\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int msm_rng_remove(struct platform_device *pdev)
+{
+ struct msm_rng *rng = platform_get_drvdata(pdev);
+
+ hwrng_unregister(&rng->hwrng);
+ return 0;
+}
+
+static const struct of_device_id msm_rng_of_match[] = {
+ { .compatible = "qcom,prng", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_rng_of_match);
+
+static struct platform_driver msm_rng_driver = {
+ .probe = msm_rng_probe,
+ .remove = msm_rng_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(msm_rng_of_match),
+ }
+};
+module_platform_driver(msm_rng_driver);
+
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_AUTHOR("The Linux Foundation");
+MODULE_DESCRIPTION("Qualcomm MSM random number generator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index f9beed54d0c..292a5889f67 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/preempt.h>
@@ -633,7 +632,7 @@ static int n2rng_probe(struct platform_device *op)
multi_capable = (match->data != NULL);
n2rng_driver_version();
- np = kzalloc(sizeof(*np), GFP_KERNEL);
+ np = devm_kzalloc(&op->dev, sizeof(*np), GFP_KERNEL);
if (!np)
goto out;
np->op = op;
@@ -654,7 +653,7 @@ static int n2rng_probe(struct platform_device *op)
&np->hvapi_minor)) {
dev_err(&op->dev, "Cannot register suitable "
"HVAPI version.\n");
- goto out_free;
+ goto out;
}
}
@@ -677,15 +676,16 @@ static int n2rng_probe(struct platform_device *op)
dev_info(&op->dev, "Registered RNG HVAPI major %lu minor %lu\n",
np->hvapi_major, np->hvapi_minor);
- np->units = kzalloc(sizeof(struct n2rng_unit) * np->num_units,
- GFP_KERNEL);
+ np->units = devm_kzalloc(&op->dev,
+ sizeof(struct n2rng_unit) * np->num_units,
+ GFP_KERNEL);
err = -ENOMEM;
if (!np->units)
goto out_hvapi_unregister;
err = n2rng_init_control(np);
if (err)
- goto out_free_units;
+ goto out_hvapi_unregister;
dev_info(&op->dev, "Found %s RNG, units: %d\n",
((np->flags & N2RNG_FLAG_MULTI) ?
@@ -698,7 +698,7 @@ static int n2rng_probe(struct platform_device *op)
err = hwrng_register(&np->hwrng);
if (err)
- goto out_free_units;
+ goto out_hvapi_unregister;
platform_set_drvdata(op, np);
@@ -706,15 +706,9 @@ static int n2rng_probe(struct platform_device *op)
return 0;
-out_free_units:
- kfree(np->units);
- np->units = NULL;
-
out_hvapi_unregister:
sun4v_hvapi_unregister(HV_GRP_RNG);
-out_free:
- kfree(np);
out:
return err;
}
@@ -731,11 +725,6 @@ static int n2rng_remove(struct platform_device *op)
sun4v_hvapi_unregister(HV_GRP_RNG);
- kfree(np->units);
- np->units = NULL;
-
- kfree(np);
-
return 0;
}
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index 232b87fb5fc..9c858157724 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -10,7 +10,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <linux/hw_random.h>
@@ -44,7 +43,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
void __iomem *base;
int ret;
- rng_clk = clk_get(&dev->dev, NULL);
+ rng_clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(rng_clk)) {
dev_err(&dev->dev, "could not get rng clock\n");
ret = PTR_ERR(rng_clk);
@@ -57,33 +56,28 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
if (ret)
goto out_clk;
ret = -ENOMEM;
- base = ioremap(dev->res.start, resource_size(&dev->res));
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
if (!base)
goto out_release;
nmk_rng.priv = (unsigned long)base;
ret = hwrng_register(&nmk_rng);
if (ret)
- goto out_unmap;
+ goto out_release;
return 0;
-out_unmap:
- iounmap(base);
out_release:
amba_release_regions(dev);
out_clk:
clk_disable(rng_clk);
- clk_put(rng_clk);
return ret;
}
static int nmk_rng_remove(struct amba_device *dev)
{
- void __iomem *base = (void __iomem *)nmk_rng.priv;
hwrng_unregister(&nmk_rng);
- iounmap(base);
amba_release_regions(dev);
clk_disable(rng_clk);
- clk_put(rng_clk);
return 0;
}
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c
index f2885dbe184..b5cc3420c65 100644
--- a/drivers/char/hw_random/octeon-rng.c
+++ b/drivers/char/hw_random/octeon-rng.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/hw_random.h>
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 9b89ff4881d..f66ea258382 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -369,10 +369,8 @@ static int omap_rng_probe(struct platform_device *pdev)
int ret;
priv = devm_kzalloc(dev, sizeof(struct omap_rng_dev), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "could not allocate memory\n");
+ if (!priv)
return -ENOMEM;
- };
omap_rng_ops.priv = (unsigned long)priv;
platform_set_drvdata(pdev, priv);
diff --git a/drivers/char/hw_random/omap3-rom-rng.c b/drivers/char/hw_random/omap3-rom-rng.c
new file mode 100644
index 00000000000..6f2eaffed62
--- /dev/null
+++ b/drivers/char/hw_random/omap3-rom-rng.c
@@ -0,0 +1,140 @@
+/*
+ * omap3-rom-rng.c - RNG driver for TI OMAP3 CPU family
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Juha Yrjola <juha.yrjola@solidboot.com>
+ *
+ * Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/hw_random.h>
+#include <linux/timer.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#define RNG_RESET 0x01
+#define RNG_GEN_PRNG_HW_INIT 0x02
+#define RNG_GEN_HW 0x08
+
+/* param1: ptr, param2: count, param3: flag */
+static u32 (*omap3_rom_rng_call)(u32, u32, u32);
+
+static struct timer_list idle_timer;
+static int rng_idle;
+static struct clk *rng_clk;
+
+static void omap3_rom_rng_idle(unsigned long data)
+{
+ int r;
+
+ r = omap3_rom_rng_call(0, 0, RNG_RESET);
+ if (r != 0) {
+ pr_err("reset failed: %d\n", r);
+ return;
+ }
+ clk_disable_unprepare(rng_clk);
+ rng_idle = 1;
+}
+
+static int omap3_rom_rng_get_random(void *buf, unsigned int count)
+{
+ u32 r;
+ u32 ptr;
+
+ del_timer_sync(&idle_timer);
+ if (rng_idle) {
+ clk_prepare_enable(rng_clk);
+ r = omap3_rom_rng_call(0, 0, RNG_GEN_PRNG_HW_INIT);
+ if (r != 0) {
+ clk_disable_unprepare(rng_clk);
+ pr_err("HW init failed: %d\n", r);
+ return -EIO;
+ }
+ rng_idle = 0;
+ }
+
+ ptr = virt_to_phys(buf);
+ r = omap3_rom_rng_call(ptr, count, RNG_GEN_HW);
+ mod_timer(&idle_timer, jiffies + msecs_to_jiffies(500));
+ if (r != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int omap3_rom_rng_data_present(struct hwrng *rng, int wait)
+{
+ return 1;
+}
+
+static int omap3_rom_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ int r;
+
+ r = omap3_rom_rng_get_random(data, 4);
+ if (r < 0)
+ return r;
+ return 4;
+}
+
+static struct hwrng omap3_rom_rng_ops = {
+ .name = "omap3-rom",
+ .data_present = omap3_rom_rng_data_present,
+ .data_read = omap3_rom_rng_data_read,
+};
+
+static int omap3_rom_rng_probe(struct platform_device *pdev)
+{
+ pr_info("initializing\n");
+
+ omap3_rom_rng_call = pdev->dev.platform_data;
+ if (!omap3_rom_rng_call) {
+ pr_err("omap3_rom_rng_call is NULL\n");
+ return -EINVAL;
+ }
+
+ setup_timer(&idle_timer, omap3_rom_rng_idle, 0);
+ rng_clk = devm_clk_get(&pdev->dev, "ick");
+ if (IS_ERR(rng_clk)) {
+ pr_err("unable to get RNG clock\n");
+ return PTR_ERR(rng_clk);
+ }
+
+ /* Leave the RNG in reset state. */
+ clk_prepare_enable(rng_clk);
+ omap3_rom_rng_idle(0);
+
+ return hwrng_register(&omap3_rom_rng_ops);
+}
+
+static int omap3_rom_rng_remove(struct platform_device *pdev)
+{
+ hwrng_unregister(&omap3_rom_rng_ops);
+ clk_disable_unprepare(rng_clk);
+ return 0;
+}
+
+static struct platform_driver omap3_rom_rng_driver = {
+ .driver = {
+ .name = "omap3-rom-rng",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap3_rom_rng_probe,
+ .remove = omap3_rom_rng_remove,
+};
+
+module_platform_driver(omap3_rom_rng_driver);
+
+MODULE_ALIAS("platform:omap3-rom-rng");
+MODULE_AUTHOR("Juha Yrjola");
+MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
index c6df5b29af0..c66279bb6ef 100644
--- a/drivers/char/hw_random/pasemi-rng.c
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <asm/io.h>
diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c
deleted file mode 100644
index 3d4c2293c6f..00000000000
--- a/drivers/char/hw_random/picoxcell-rng.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (c) 2010-2011 Picochip Ltd., Jamie Iles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * All enquiries to support@picochip.com
- */
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/hw_random.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#define DATA_REG_OFFSET 0x0200
-#define CSR_REG_OFFSET 0x0278
-#define CSR_OUT_EMPTY_MASK (1 << 24)
-#define CSR_FAULT_MASK (1 << 1)
-#define TRNG_BLOCK_RESET_MASK (1 << 0)
-#define TAI_REG_OFFSET 0x0380
-
-/*
- * The maximum amount of time in microseconds to spend waiting for data if the
- * core wants us to wait. The TRNG should generate 32 bits every 320ns so a
- * timeout of 20us seems reasonable. The TRNG does builtin tests of the data
- * for randomness so we can't always assume there is data present.
- */
-#define PICO_TRNG_TIMEOUT 20
-
-static void __iomem *rng_base;
-static struct clk *rng_clk;
-static struct device *rng_dev;
-
-static inline u32 picoxcell_trng_read_csr(void)
-{
- return __raw_readl(rng_base + CSR_REG_OFFSET);
-}
-
-static inline bool picoxcell_trng_is_empty(void)
-{
- return picoxcell_trng_read_csr() & CSR_OUT_EMPTY_MASK;
-}
-
-/*
- * Take the random number generator out of reset and make sure the interrupts
- * are masked. We shouldn't need to get large amounts of random bytes so just
- * poll the status register. The hardware generates 32 bits every 320ns so we
- * shouldn't have to wait long enough to warrant waiting for an IRQ.
- */
-static void picoxcell_trng_start(void)
-{
- __raw_writel(0, rng_base + TAI_REG_OFFSET);
- __raw_writel(0, rng_base + CSR_REG_OFFSET);
-}
-
-static void picoxcell_trng_reset(void)
-{
- __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + CSR_REG_OFFSET);
- __raw_writel(TRNG_BLOCK_RESET_MASK, rng_base + TAI_REG_OFFSET);
- picoxcell_trng_start();
-}
-
-/*
- * Get some random data from the random number generator. The hw_random core
- * layer provides us with locking.
- */
-static int picoxcell_trng_read(struct hwrng *rng, void *buf, size_t max,
- bool wait)
-{
- int i;
-
- /* Wait for some data to become available. */
- for (i = 0; i < PICO_TRNG_TIMEOUT && picoxcell_trng_is_empty(); ++i) {
- if (!wait)
- return 0;
-
- udelay(1);
- }
-
- if (picoxcell_trng_read_csr() & CSR_FAULT_MASK) {
- dev_err(rng_dev, "fault detected, resetting TRNG\n");
- picoxcell_trng_reset();
- return -EIO;
- }
-
- if (i == PICO_TRNG_TIMEOUT)
- return 0;
-
- *(u32 *)buf = __raw_readl(rng_base + DATA_REG_OFFSET);
- return sizeof(u32);
-}
-
-static struct hwrng picoxcell_trng = {
- .name = "picoxcell",
- .read = picoxcell_trng_read,
-};
-
-static int picoxcell_trng_probe(struct platform_device *pdev)
-{
- int ret;
- struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- if (!mem) {
- dev_warn(&pdev->dev, "no memory resource\n");
- return -ENOMEM;
- }
-
- if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
- "picoxcell_trng")) {
- dev_warn(&pdev->dev, "unable to request io mem\n");
- return -EBUSY;
- }
-
- rng_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!rng_base) {
- dev_warn(&pdev->dev, "unable to remap io mem\n");
- return -ENOMEM;
- }
-
- rng_clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(rng_clk)) {
- dev_warn(&pdev->dev, "no clk\n");
- return PTR_ERR(rng_clk);
- }
-
- ret = clk_enable(rng_clk);
- if (ret) {
- dev_warn(&pdev->dev, "unable to enable clk\n");
- goto err_enable;
- }
-
- picoxcell_trng_start();
- ret = hwrng_register(&picoxcell_trng);
- if (ret)
- goto err_register;
-
- rng_dev = &pdev->dev;
- dev_info(&pdev->dev, "pixoxcell random number generator active\n");
-
- return 0;
-
-err_register:
- clk_disable(rng_clk);
-err_enable:
- clk_put(rng_clk);
-
- return ret;
-}
-
-static int picoxcell_trng_remove(struct platform_device *pdev)
-{
- hwrng_unregister(&picoxcell_trng);
- clk_disable(rng_clk);
- clk_put(rng_clk);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int picoxcell_trng_suspend(struct device *dev)
-{
- clk_disable(rng_clk);
-
- return 0;
-}
-
-static int picoxcell_trng_resume(struct device *dev)
-{
- return clk_enable(rng_clk);
-}
-
-static const struct dev_pm_ops picoxcell_trng_pm_ops = {
- .suspend = picoxcell_trng_suspend,
- .resume = picoxcell_trng_resume,
-};
-#endif /* CONFIG_PM */
-
-static struct platform_driver picoxcell_trng_driver = {
- .probe = picoxcell_trng_probe,
- .remove = picoxcell_trng_remove,
- .driver = {
- .name = "picoxcell-trng",
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &picoxcell_trng_pm_ops,
-#endif /* CONFIG_PM */
- },
-};
-
-module_platform_driver(picoxcell_trng_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jamie Iles");
-MODULE_DESCRIPTION("Picochip picoXcell TRNG driver");
diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c
new file mode 100644
index 00000000000..3f4f6320456
--- /dev/null
+++ b/drivers/char/hw_random/powernv-rng.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2013 Michael Ellerman, Guo Chao, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/hw_random.h>
+
+static int powernv_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+ unsigned long *buf;
+ int i, len;
+
+ /* We rely on rng_buffer_size() being >= sizeof(unsigned long) */
+ len = max / sizeof(unsigned long);
+
+ buf = (unsigned long *)data;
+
+ for (i = 0; i < len; i++)
+ powernv_get_random_long(buf++);
+
+ return len * sizeof(unsigned long);
+}
+
+static struct hwrng powernv_hwrng = {
+ .name = "powernv-rng",
+ .read = powernv_rng_read,
+};
+
+static int powernv_rng_remove(struct platform_device *pdev)
+{
+ hwrng_unregister(&powernv_hwrng);
+
+ return 0;
+}
+
+static int powernv_rng_probe(struct platform_device *pdev)
+{
+ int rc;
+
+ rc = hwrng_register(&powernv_hwrng);
+ if (rc) {
+ /* We only register one device, ignore any others */
+ if (rc == -EEXIST)
+ rc = -ENODEV;
+
+ return rc;
+ }
+
+ pr_info("Registered powernv hwrng.\n");
+
+ return 0;
+}
+
+static struct of_device_id powernv_rng_match[] = {
+ { .compatible = "ibm,power-rng",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, powernv_rng_match);
+
+static struct platform_driver powernv_rng_driver = {
+ .driver = {
+ .name = "powernv_rng",
+ .of_match_table = powernv_rng_match,
+ },
+ .probe = powernv_rng_probe,
+ .remove = powernv_rng_remove,
+};
+module_platform_driver(powernv_rng_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Bare metal HWRNG driver for POWER7+ and above");
diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c
index 732c330805f..521f76b0934 100644
--- a/drivers/char/hw_random/ppc4xx-rng.c
+++ b/drivers/char/hw_random/ppc4xx-rng.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/hw_random.h>
#include <linux/delay.h>
+#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <asm/io.h>
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
index 5f1197929f0..ab7ffdec0ec 100644
--- a/drivers/char/hw_random/pseries-rng.c
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -17,18 +17,25 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hw_random.h>
#include <asm/vio.h>
-#define MODULE_NAME "pseries-rng"
static int pseries_rng_data_read(struct hwrng *rng, u32 *data)
{
- if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) {
- printk(KERN_ERR "pseries rng hcall error\n");
- return 0;
+ int rc;
+
+ rc = plpar_hcall(H_RANDOM, (unsigned long *)data);
+ if (rc != H_SUCCESS) {
+ pr_err_ratelimited("H_RANDOM call failed %d\n", rc);
+ return -EIO;
}
+
+ /* The hypervisor interface returns 64 bits */
return 8;
}
@@ -47,7 +54,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
};
static struct hwrng pseries_rng = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.data_read = pseries_rng_data_read,
};
@@ -70,7 +77,7 @@ static struct vio_device_id pseries_rng_driver_ids[] = {
MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);
static struct vio_driver pseries_rng_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.probe = pseries_rng_probe,
.remove = pseries_rng_remove,
.get_desired_dma = pseries_rng_get_desired_dma,
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index d2120ba8f3f..b6ab9ac3f34 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -79,7 +79,7 @@ static int timeriomem_rng_data_read(struct hwrng *rng, u32 *data)
priv->expires = cur + delay;
priv->present = 0;
- INIT_COMPLETION(priv->completion);
+ reinit_completion(&priv->completion);
mod_timer(&priv->timer, priv->expires);
return 4;
@@ -118,11 +118,10 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
}
/* Allocate memory for the device structure (and zero it) */
- priv = kzalloc(sizeof(struct timeriomem_rng_private_data), GFP_KERNEL);
- if (!priv) {
- dev_err(&pdev->dev, "failed to allocate device structure.\n");
+ priv = devm_kzalloc(&pdev->dev,
+ sizeof(struct timeriomem_rng_private_data), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- }
platform_set_drvdata(pdev, priv);
@@ -134,17 +133,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
period = i;
else {
dev_err(&pdev->dev, "missing period\n");
- err = -EINVAL;
- goto out_free;
+ return -EINVAL;
}
- } else
+ } else {
period = pdata->period;
+ }
priv->period = usecs_to_jiffies(period);
if (priv->period < 1) {
dev_err(&pdev->dev, "period is less than one jiffy\n");
- err = -EINVAL;
- goto out_free;
+ return -EINVAL;
}
priv->expires = jiffies;
@@ -160,24 +158,16 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
priv->timeriomem_rng_ops.data_read = timeriomem_rng_data_read;
priv->timeriomem_rng_ops.priv = (unsigned long)priv;
- if (!request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev))) {
- dev_err(&pdev->dev, "request_mem_region failed\n");
- err = -EBUSY;
+ priv->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->io_base)) {
+ err = PTR_ERR(priv->io_base);
goto out_timer;
}
- priv->io_base = ioremap(res->start, resource_size(res));
- if (priv->io_base == NULL) {
- dev_err(&pdev->dev, "ioremap failed\n");
- err = -EIO;
- goto out_release_io;
- }
-
err = hwrng_register(&priv->timeriomem_rng_ops);
if (err) {
dev_err(&pdev->dev, "problem registering\n");
- goto out;
+ goto out_timer;
}
dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n",
@@ -185,30 +175,18 @@ static int timeriomem_rng_probe(struct platform_device *pdev)
return 0;
-out:
- iounmap(priv->io_base);
-out_release_io:
- release_mem_region(res->start, resource_size(res));
out_timer:
del_timer_sync(&priv->timer);
-out_free:
- kfree(priv);
return err;
}
static int timeriomem_rng_remove(struct platform_device *pdev)
{
struct timeriomem_rng_private_data *priv = platform_get_drvdata(pdev);
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hwrng_unregister(&priv->timeriomem_rng_ops);
del_timer_sync(&priv->timer);
- iounmap(priv->io_base);
- release_mem_region(res->start, resource_size(res));
- kfree(priv);
return 0;
}
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c