Linus, usually the patches that have already been included in the
-next kernel for a few weeks. The preferred way to submit big changes
is using git (the kernel's source management tool, more information
- can be found at http://git.or.cz/) but plain patches are also just
+ can be found at http://git-scm.com/) but plain patches are also just
fine.
- After two weeks a -rc1 kernel is released it is now possible to push
only patches that do not include new features that could affect the
cpu = smp_processor_id();
++nmi_count(cpu);
- if (!rcu_dereference(nmi_callback)(regs, cpu))
+ if (!rcu_dereference_sched(nmi_callback)(regs, cpu))
default_do_nmi(regs);
nmi_exit();
default_do_nmi() function to handle a machine-specific NMI. Finally,
preemption is restored.
-Strictly speaking, rcu_dereference() is not needed, since this code runs
-only on i386, which does not need rcu_dereference() anyway. However,
-it is a good documentation aid, particularly for anyone attempting to
-do something similar on Alpha.
+In theory, rcu_dereference_sched() is not needed, since this code runs
+only on i386, which in theory does not need rcu_dereference_sched()
+anyway. However, in practice it is a good documentation aid, particularly
+for anyone attempting to do something similar on Alpha or on systems
+with aggressive optimizing compilers.
-Quick Quiz: Why might the rcu_dereference() be necessary on Alpha,
+Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha,
given that the code referenced by the pointer is read-only?
Answer to Quick Quiz
- Why might the rcu_dereference() be necessary on Alpha, given
+ Why might the rcu_dereference_sched() be necessary on Alpha, given
that the code referenced by the pointer is read-only?
Answer: The caller to set_nmi_callback() might well have
- initialized some data that is to be used by the
- new NMI handler. In this case, the rcu_dereference()
- would be needed, because otherwise a CPU that received
- an NMI just after the new handler was set might see
- the pointer to the new NMI handler, but the old
- pre-initialized version of the handler's data.
-
- More important, the rcu_dereference() makes it clear
- to someone reading the code that the pointer is being
- protected by RCU.
+ initialized some data that is to be used by the new NMI
+ handler. In this case, the rcu_dereference_sched() would
+ be needed, because otherwise a CPU that received an NMI
+ just after the new handler was set might see the pointer
+ to the new NMI handler, but the old pre-initialized
+ version of the handler's data.
+
+ This same sad story can happen on other CPUs when using
+ a compiler with aggressive pointer-value speculation
+ optimizations.
+
+ More important, the rcu_dereference_sched() makes it
+ clear to someone reading the code that the pointer is
+ being protected by RCU-sched.
The reason that it is permissible to use RCU list-traversal
primitives when the update-side lock is held is that doing so
can be quite helpful in reducing code bloat when common code is
- shared between readers and updaters.
+ shared between readers and updaters. Additional primitives
+ are provided for this case, as discussed in lockdep.txt.
10. Conversely, if you are in an RCU read-side critical section,
and you don't hold the appropriate update-side lock, you -must-
requiring SRCU's read-side deadlock immunity or low read-side
realtime latency.
- Note that, rcu_assign_pointer() and rcu_dereference() relate to
- SRCU just as they do to other forms of RCU.
+ Note that, rcu_assign_pointer() relates to SRCU just as they do
+ to other forms of RCU.
15. The whole point of call_rcu(), synchronize_rcu(), and friends
is to wait until all pre-existing readers have finished before
srcu_dereference(p, sp):
Check for SRCU read-side critical section.
rcu_dereference_check(p, c):
- Use explicit check expression "c".
+ Use explicit check expression "c". This is useful in
+ code that is invoked by both readers and updaters.
rcu_dereference_raw(p)
Don't check. (Use sparingly, if at all.)
+ rcu_dereference_protected(p, c):
+ Use explicit check expression "c", and omit all barriers
+ and compiler constraints. This is useful when the data
+ structure cannot change, for example, in code that is
+ invoked only by updaters.
+ rcu_access_pointer(p):
+ Return the value of the pointer and omit all barriers,
+ but retain the compiler constraints that prevent duplicating
+ or coalescsing. This is useful when when testing the
+ value of the pointer itself, for example, against NULL.
The rcu_dereference_check() check expression can be any boolean
expression, but would normally include one of the rcu_read_lock_held()
RCU read-side critical sections, in case (2) the ->file_lock prevents
any change from taking place, and finally, in case (3) the current task
is the only task accessing the file_struct, again preventing any change
-from taking place.
+from taking place. If the above statement was invoked only from updater
+code, it could instead be written as follows:
+
+ file = rcu_dereference_protected(fdt->fd[fd],
+ lockdep_is_held(&files->file_lock) ||
+ atomic_read(&files->count) == 1);
+
+This would verify cases #2 and #3 above, and furthermore lockdep would
+complain if this was used in an RCU read-side critical section unless one
+of these two cases held. Because rcu_dereference_protected() omits all
+barriers and compiler constraints, it generates better code than do the
+other flavors of rcu_dereference(). On the other hand, it is illegal
+to use rcu_dereference_protected() if either the RCU-protected pointer
+or the RCU-protected data that it points to can change concurrently.
There are currently only "universal" versions of the rcu_assign_pointer()
and RCU list-/tree-traversal primitives, which do not (yet) check for
init_srcu_struct
cleanup_srcu_struct
+All: lockdep-checked RCU-protected pointer access
+
+ rcu_dereference_check
+ rcu_dereference_protected
+ rcu_access_pointer
+
See the comment headers in the source code (or the docbook generated
from them) for more information.
SYN_MT_REPORT
SYN_REPORT
+Here is the sequence after lifting one of the fingers:
+
+ ABS_MT_POSITION_X
+ ABS_MT_POSITION_Y
+ SYN_MT_REPORT
+ SYN_REPORT
+
+And here is the sequence after lifting the remaining finger:
+
+ SYN_MT_REPORT
+ SYN_REPORT
+
+If the driver reports one of BTN_TOUCH or ABS_PRESSURE in addition to the
+ABS_MT events, the last SYN_MT_REPORT event may be omitted. Otherwise, the
+last SYN_REPORT will be dropped by the input core, resulting in no
+zero-finger event reaching userland.
Event Semantics
---------------
difference between the contact position and the approaching tool position
could be used to derive tilt.
[2] The list can of course be extended.
-[3] The multi-touch X driver is currently in the prototyping stage. At the
-time of writing (April 2009), the MT protocol is not yet merged, and the
-prototype implements finger matching, basic mouse support and two-finger
-scrolling. The project aims at improving the quality of current multi-touch
-functionality available in the Synaptics X driver, and in addition
-implement more advanced gestures.
+[3] Multitouch X driver project: http://bitmath.org/code/multitouch/.
[4] See the section on event computation.
[5] See the section on finger tracking.
amd_iommu= [HW,X86-84]
Pass parameters to the AMD IOMMU driver in the system.
Possible values are:
- isolate - enable device isolation (each device, as far
- as possible, will get its own protection
- domain) [default]
- share - put every device behind one IOMMU into the
- same protection domain
fullflush - enable flushing of IO/TLB entries when
they are unmapped. Otherwise they are
flushed before they will be reused, which
libata.force= [LIBATA] Force configurations. The format is comma
separated list of "[ID:]VAL" where ID is
- PORT[:DEVICE]. PORT and DEVICE are decimal numbers
+ PORT[.DEVICE]. PORT and DEVICE are decimal numbers
matching port, link or device. Basically, it matches
the ATA ID string printed on console by libata. If
the whole ID part is omitted, the last PORT and DEVICE
SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
following control message:
- struct scm_timestamping {
- struct timespec systime;
- struct timespec hwtimetrans;
- struct timespec hwtimeraw;
- };
+
+struct scm_timestamping {
+ struct timespec systime;
+ struct timespec hwtimetrans;
+ struct timespec hwtimeraw;
+};
recvmsg() can be used to get this control message for regular incoming
packets. For send time stamps the outgoing packet is looped back to
SIOCSHWTSTAMP:
Hardware time stamping must also be initialized for each device driver
-that is expected to do hardware time stamping. The parameter is:
+that is expected to do hardware time stamping. The parameter is defined in
+/include/linux/net_tstamp.h as:
struct hwtstamp_config {
- int flags; /* no flags defined right now, must be zero */
- int tx_type; /* HWTSTAMP_TX_* */
- int rx_filter; /* HWTSTAMP_FILTER_* */
+ int flags; /* no flags defined right now, must be zero */
+ int tx_type; /* HWTSTAMP_TX_* */
+ int rx_filter; /* HWTSTAMP_FILTER_* */
};
Desired behavior is passed into the kernel and to a specific device by
/* time stamp any incoming packet */
HWTSTAMP_FILTER_ALL,
- /* return value: time stamp all packets requested plus some others */
- HWTSTAMP_FILTER_SOME,
+ /* return value: time stamp all packets requested plus some others */
+ HWTSTAMP_FILTER_SOME,
/* PTP v1, UDP, any kind of event packet */
HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
- ...
+ /* for the complete list of values, please check
+ * the include file /include/linux/net_tstamp.h
+ */
};
DEVICE IMPLEMENTATION
A driver which supports hardware time stamping must support the
-SIOCSHWTSTAMP ioctl. Time stamps for received packets must be stored
-in the skb with skb_hwtstamp_set().
+SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
+the actual values as described in the section on SIOCSHWTSTAMP.
+
+Time stamps for received packets must be stored in the skb. To get a pointer
+to the shared time stamp structure of the skb call skb_hwtstamps(). Then
+set the time stamps in the structure:
+
+struct skb_shared_hwtstamps {
+ /* hardware time stamp transformed into duration
+ * since arbitrary point in time
+ */
+ ktime_t hwtstamp;
+ ktime_t syststamp; /* hwtstamp transformed to system time base */
+};
Time stamps for outgoing packets are to be generated as follows:
-- In hard_start_xmit(), check if skb_hwtstamp_check_tx_hardware()
- returns non-zero. If yes, then the driver is expected
- to do hardware time stamping.
+- In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero.
+ If yes, then the driver is expected to do hardware time stamping.
- If this is possible for the skb and requested, then declare
- that the driver is doing the time stamping by calling
- skb_hwtstamp_tx_in_progress(). A driver not supporting
- hardware time stamping doesn't do that. A driver must never
- touch sk_buff::tstamp! It is used to store how time stamping
- for an outgoing packets is to be done.
+ that the driver is doing the time stamping by setting the field
+ skb_tx(skb)->in_progress non-zero. You might want to keep a pointer
+ to the associated skb for the next step and not free the skb. A driver
+ not supporting hardware time stamping doesn't do that. A driver must
+ never touch sk_buff::tstamp! It is used to store software generated
+ time stamps by the network subsystem.
- As soon as the driver has sent the packet and/or obtained a
hardware time stamp for it, it passes the time stamp back by
calling skb_hwtstamp_tx() with the original skb, the raw
- hardware time stamp and a handle to the device (necessary
- to convert the hardware time stamp to system time). If obtaining
- the hardware time stamp somehow fails, then the driver should
- not fall back to software time stamping. The rationale is that
- this would occur at a later time in the processing pipeline
- than other software time stamping and therefore could lead
- to unexpected deltas between time stamps.
-- If the driver did not call skb_hwtstamp_tx_in_progress(), then
+ hardware time stamp. skb_hwtstamp_tx() clones the original skb and
+ adds the timestamps, therefore the original skb has to be freed now.
+ If obtaining the hardware time stamp somehow fails, then the driver
+ should not fall back to software time stamping. The rationale is that
+ this would occur at a later time in the processing pipeline than other
+ software time stamping and therefore could lead to unexpected deltas
+ between time stamps.
+- If the driver did not call set skb_tx(skb)->in_progress, then
dev_hard_start_xmit() checks whether software time stamping
is wanted as fallback and potentially generates the time stamp.
- It cannot contain any "trivial" fixes in it (spelling changes,
whitespace cleanups, etc).
- It must follow the Documentation/SubmittingPatches rules.
- - It or an equivalent fix must already exist in Linus' tree. Quote the
- respective commit ID in Linus' tree in your patch submission to -stable.
+ - It or an equivalent fix must already exist in Linus' tree (upstream).
Procedure for submitting patches to the -stable tree:
- Send the patch, after verifying that it follows the above rules, to
- stable@kernel.org.
- - To have the patch automatically included in the stable tree, add the
- the tag
+ stable@kernel.org. You must note the upstream commit ID in the changelog
+ of your submission.
+ - To have the patch automatically included in the stable tree, add the tag
Cc: stable@kernel.org
in the sign-off area. Once the patch is merged it will be applied to
the stable tree without anything else needing to be done by the author
F: drivers/input/mouse/bcm5974.c
APPLE SMC DRIVER
-M: Nicolas Boichat <nicolas@boichat.ch>
-L: mactel-linux-devel@lists.sourceforge.net
+M: Henrik Rydberg <rydberg@euromail.se>
+L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/applesmc.c
DRM DRIVERS
M: David Airlie <airlied@linux.ie>
-L: dri-devel@lists.sourceforge.net
+L: dri-devel@lists.freedesktop.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
S: Maintained
F: drivers/gpu/drm/
S390 ZFCP DRIVER
M: Christof Schmitt <christof.schmitt@de.ibm.com>
-M: Martin Peschke <mp3@de.ibm.com>
+M: Swen Schillig <swen@vnet.ibm.com>
M: linux390@de.ibm.com
L: linux-s390@vger.kernel.org
W: http://www.ibm.com/developerworks/linux/linux390/
S: Supported
-F: Documentation/s390/zfcpdump.txt
F: drivers/s390/scsi/zfcp_*
S390 IUCV NETWORK LAYER
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 34
-EXTRAVERSION = -rc4
-NAME = Man-Eating Seals of Antiquity
+EXTRAVERSION = -rc5
+NAME = Sheep on Meth
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
#define kmap_prot PAGE_KERNEL
-#define flush_cache_kmaps() flush_cache_all()
+#define flush_cache_kmaps() \
+ do { \
+ if (cache_is_vivt()) \
+ flush_cache_all(); \
+ } while (0)
extern pte_t *pkmap_page_table;
extern void *kmap_high_get(struct page *page);
extern void kunmap_high(struct page *page);
+extern void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte);
+extern void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte);
+
+/*
+ * The following functions are already defined by <linux/highmem.h>
+ * when CONFIG_HIGHMEM is not set.
+ */
+#ifdef CONFIG_HIGHMEM
extern void *kmap(struct page *page);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page, enum km_type type);
extern void kunmap_atomic(void *kvaddr, enum km_type type);
extern void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
extern struct page *kmap_atomic_to_page(const void *ptr);
+#endif
#endif
KM_IRQ1,
KM_SOFTIRQ0,
KM_SOFTIRQ1,
+ KM_L1_CACHE,
KM_L2_CACHE,
KM_TYPE_NR
};
#endif /* CONFIG_IWMMXT */
#ifdef CONFIG_VFP
-#if __LINUX_ARM_ARCH__ < 6
-/* For ARM pre-v6, we use fstmiax and fldmiax. This adds one extra
- * word after the registers, and a word of padding at the end for
- * alignment. */
#define VFP_MAGIC 0x56465001
-#define VFP_STORAGE_SIZE 152
-#else
-#define VFP_MAGIC 0x56465002
-#define VFP_STORAGE_SIZE 144
-#endif
struct vfp_sigframe
{
unsigned long magic;
unsigned long size;
- union vfp_state storage;
-};
+ struct user_vfp ufp;
+ struct user_vfp_exc ufp_exc;
+} __attribute__((__aligned__(8)));
+
+/*
+ * 8 byte for magic and size, 264 byte for ufp, 12 bytes for ufp_exc,
+ * 4 bytes padding.
+ */
+#define VFP_STORAGE_SIZE sizeof(struct vfp_sigframe)
+
#endif /* CONFIG_VFP */
/*
#ifdef CONFIG_IWMMXT
struct iwmmxt_sigframe iwmmxt;
#endif
-#if 0 && defined CONFIG_VFP /* Not yet saved. */
+#ifdef CONFIG_VFP
struct vfp_sigframe vfp;
#endif
/* Something that isn't a valid magic number for any coprocessor. */
/*
* User specific VFP registers. If only VFPv2 is present, registers 16 to 31
- * are ignored by the ptrace system call.
+ * are ignored by the ptrace system call and the signal handler.
*/
struct user_vfp {
unsigned long long fpregs[32];
unsigned long fpscr;
};
+/*
+ * VFP exception registers exposed to user space during signal delivery.
+ * Fields not relavant to the current VFP architecture are ignored.
+ */
+struct user_vfp_exc {
+ unsigned long fpexc;
+ unsigned long fpinst;
+ unsigned long fpinst2;
+};
+
#endif /* _ARM_USER_H */
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
#include <asm/unistd.h>
+#include <asm/vfp.h>
#include "ptrace.h"
#include "signal.h"
#endif
+#ifdef CONFIG_VFP
+
+static int preserve_vfp_context(struct vfp_sigframe __user *frame)
+{
+ struct thread_info *thread = current_thread_info();
+ struct vfp_hard_struct *h = &thread->vfpstate.hard;
+ const unsigned long magic = VFP_MAGIC;
+ const unsigned long size = VFP_STORAGE_SIZE;
+ int err = 0;
+
+ vfp_sync_hwstate(thread);
+ __put_user_error(magic, &frame->magic, err);
+ __put_user_error(size, &frame->size, err);
+
+ /*
+ * Copy the floating point registers. There can be unused
+ * registers see asm/hwcap.h for details.
+ */
+ err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs,
+ sizeof(h->fpregs));
+ /*
+ * Copy the status and control register.
+ */
+ __put_user_error(h->fpscr, &frame->ufp.fpscr, err);
+
+ /*
+ * Copy the exception registers.
+ */
+ __put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err);
+ __put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
+ __put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
+
+ return err ? -EFAULT : 0;
+}
+
+static int restore_vfp_context(struct vfp_sigframe __user *frame)
+{
+ struct thread_info *thread = current_thread_info();
+ struct vfp_hard_struct *h = &thread->vfpstate.hard;
+ unsigned long magic;
+ unsigned long size;
+ unsigned long fpexc;
+ int err = 0;
+
+ __get_user_error(magic, &frame->magic, err);
+ __get_user_error(size, &frame->size, err);
+
+ if (err)
+ return -EFAULT;
+ if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
+ return -EINVAL;
+
+ /*
+ * Copy the floating point registers. There can be unused
+ * registers see asm/hwcap.h for details.
+ */
+ err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs,
+ sizeof(h->fpregs));
+ /*
+ * Copy the status and control register.
+ */
+ __get_user_error(h->fpscr, &frame->ufp.fpscr, err);
+
+ /*
+ * Sanitise and restore the exception registers.
+ */
+ __get_user_error(fpexc, &frame->ufp_exc.fpexc, err);
+ /* Ensure the VFP is enabled. */
+ fpexc |= FPEXC_EN;
+ /* Ensure FPINST2 is invalid and the exception flag is cleared. */
+ fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
+ h->fpexc = fpexc;
+
+ __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
+ __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
+
+ if (!err)
+ vfp_flush_hwstate(thread);
+
+ return err ? -EFAULT : 0;
+}
+
+#endif
+
/*
* Do a signal return; undo the signal stack. These are aligned to 64-bit.
*/
err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
-// if (err == 0)
-// err |= vfp_restore_state(&sf->aux.vfp);
+ if (err == 0)
+ err |= restore_vfp_context(&aux->vfp);
#endif
return err;
err |= preserve_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
-// if (err == 0)
-// err |= vfp_save_state(&sf->aux.vfp);
+ if (err == 0)
+ err |= preserve_vfp_context(&aux->vfp);
#endif
__put_user_error(0, &aux->end_magic, err);
obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
- obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91CAP9) += at91cap9.o at91sam926x_time.o at91cap9_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT572D940HF) += at572d940hf.o at91sam926x_time.o at572d940hf_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
orr r3, r3, #(1 << 29) /* bit 29 always set */
str r3, [r1, #(AT91_CKGR_PLLAR - AT91_PMC)]
- wait_pllalock
-
/* Save PLLB setting and disable it */
ldr r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
str r3, .saved_pllbr
mov r3, #AT91_PMC_PLLCOUNT
str r3, [r1, #(AT91_CKGR_PLLBR - AT91_PMC)]
- wait_pllblock
-
/* Turn off the main oscillator */
ldr r3, [r1, #(AT91_CKGR_MOR - AT91_PMC)]
bic r3, r3, #AT91_PMC_MOSCEN
kfrom = kmap_atomic(from, KM_USER0);
kto = kmap_atomic(to, KM_USER1);
copy_page(kto, kfrom);
-#ifdef CONFIG_HIGHMEM
- /*
- * kmap_atomic() doesn't set the page virtual address, and
- * kunmap_atomic() takes care of cache flushing already.
- */
- if (page_address(to) != NULL)
-#endif
- __cpuc_flush_dcache_area(kto, PAGE_SIZE);
+ __cpuc_flush_dcache_area(kto, PAGE_SIZE);
kunmap_atomic(kto, KM_USER1);
kunmap_atomic(kfrom, KM_USER0);
}
vaddr += offset;
op(vaddr, len, dir);
kunmap_high(page);
+ } else if (cache_is_vipt()) {
+ pte_t saved_pte;
+ vaddr = kmap_high_l1_vipt(page, &saved_pte);
+ op(vaddr + offset, len, dir);
+ kunmap_high_l1_vipt(page, saved_pte);
}
} else {
vaddr = page_address(page) + offset;
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
+#include <asm/highmem.h>
#include <asm/smp_plat.h>
#include <asm/system.h>
#include <asm/tlbflush.h>
void __flush_dcache_page(struct address_space *mapping, struct page *page)
{
- void *addr = page_address(page);
-
/*
* Writeback any data associated with the kernel mapping of this
* page. This ensures that data in the physical page is mutually
* coherent with the kernels mapping.
*/
-#ifdef CONFIG_HIGHMEM
- /*
- * kmap_atomic() doesn't set the page virtual address, and
- * kunmap_atomic() takes care of cache flushing already.
- */
- if (addr)
-#endif
- __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ if (!PageHighMem(page)) {
+ __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
+ } else {
+ void *addr = kmap_high_get(page);
+ if (addr) {
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_high(page);
+ } else if (cache_is_vipt()) {
+ pte_t saved_pte;
+ addr = kmap_high_l1_vipt(page, &saved_pte);
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_high_l1_vipt(page, saved_pte);
+ }
+ }
/*
* If this is a page cache page, and we have an aliasing VIPT cache,
unsigned int idx = type + KM_TYPE_NR * smp_processor_id();
if (kvaddr >= (void *)FIXADDR_START) {
- __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
+ if (cache_is_vivt())
+ __cpuc_flush_dcache_area((void *)vaddr, PAGE_SIZE);
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
set_pte_ext(TOP_PTE(vaddr), __pte(0), 0);
pte = TOP_PTE(vaddr);
return pte_page(*pte);
}
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+
+#include <linux/percpu.h>
+
+/*
+ * The VIVT cache of a highmem page is always flushed before the page
+ * is unmapped. Hence unmapped highmem pages need no cache maintenance
+ * in that case.
+ *
+ * However unmapped pages may still be cached with a VIPT cache, and
+ * it is not possible to perform cache maintenance on them using physical
+ * addresses unfortunately. So we have no choice but to set up a temporary
+ * virtual mapping for that purpose.
+ *
+ * Yet this VIPT cache maintenance may be triggered from DMA support
+ * functions which are possibly called from interrupt context. As we don't
+ * want to keep interrupt disabled all the time when such maintenance is
+ * taking place, we therefore allow for some reentrancy by preserving and
+ * restoring the previous fixmap entry before the interrupted context is
+ * resumed. If the reentrancy depth is 0 then there is no need to restore
+ * the previous fixmap, and leaving the current one in place allow it to
+ * be reused the next time without a TLB flush (common with DMA).
+ */
+
+static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth);
+
+void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
+{
+ unsigned int idx, cpu = smp_processor_id();
+ int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+ unsigned long vaddr, flags;
+ pte_t pte, *ptep;
+
+ idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ ptep = TOP_PTE(vaddr);
+ pte = mk_pte(page, kmap_prot);
+
+ if (!in_interrupt())
+ preempt_disable();
+
+ raw_local_irq_save(flags);
+ (*depth)++;
+ if (pte_val(*ptep) == pte_val(pte)) {
+ *saved_pte = pte;
+ } else {
+ *saved_pte = *ptep;
+ set_pte_ext(ptep, pte, 0);
+ local_flush_tlb_kernel_page(vaddr);
+ }
+ raw_local_irq_restore(flags);
+
+ return (void *)vaddr;
+}
+
+void kunmap_high_l1_vipt(struct page *page, pte_t saved_pte)
+{
+ unsigned int idx, cpu = smp_processor_id();
+ int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu);
+ unsigned long vaddr, flags;
+ pte_t pte, *ptep;
+
+ idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ ptep = TOP_PTE(vaddr);
+ pte = mk_pte(page, kmap_prot);
+
+ BUG_ON(pte_val(*ptep) != pte_val(pte));
+ BUG_ON(*depth <= 0);
+
+ raw_local_irq_save(flags);
+ (*depth)--;
+ if (*depth != 0 && pte_val(pte) != pte_val(saved_pte)) {
+ set_pte_ext(ptep, saved_pte, 0);
+ local_flush_tlb_kernel_page(vaddr);
+ }
+ raw_local_irq_restore(flags);
+
+ if (!in_interrupt())
+ preempt_enable();
+}
+
+#endif /* CONFIG_CPU_CACHE_VIPT */
pgd_t *pgd;
int i;
- if (current->mm && current->mm->pgd)
- pgd = current->mm->pgd;
- else
- pgd = init_mm.pgd;
+ /*
+ * We need to access to user-mode page tables here. For kernel threads
+ * we don't have any user-mode mappings so we use the context that we
+ * "borrowed".
+ */
+ pgd = current->active_mm->pgd;
base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
static inline void vfp_pm_init(void) { }
#endif /* CONFIG_PM */
-/*
- * Synchronise the hardware VFP state of a thread other than current with the
- * saved one. This function is used by the ptrace mechanism.
- */
-#ifdef CONFIG_SMP
-void vfp_sync_hwstate(struct thread_info *thread)
-{
-}
-
-void vfp_flush_hwstate(struct thread_info *thread)
-{
- /*
- * On SMP systems, the VFP state is automatically saved at every
- * context switch. We mark the thread VFP state as belonging to a
- * non-existent CPU so that the saved one will be reloaded when
- * needed.
- */
- thread->vfpstate.hard.cpu = NR_CPUS;
-}
-#else
void vfp_sync_hwstate(struct thread_info *thread)
{
unsigned int cpu = get_cpu();
last_VFP_context[cpu] = NULL;
}
+#ifdef CONFIG_SMP
+ /*
+ * For SMP we still have to take care of the case where the thread
+ * migrates to another CPU and then back to the original CPU on which
+ * the last VFP user is still the same thread. Mark the thread VFP
+ * state as belonging to a non-existent CPU so that the saved one will
+ * be reloaded in the above case.
+ */
+ thread->vfpstate.hard.cpu = NR_CPUS;
+#endif
put_cpu();
}
-#endif
#include <linux/smp.h>
{
struct kvm_memory_slot *memslot;
int r, i;
- long n, base;
+ long base;
+ unsigned long n;
unsigned long *dirty_bitmap = (unsigned long *)(kvm->arch.vm_base +
offsetof(struct kvm_vm_data, kvm_mem_dirty_log));
if (!memslot->dirty_bitmap)
goto out;
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ n = kvm_dirty_bitmap_bytes(memslot);
base = memslot->base_gfn / BITS_PER_LONG;
for (i = 0; i < n/sizeof(long); ++i) {
struct kvm_dirty_log *log)
{
int r;
- int n;
+ unsigned long n;
struct kvm_memory_slot *memslot;
int is_dirty = 0;
if (is_dirty) {
kvm_flush_remote_tlbs(kvm);
memslot = &kvm->memslots->memslots[log->slot];
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ n = kvm_dirty_bitmap_bytes(memslot);
memset(memslot->dirty_bitmap, 0, n);
}
r = 0;
static inline int atomic_sub_and_test(int i, atomic_t *v)
{
char c;
- __asm__ __volatile__("subl %2,%1; seq %0" : "=d" (c), "+m" (*v): "g" (i));
+ __asm__ __volatile__("subl %2,%1; seq %0"
+ : "=d" (c), "+m" (*v)
+ : "id" (i));
return c != 0;
}
static inline int atomic_add_negative(int i, atomic_t *v)
{
char c;
- __asm__ __volatile__("addl %2,%1; smi %0" : "=d" (c), "+m" (*v): "g" (i));
+ __asm__ __volatile__("addl %2,%1; smi %0"
+ : "=d" (c), "+m" (*v)
+ : "id" (i));
return c != 0;
}
#define MCFUART_URF_RXS 0xc0 /* Receiver status */
#endif
+#if defined(CONFIG_M5272)
+#define MCFUART_TXFIFOSIZE 25
+#else
+#define MCFUART_TXFIFOSIZE 1
+#endif
/****************************************************************************/
#endif /* mcfuart_h */
#ifndef __uClinux__
# ifdef __mcoldfire__
unsigned long sc_fpregs[2][2]; /* room for two fp registers */
- unsigned long sc_fpcntl[3];
- unsigned char sc_fpstate[16+6*8];
# else
unsigned long sc_fpregs[2*3]; /* room for two fp registers */
+# endif
unsigned long sc_fpcntl[3];
unsigned char sc_fpstate[216];
-# endif
#endif
};
cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307)
cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200)
cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307)
-cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5271,-m5200)
+cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307)
cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307)
cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307)
cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200)
trap #0
ENTRY(ret_from_user_rt_signal)
- move #__NR_rt_sigreturn,%d0
+ movel #__NR_rt_sigreturn,%d0
trap #0
_ramvec[vba+CPMVEC_PIO_PC7] = inthandler; /* pio - pc7 */
_ramvec[vba+CPMVEC_PIO_PC6] = inthandler; /* pio - pc6 */
_ramvec[vba+CPMVEC_TIMER3] = inthandler; /* timer 3 */
- _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* reserved */
_ramvec[vba+CPMVEC_PIO_PC5] = inthandler; /* pio - pc5 */
_ramvec[vba+CPMVEC_PIO_PC4] = inthandler; /* pio - pc4 */
_ramvec[vba+CPMVEC_RESERVED2] = inthandler; /* reserved */
struct kvm_vcpu *vcpu;
ulong ga, ga_end;
int is_dirty = 0;
- int r, n;
+ int r;
+ unsigned long n;
mutex_lock(&kvm->slots_lock);
kvm_for_each_vcpu(n, vcpu, kvm)
kvmppc_mmu_pte_pflush(vcpu, ga, ga_end);
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ n = kvm_dirty_bitmap_bytes(memslot);
memset(memslot->dirty_bitmap, 0, n);
}
__u32 tz_minuteswest; /* Minutes west of Greenwich 0x30 */
__u32 tz_dsttime; /* Type of dst correction 0x34 */
__u32 ectg_available;
+ __u32 ntp_mult; /* NTP adjusted multiplier 0x3C */
};
struct vdso_per_cpu_data {
DEFINE(__VDSO_WTOM_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
DEFINE(__VDSO_TIMEZONE, offsetof(struct vdso_data, tz_minuteswest));
DEFINE(__VDSO_ECTG_OK, offsetof(struct vdso_data, ectg_available));
+ DEFINE(__VDSO_NTP_MULT, offsetof(struct vdso_data, ntp_mult));
DEFINE(__VDSO_ECTG_BASE, offsetof(struct vdso_per_cpu_data, ectg_timer_base));
DEFINE(__VDSO_ECTG_USER, offsetof(struct vdso_per_cpu_data, ectg_user_time));
/* constants used by the vdso */
lghi %r2,0
brasl %r14,arch_set_page_states
+ /* Reinitialize the channel subsystem */
+ brasl %r14,channel_subsystem_reinit
+
/* Return 0 */
lmg %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
lghi %r2,0
vdso_data->xtime_clock_nsec = wall_time->tv_nsec;
vdso_data->wtom_clock_sec = wall_to_monotonic.tv_sec;
vdso_data->wtom_clock_nsec = wall_to_monotonic.tv_nsec;
+ vdso_data->ntp_mult = mult;
smp_wmb();
++vdso_data->tb_update_count;
}
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
brc 3,2f
ahi %r0,-1
-2: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */
+2: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
lr %r2,%r0
- lhi %r0,1000
+ l %r0,__VDSO_NTP_MULT(%r5)
ltr %r1,%r1
mr %r0,%r0
jnm 3f
- ahi %r0,1000
+ a %r0,__VDSO_NTP_MULT(%r5)
3: alr %r0,%r2
srdl %r0,12
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
brc 3,12f
ahi %r0,-1
-12: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */
+12: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
lr %r2,%r0
- lhi %r0,1000
+ l %r0,__VDSO_NTP_MULT(%r5)
ltr %r1,%r1
mr %r0,%r0
jnm 13f
- ahi %r0,1000
+ a %r0,__VDSO_NTP_MULT(%r5)
13: alr %r0,%r2
srdl %r0,12
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
sl %r1,__VDSO_XTIME_STAMP+4(%r5)
brc 3,3f
ahi %r0,-1
-3: mhi %r0,1000 /* cyc2ns(clock,cycle_delta) */
+3: ms %r0,__VDSO_NTP_MULT(%r5) /* cyc2ns(clock,cycle_delta) */
st %r0,24(%r15)
- lhi %r0,1000
+ l %r0,__VDSO_NTP_MULT(%r5)
ltr %r1,%r1
mr %r0,%r0
jnm 4f
- ahi %r0,1000
+ a %r0,__VDSO_NTP_MULT(%r5)
4: al %r0,24(%r15)
srdl %r0,12
al %r0,__VDSO_XTIME_NSEC(%r5) /* + xtime */
stck 48(%r15) /* Store TOD clock */
lg %r1,48(%r15)
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
- mghi %r1,1000
+ msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
lg %r0,__VDSO_XTIME_SEC(%r5)
stck 48(%r15) /* Store TOD clock */
lg %r1,48(%r15)
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
- mghi %r1,1000
+ msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime */
lg %r0,__VDSO_XTIME_SEC(%r5)
stck 48(%r15) /* Store TOD clock */
lg %r1,48(%r15)
sg %r1,__VDSO_XTIME_STAMP(%r5) /* TOD - cycle_last */
- mghi %r1,1000
+ msgf %r1,__VDSO_NTP_MULT(%r5) /* * NTP adjustment */
srlg %r1,%r1,12 /* cyc2ns(clock,cycle_delta) */
alg %r1,__VDSO_XTIME_NSEC(%r5) /* + xtime.tv_nsec */
lg %r0,__VDSO_XTIME_SEC(%r5) /* xtime.tv_sec */
def_bool 64BIT
select ARCH_SUPPORTS_MSI
select HAVE_FUNCTION_TRACER
+ select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_FUNCTION_GRAPH_FP_TEST
+ select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_KRETPROBES
select HAVE_KPROBES
select HAVE_LMB
bool "D-cache flush debugging"
depends on SPARC64 && DEBUG_KERNEL
-config STACK_DEBUG
- bool "Stack Overflow Detection Support"
-
config MCOUNT
bool
depends on SPARC64
- depends on STACK_DEBUG || FUNCTION_TRACER
+ depends on FUNCTION_TRACER
default y
config FRAME_POINTER
unsigned int __nmi_count;
unsigned long clock_tick; /* %tick's per second */
unsigned long __pad;
- unsigned int __pad1;
+ unsigned int irq0_irqs;
unsigned int __pad2;
/* Dcache line 2, rarely used */
*/
static inline unsigned long __raw_local_irq_save(void)
{
- unsigned long flags = __raw_local_save_flags();
-
- raw_local_irq_disable();
+ unsigned long flags, tmp;
+
+ /* Disable interrupts to PIL_NORMAL_MAX unless we already
+ * are using PIL_NMI, in which case PIL_NMI is retained.
+ *
+ * The only values we ever program into the %pil are 0,
+ * PIL_NORMAL_MAX and PIL_NMI.
+ *
+ * Since PIL_NMI is the largest %pil value and all bits are
+ * set in it (0xf), it doesn't matter what PIL_NORMAL_MAX
+ * actually is.
+ */
+ __asm__ __volatile__(
+ "rdpr %%pil, %0\n\t"
+ "or %0, %2, %1\n\t"
+ "wrpr %1, 0x0, %%pil"
+ : "=r" (flags), "=r" (tmp)
+ : "i" (PIL_NORMAL_MAX)
+ : "memory"
+ );
return flags;
}
#define THREAD_SHIFT PAGE_SHIFT
#endif /* PAGE_SHIFT == 13 */
-#define PREEMPT_ACTIVE 0x4000000
+#define PREEMPT_ACTIVE 0x10000000
/*
* macros/functions for gaining access to the thread information structure
CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS)
extra-y += vmlinux.lds
+ifdef CONFIG_FUNCTION_TRACER
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o := -pg
+CFLAGS_REMOVE_time_$(BITS).o := -pg
+CFLAGS_REMOVE_perf_event.o := -pg
+CFLAGS_REMOVE_pcr.o := -pg
+endif
+
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
obj-$(CONFIG_SPARC32) += etrap_32.o
obj-$(CONFIG_SPARC32) += rtrap_32.o
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
-CFLAGS_REMOVE_ftrace.o := -pg
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_EARLYFB) += btext.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
{
- static u32 call;
+ u32 call;
s32 off;
off = ((s32)addr - (s32)ip);
return 0;
}
#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ unsigned long ip = (unsigned long)(&ftrace_graph_call);
+ u32 old, new;
+
+ old = *(u32 *) &ftrace_graph_call;
+ new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller);
+ return ftrace_modify_code(ip, old, new);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ unsigned long ip = (unsigned long)(&ftrace_graph_call);
+ u32 old, new;
+
+ old = *(u32 *) &ftrace_graph_call;
+ new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub);
+
+ return ftrace_modify_code(ip, old, new);
+}
+
+#endif /* !CONFIG_DYNAMIC_FTRACE */
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+unsigned long prepare_ftrace_return(unsigned long parent,
+ unsigned long self_addr,
+ unsigned long frame_pointer)
+{
+ unsigned long return_hooker = (unsigned long) &return_to_handler;
+ struct ftrace_graph_ent trace;
+
+ if (unlikely(atomic_read(¤t->tracing_graph_pause)))
+ return parent + 8UL;
+
+ if (ftrace_push_return_trace(parent, self_addr, &trace.depth,
+ frame_pointer) == -EBUSY)
+ return parent + 8UL;
+
+ trace.func = self_addr;
+
+ /* Only trace if the calling function expects to */
+ if (!ftrace_graph_entry(&trace)) {
+ current->curr_ret_stack--;
+ return parent + 8UL;
+ }
+
+ return return_hooker;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/ftrace.h>
#include <linux/irq.h>
+#include <linux/kmemleak.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
#include "entry.h"
#include "cpumap.h"
+#include "kstack.h"
#define NUM_IVECS (IMAP_INR + 1)
bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
if (unlikely(!bucket))
return 0;
+
+ /* The only reference we store to the IRQ bucket is
+ * by physical address which kmemleak can't see, tell
+ * it that this object explicitly is not a leak and
+ * should be scanned.
+ */
+ kmemleak_not_leak(bucket);
+
__flush_dcache_range((unsigned long) bucket,
((unsigned long) bucket +
sizeof(struct ino_bucket)));
void *hardirq_stack[NR_CPUS];
void *softirq_stack[NR_CPUS];
-static __attribute__((always_inline)) void *set_hardirq_stack(void)
-{
- void *orig_sp, *sp = hardirq_stack[smp_processor_id()];
-
- __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
- if (orig_sp < sp ||
- orig_sp > (sp + THREAD_SIZE)) {
- sp += THREAD_SIZE - 192 - STACK_BIAS;
- __asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
- }
-
- return orig_sp;
-}
-static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
-{
- __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
-}
-
-void handler_irq(int irq, struct pt_regs *regs)
+void __irq_entry handler_irq(int irq, struct pt_regs *regs)
{
unsigned long pstate, bucket_pa;
struct pt_regs *old_regs;
#include <linux/kgdb.h>
#include <linux/kdebug.h>
+#include <linux/ftrace.h>
#include <asm/kdebug.h>
#include <asm/ptrace.h>
}
#ifdef CONFIG_SMP
-void smp_kgdb_capture_client(int irq, struct pt_regs *regs)
+void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs)
{
unsigned long flags;
}
+static inline __attribute__((always_inline)) void *set_hardirq_stack(void)
+{
+ void *orig_sp, *sp = hardirq_stack[smp_processor_id()];
+
+ __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
+ if (orig_sp < sp ||
+ orig_sp > (sp + THREAD_SIZE)) {
+ sp += THREAD_SIZE - 192 - STACK_BIAS;
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
+ }
+
+ return orig_sp;
+}
+
+static inline __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
+{
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
+}
+
#endif /* _KSTACK_H */
#include <asm/ptrace.h>
#include <asm/pcr.h>
+#include "kstack.h"
+
/* We don't have a real NMI on sparc64, but we can fake one
* up using profiling counter overflow interrupts and interrupt
* levels.
notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs)
{
unsigned int sum, touched = 0;
- int cpu = smp_processor_id();
+ void *orig_sp;
clear_softint(1 << irq);
nmi_enter();
+ orig_sp = set_hardirq_stack();
+
if (notify_die(DIE_NMI, "nmi", regs, 0,
pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP)
touched = 1;
else
pcr_ops->write(PCR_PIC_PRIV);
- sum = kstat_irqs_cpu(0, cpu);
+ sum = local_cpu_data().irq0_irqs;
if (__get_cpu_var(nmi_touch)) {
__get_cpu_var(nmi_touch) = 0;
touched = 1;
pcr_ops->write(pcr_enable);
}
+ restore_hardirq_stack(orig_sp);
+
nmi_exit();
}
struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL);
if (!rp) {
- prom_printf("Cannot allocate IOMMU resource.\n");
- prom_halt();
+ pr_info("%s: Cannot allocate IOMMU resource.\n",
+ pbm->name);
+ return;
}
rp->name = "IOMMU";
rp->start = pbm->mem_space.start + (unsigned long) vdma[0];
rp->end = rp->start + (unsigned long) vdma[1] - 1UL;
rp->flags = IORESOURCE_BUSY;
- request_resource(&pbm->mem_space, rp);
+ if (request_resource(&pbm->mem_space, rp)) {
+ pr_info("%s: Unable to request IOMMU resource.\n",
+ pbm->name);
+ kfree(rp);
+ }
}
}
#include <linux/irq.h>
#include <linux/perf_event.h>
+#include <linux/ftrace.h>
#include <asm/pil.h>
#include <asm/pcr.h>
* Therefore in such situations we defer the work by signalling
* a lower level cpu IRQ.
*/
-void deferred_pcr_work_irq(int irq, struct pt_regs *regs)
+void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs;
nop
call trace_hardirqs_on
nop
- wrpr %l4, %pil
+ /* Do not actually set the %pil here. We will do that
+ * below after we clear PSTATE_IE in the %pstate register.
+ * If we re-enable interrupts here, we can recurse down
+ * the hardirq stack potentially endlessly, causing a
+ * stack overflow.
+ *
+ * It is tempting to put this test and trace_hardirqs_on
+ * call at the 'rt_continue' label, but that will not work
+ * as that path hits unconditionally and we do not want to
+ * execute this in NMI return paths, for example.
+ */
#endif
rtrap_no_irq_enable:
andcc %l1, TSTATE_PRIV, %l3
#include <linux/profile.h>
#include <linux/bootmem.h>
#include <linux/vmalloc.h>
+#include <linux/ftrace.h>
#include <linux/cpu.h>
#include <linux/slab.h>
&cpumask_of_cpu(cpu));
}
-void smp_call_function_client(int irq, struct pt_regs *regs)
+void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
generic_smp_call_function_interrupt();
}
-void smp_call_function_single_client(int irq, struct pt_regs *regs)
+void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
generic_smp_call_function_single_interrupt();
put_cpu();
}
-void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
+void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
{
struct mm_struct *mm;
unsigned long flags;
*/
extern void prom_world(int);
-void smp_penguin_jailcell(int irq, struct pt_regs *regs)
+void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
&cpumask_of_cpu(cpu));
}
-void smp_receive_signal_client(int irq, struct pt_regs *regs)
+void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
}
#include <linux/clocksource.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
+#include <linux/ftrace.h>
#include <asm/oplib.h>
#include <asm/timer.h>
};
static DEFINE_PER_CPU(struct clock_event_device, sparc64_events);
-void timer_interrupt(int irq, struct pt_regs *regs)
+void __irq_entry timer_interrupt(int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long tick_mask = tick_ops->softint_mask;
irq_enter();
+ local_cpu_data().irq0_irqs++;
kstat_incr_irqs_this_cpu(0, irq_to_desc(0));
if (unlikely(!evt->event_handler)) {
EXPORT_SYMBOL(dump_stack);
-static inline int is_kernel_stack(struct task_struct *task,
- struct reg_window *rw)
-{
- unsigned long rw_addr = (unsigned long) rw;
- unsigned long thread_base, thread_end;
-
- if (rw_addr < PAGE_OFFSET) {
- if (task != &init_task)
- return 0;
- }
-
- thread_base = (unsigned long) task_stack_page(task);
- thread_end = thread_base + sizeof(union thread_union);
- if (rw_addr >= thread_base &&
- rw_addr < thread_end &&
- !(rw_addr & 0x7UL))
- return 1;
-
- return 0;
-}
-
static inline struct reg_window *kernel_stack_up(struct reg_window *rw)
{
unsigned long fp = rw->ins[6];
show_regs(regs);
add_taint(TAINT_DIE);
if (regs->tstate & TSTATE_PRIV) {
+ struct thread_info *tp = current_thread_info();
struct reg_window *rw = (struct reg_window *)
(regs->u_regs[UREG_FP] + STACK_BIAS);
* find some badly aligned kernel stack.
*/
while (rw &&
- count++ < 30&&
- is_kernel_stack(current, rw)) {
+ count++ < 30 &&
+ kstack_valid(tp, (unsigned long) rw)) {
printk("Caller[%016lx]: %pS\n", rw->ins[7],
(void *) rw->ins[7]);
}
/* 16 = double-word, 8 = extra-word, 4 = word, 2 = half-word */
-static inline int decode_access_size(unsigned int insn)
+static inline int decode_access_size(struct pt_regs *regs, unsigned int insn)
{
unsigned int tmp;
return 2;
else {
printk("Impossible unaligned trap. insn=%08x\n", insn);
- die_if_kernel("Byte sized unaligned access?!?!", current_thread_info()->kregs);
+ die_if_kernel("Byte sized unaligned access?!?!", regs);
/* GCC should never warn that control reaches the end
* of this function without returning a value because
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
enum direction dir = decode_direction(insn);
- int size = decode_access_size(insn);
+ int size = decode_access_size(regs, insn);
int orig_asi, asi;
current_thread_info()->kern_una_regs = regs;
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
+ IRQENTRY_TEXT
*(.gnu.warning)
} = 0
_etext = .;
RO_DATA(PAGE_SIZE)
+
+ /* Start of data section */
+ _sdata = .;
+
.data1 : {
*(.data1)
}
#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm/thread_info.h>
-
/*
* This is the main variant and is called by C code. GCC's -pg option
* automatically instruments every C function with a call to this.
*/
-#ifdef CONFIG_STACK_DEBUG
-
-#define OVSTACKSIZE 4096 /* lets hope this is enough */
-
- .data
- .align 8
-panicstring:
- .asciz "Stack overflow\n"
- .align 8
-ovstack:
- .skip OVSTACKSIZE
-#endif
.text
.align 32
.globl _mcount
.type mcount,#function
_mcount:
mcount:
-#ifdef CONFIG_STACK_DEBUG
- /*
- * Check whether %sp is dangerously low.
- */
- ldub [%g6 + TI_FPDEPTH], %g1
- srl %g1, 1, %g3
- add %g3, 1, %g3
- sllx %g3, 8, %g3 ! each fpregs frame is 256b
- add %g3, 192, %g3
- add %g6, %g3, %g3 ! where does task_struct+frame end?
- sub %g3, STACK_BIAS, %g3
- cmp %sp, %g3
- bg,pt %xcc, 1f
- nop
- lduh [%g6 + TI_CPU], %g1
- sethi %hi(hardirq_stack), %g3
- or %g3, %lo(hardirq_stack), %g3
- sllx %g1, 3, %g1
- ldx [%g3 + %g1], %g7
- sub %g7, STACK_BIAS, %g7
- cmp %sp, %g7
- bleu,pt %xcc, 2f
- sethi %hi(THREAD_SIZE), %g3
- add %g7, %g3, %g7
- cmp %sp, %g7
- blu,pn %xcc, 1f
-2: sethi %hi(softirq_stack), %g3
- or %g3, %lo(softirq_stack), %g3
- ldx [%g3 + %g1], %g7
- sub %g7, STACK_BIAS, %g7
- cmp %sp, %g7
- bleu,pt %xcc, 3f
- sethi %hi(THREAD_SIZE), %g3
- add %g7, %g3, %g7
- cmp %sp, %g7
- blu,pn %xcc, 1f
- nop
- /* If we are already on ovstack, don't hop onto it
- * again, we are already trying to output the stack overflow
- * message.
- */
-3: sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough
- or %g7, %lo(ovstack), %g7
- add %g7, OVSTACKSIZE, %g3
- sub %g3, STACK_BIAS + 192, %g3
- sub %g7, STACK_BIAS, %g7
- cmp %sp, %g7
- blu,pn %xcc, 2f
- cmp %sp, %g3
- bleu,pn %xcc, 1f
- nop
-2: mov %g3, %sp
- sethi %hi(panicstring), %g3
- call prom_printf
- or %g3, %lo(panicstring), %o0
- call prom_halt
- nop
-1:
-#endif
#ifdef CONFIG_FUNCTION_TRACER
#ifdef CONFIG_DYNAMIC_FTRACE
- mov %o7, %o0
- .globl mcount_call
-mcount_call:
- call ftrace_stub
- mov %o0, %o7
+ /* Do nothing, the retl/nop below is all we need. */
#else
- sethi %hi(ftrace_trace_function), %g1
+ sethi %hi(function_trace_stop), %g1
+ lduw [%g1 + %lo(function_trace_stop)], %g2
+ brnz,pn %g2, 2f
+ sethi %hi(ftrace_trace_function), %g1
sethi %hi(ftrace_stub), %g2
ldx [%g1 + %lo(ftrace_trace_function)], %g1
or %g2, %lo(ftrace_stub), %g2
cmp %g1, %g2
be,pn %icc, 1f
- mov %i7, %o1
- jmpl %g1, %g0
- mov %o7, %o0
+ mov %i7, %g3
+ save %sp, -176, %sp
+ mov %g3, %o1
+ jmpl %g1, %o7
+ mov %i7, %o0
+ ret
+ restore
/* not reached */
1:
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ sethi %hi(ftrace_graph_return), %g1
+ ldx [%g1 + %lo(ftrace_graph_return)], %g3
+ cmp %g2, %g3
+ bne,pn %xcc, 5f
+ sethi %hi(ftrace_graph_entry_stub), %g2
+ sethi %hi(ftrace_graph_entry), %g1
+ or %g2, %lo(ftrace_graph_entry_stub), %g2
+ ldx [%g1 + %lo(ftrace_graph_entry)], %g1
+ cmp %g1, %g2
+ be,pt %xcc, 2f
+ nop
+5: mov %i7, %g2
+ mov %fp, %g3
+ save %sp, -176, %sp
+ mov %g2, %l0
+ ba,pt %xcc, ftrace_graph_caller
+ mov %g3, %l1
+#endif
+2:
#endif
#endif
retl
.globl ftrace_caller
.type ftrace_caller,#function
ftrace_caller:
- mov %i7, %o1
- mov %o7, %o0
+ sethi %hi(function_trace_stop), %g1
+ mov %i7, %g2
+ lduw [%g1 + %lo(function_trace_stop)], %g1
+ brnz,pn %g1, ftrace_stub
+ mov %fp, %g3
+ save %sp, -176, %sp
+ mov %g2, %o1
+ mov %g2, %l0
+ mov %g3, %l1
.globl ftrace_call
ftrace_call:
call ftrace_stub
- mov %o0, %o7
- retl
+ mov %i7, %o0
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .globl ftrace_graph_call
+ftrace_graph_call:
+ call ftrace_stub
nop
+#endif
+ ret
+ restore
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .size ftrace_graph_call,.-ftrace_graph_call
+#endif
+ .size ftrace_call,.-ftrace_call
.size ftrace_caller,.-ftrace_caller
#endif
#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(ftrace_graph_caller)
+ mov %l0, %o0
+ mov %i7, %o1
+ call prepare_ftrace_return
+ mov %l1, %o2
+ ret
+ restore %o0, -8, %i7
+END(ftrace_graph_caller)
+
+ENTRY(return_to_handler)
+ save %sp, -176, %sp
+ call ftrace_return_to_handler
+ mov %fp, %o0
+ jmpl %o0 + 8, %g0
+ restore
+END(return_to_handler)
+#endif
#include "linux/irqreturn.h"
#include "linux/kd.h"
#include "linux/sched.h"
+#include "linux/slab.h"
#include "chan_kern.h"
#include "irq_kern.h"
#include "irq_user.h"
#include <errno.h>
#include <sched.h>
#include <linux/limits.h>
-#include <linux/slab.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include "kern_constants.h"
.quad stub32_sigreturn
.quad stub32_clone /* 120 */
.quad sys_setdomainname
- .quad sys_uname
+ .quad sys_newuname
.quad sys_modify_ldt
.quad compat_sys_adjtimex
.quad sys32_mprotect /* 125 */
#define _ASM_X86_AMD_IOMMU_TYPES_H
#include <linux/types.h>
+#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/spinlock.h>
/* constants to configure the command buffer */
#define CMD_BUFFER_SIZE 8192
+#define CMD_BUFFER_UNINITIALIZED 1
#define CMD_BUFFER_ENTRIES 512
#define MMIO_CMD_SIZE_SHIFT 56
#define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT)
struct list_head list; /* for list of all protection domains */
struct list_head dev_list; /* List of all devices in this domain */
spinlock_t lock; /* mostly used to lock the page table*/
+ struct mutex api_lock; /* protect page tables in the iommu-api path */
u16 id; /* the domain id written to the device table */
int mode; /* paging mode (0-6 levels) */
u64 *pt_root; /* page table root pointer */
#ifndef __ASSEMBLY__
#include <asm/hw_irq.h>
-#include <asm/kvm_para.h>
/*G:030
* But first, how does our Guest contact the Host to ask for privileged
* operations? There are two ways: the direct way is to make a "hypercall",
* to make requests of the Host Itself.
*
- * We use the KVM hypercall mechanism, though completely different hypercall
- * numbers. Seventeen hypercalls are available: the hypercall number is put in
- * the %eax register, and the arguments (when required) are placed in %ebx,
- * %ecx, %edx and %esi. If a return value makes sense, it's returned in %eax.
+ * Our hypercall mechanism uses the highest unused trap code (traps 32 and
+ * above are used by real hardware interrupts). Seventeen hypercalls are
+ * available: the hypercall number is put in the %eax register, and the
+ * arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
+ * If a return value makes sense, it's returned in %eax.
*
* Grossly invalid calls result in Sudden Death at the hands of the vengeful
* Host, rather than returning failure. This reflects Winston Churchill's
* definition of a gentleman: "someone who is only rude intentionally".
-:*/
+ */
+static inline unsigned long
+hcall(unsigned long call,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4)
+{
+ /* "int" is the Intel instruction to trigger a trap. */
+ asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
+ /* The call in %eax (aka "a") might be overwritten */
+ : "=a"(call)
+ /* The arguments are in %eax, %ebx, %ecx, %edx & %esi */
+ : "a"(call), "b"(arg1), "c"(arg2), "d"(arg3), "S"(arg4)
+ /* "memory" means this might write somewhere in memory.
+ * This isn't true for all calls, but it's safe to tell
+ * gcc that it might happen so it doesn't get clever. */
+ : "memory");
+ return call;
+}
/* Can't use our min() macro here: needs to be a constant */
#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
return false;
/* No device or no PCI device */
- if (!dev || dev->bus != &pci_bus_type)
+ if (dev->bus != &pci_bus_type)
return false;
devid = get_device_id(dev);
u32 tail, head;
u8 *target;
+ WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
target = iommu->cmd_buf + tail;
memcpy_toio(target, cmd, sizeof(*cmd));
struct dma_ops_domain *dma_dom;
u16 devid;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev) {
/* Do we handle this device? */
if (!check_device(&dev->dev))
list_for_each_entry_safe(dev_data, next, &domain->dev_list, list) {
struct device *dev = dev_data->dev;
- do_detach(dev);
+ __detach_device(dev);
atomic_set(&dev_data->bind, 0);
}
return NULL;
spin_lock_init(&domain->lock);
+ mutex_init(&domain->api_lock);
domain->id = domain_id_alloc();
if (!domain->id)
goto out_err;
free_pagetable(domain);
- domain_id_free(domain->id);
-
- kfree(domain);
+ protection_domain_free(domain);
dom->priv = NULL;
}
iova &= PAGE_MASK;
paddr &= PAGE_MASK;
+ mutex_lock(&domain->api_lock);
+
for (i = 0; i < npages; ++i) {
ret = iommu_map_page(domain, iova, paddr, prot, PM_MAP_4k);
if (ret)
paddr += PAGE_SIZE;
}
+ mutex_unlock(&domain->api_lock);
+
return 0;
}
iova &= PAGE_MASK;
+ mutex_lock(&domain->api_lock);
+
for (i = 0; i < npages; ++i) {
iommu_unmap_page(domain, iova, PM_MAP_4k);
iova += PAGE_SIZE;
}
iommu_flush_tlb_pde(domain);
+
+ mutex_unlock(&domain->api_lock);
}
static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
bool amd_iommu_np_cache __read_mostly;
/*
- * Set to true if ACPI table parsing and hardware intialization went properly
+ * The ACPI table parsing functions set this variable on an error
*/
-static bool amd_iommu_initialized;
+static int __initdata amd_iommu_init_err;
/*
* List of protection domains - used during resume
*/
for (i = 0; i < table->length; ++i)
checksum += p[i];
- if (checksum != 0)
+ if (checksum != 0) {
/* ACPI table corrupt */
- return -ENODEV;
+ amd_iommu_init_err = -ENODEV;
+ return 0;
+ }
p += IVRS_HEADER_LENGTH;
if (cmd_buf == NULL)
return NULL;
- iommu->cmd_buf_size = CMD_BUFFER_SIZE;
+ iommu->cmd_buf_size = CMD_BUFFER_SIZE | CMD_BUFFER_UNINITIALIZED;
return cmd_buf;
}
&entry, sizeof(entry));
amd_iommu_reset_cmd_buffer(iommu);
+ iommu->cmd_buf_size &= ~(CMD_BUFFER_UNINITIALIZED);
}
static void __init free_command_buffer(struct amd_iommu *iommu)
{
free_pages((unsigned long)iommu->cmd_buf,
- get_order(iommu->cmd_buf_size));
+ get_order(iommu->cmd_buf_size & ~(CMD_BUFFER_UNINITIALIZED)));
}
/* allocates the memory where the IOMMU will log its events to */
h->mmio_phys);
iommu = kzalloc(sizeof(struct amd_iommu), GFP_KERNEL);
- if (iommu == NULL)
- return -ENOMEM;
+ if (iommu == NULL) {
+ amd_iommu_init_err = -ENOMEM;
+ return 0;
+ }
+
ret = init_iommu_one(iommu, h);
- if (ret)
- return ret;
+ if (ret) {
+ amd_iommu_init_err = ret;
+ return 0;
+ }
break;
default:
break;
}
WARN_ON(p != end);
- amd_iommu_initialized = true;
-
return 0;
}
if (acpi_table_parse("IVRS", find_last_devid_acpi) != 0)
return -ENODEV;
+ ret = amd_iommu_init_err;
+ if (ret)
+ goto out;
+
dev_table_size = tbl_size(DEV_TABLE_ENTRY_SIZE);
alias_table_size = tbl_size(ALIAS_TABLE_ENTRY_SIZE);
rlookup_table_size = tbl_size(RLOOKUP_TABLE_ENTRY_SIZE);
if (acpi_table_parse("IVRS", init_iommu_all) != 0)
goto free;
- if (!amd_iommu_initialized)
+ if (amd_iommu_init_err) {
+ ret = amd_iommu_init_err;
goto free;
+ }
if (acpi_table_parse("IVRS", init_memory_definitions) != 0)
goto free;
+ if (amd_iommu_init_err) {
+ ret = amd_iommu_init_err;
+ goto free;
+ }
+
ret = sysdev_class_register(&amd_iommu_sysdev_class);
if (ret)
goto free;
if (ret)
goto free;
+ enable_iommus();
+
if (iommu_pass_through)
ret = amd_iommu_init_passthrough();
else
amd_iommu_init_notifier();
- enable_iommus();
-
if (iommu_pass_through)
goto out;
return ret;
free:
+ disable_iommus();
amd_iommu_uninit_devices();
for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
int bus;
int dev_base, dev_limit;
+ u32 ctl;
bus = bus_dev_ranges[i].bus;
dev_base = bus_dev_ranges[i].dev_base;
gart_iommu_aperture = 1;
x86_init.iommu.iommu_init = gart_iommu_init;
- aper_order = (read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL) >> 1) & 7;
+ ctl = read_pci_config(bus, slot, 3,
+ AMD64_GARTAPERTURECTL);
+
+ /*
+ * Before we do anything else disable the GART. It may
+ * still be enabled if we boot into a crash-kernel here.
+ * Reconfiguring the GART while it is enabled could have
+ * unknown side-effects.
+ */
+ ctl &= ~GARTEN;
+ write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
+
+ aper_order = (ctl >> 1) & 7;
aper_size = (32 * 1024 * 1024) << aper_order;
aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
aper_base <<= 25;
#include <asm/cpu.h>
#include <asm/reboot.h>
#include <asm/virtext.h>
-#include <asm/x86_init.h>
#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
#ifdef CONFIG_HPET_TIMER
hpet_disable();
#endif
-
-#ifdef CONFIG_X86_64
- x86_platform.iommu_shutdown();
-#endif
-
crash_save_cpu(regs, safe_smp_processor_id());
}
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif
+#include <linux/uaccess.h>
+
extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, char *log_lvl);
get_bp(frame);
#ifdef CONFIG_FRAME_POINTER
- while (n--)
- frame = frame->next_frame;
+ while (n--) {
+ if (probe_kernel_address(&frame->next_frame, frame))
+ break;
+ }
#endif
return (unsigned long)frame;
enable_gart_translation(dev, __pa(agp_gatt_table));
}
+
+ /* Flush the GART-TLB to remove stale entries */
+ k8_flush_garts();
}
/*
for_each_sp(pages, sp, parents, i) {
kvm_mmu_zap_page(kvm, sp);
mmu_pages_clear_parents(&parents);
+ zapped++;
}
- zapped += pages.nr;
kvm_mmu_pages_init(parent, &parents, &pages);
}
*/
if (used_pages > kvm_nr_mmu_pages) {
- while (used_pages > kvm_nr_mmu_pages) {
+ while (used_pages > kvm_nr_mmu_pages &&
+ !list_empty(&kvm->arch.active_mmu_pages)) {
struct kvm_mmu_page *page;
page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(kvm, page);
+ used_pages -= kvm_mmu_zap_page(kvm, page);
used_pages--;
}
+ kvm_nr_mmu_pages = used_pages;
kvm->arch.n_free_mmu_pages = 0;
}
else
&& !sp->role.invalid) {
pgprintk("%s: zap %lx %x\n",
__func__, gfn, sp->role.word);
- kvm_mmu_zap_page(kvm, sp);
+ if (kvm_mmu_zap_page(kvm, sp))
+ nn = bucket->first;
}
}
}
if (err)
goto free_svm;
+ err = -ENOMEM;
page = alloc_page(GFP_KERNEL);
- if (!page) {
- err = -ENOMEM;
+ if (!page)
goto uninit;
- }
- err = -ENOMEM;
msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
if (!msrpm_pages)
- goto uninit;
+ goto free_page1;
nested_msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER);
if (!nested_msrpm_pages)
- goto uninit;
-
- svm->msrpm = page_address(msrpm_pages);
- svm_vcpu_init_msrpm(svm->msrpm);
+ goto free_page2;
hsave_page = alloc_page(GFP_KERNEL);
if (!hsave_page)
- goto uninit;
+ goto free_page3;
+
svm->nested.hsave = page_address(hsave_page);
+ svm->msrpm = page_address(msrpm_pages);
+ svm_vcpu_init_msrpm(svm->msrpm);
+
svm->nested.msrpm = page_address(nested_msrpm_pages);
svm->vmcb = page_address(page);
return &svm->vcpu;
+free_page3:
+ __free_pages(nested_msrpm_pages, MSRPM_ALLOC_ORDER);
+free_page2:
+ __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER);
+free_page1:
+ __free_page(page);
uninit:
kvm_vcpu_uninit(&svm->vcpu);
free_svm:
#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
+#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM))
+
/*
* These 2 parameters are used to config the controls for Pause-Loop Exiting:
* ple_gap: upper bound on the amount of time between two successive
} host_state;
struct {
int vm86_active;
- u8 save_iopl;
+ ulong save_rflags;
struct kvm_save_segment {
u16 selector;
unsigned long base;
static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
{
- unsigned long rflags;
+ unsigned long rflags, save_rflags;
rflags = vmcs_readl(GUEST_RFLAGS);
- if (to_vmx(vcpu)->rmode.vm86_active)
- rflags &= ~(unsigned long)(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
+ if (to_vmx(vcpu)->rmode.vm86_active) {
+ rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
+ save_rflags = to_vmx(vcpu)->rmode.save_rflags;
+ rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
+ }
return rflags;
}
static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
- if (to_vmx(vcpu)->rmode.vm86_active)
+ if (to_vmx(vcpu)->rmode.vm86_active) {
+ to_vmx(vcpu)->rmode.save_rflags = rflags;
rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
+ }
vmcs_writel(GUEST_RFLAGS, rflags);
}
vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar);
flags = vmcs_readl(GUEST_RFLAGS);
- flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
- flags |= (vmx->rmode.save_iopl << IOPL_SHIFT);
+ flags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
+ flags |= vmx->rmode.save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
vmcs_writel(GUEST_RFLAGS, flags);
vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
flags = vmcs_readl(GUEST_RFLAGS);
- vmx->rmode.save_iopl
- = (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
+ vmx->rmode.save_rflags = flags;
flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
#ifdef CONFIG_X86_64
if (cr0 & 0xffffffff00000000UL) {
- printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n",
- cr0, kvm_read_cr0(vcpu));
kvm_inject_gp(vcpu, 0);
return;
}
cr0 &= ~CR0_RESERVED_BITS;
if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) {
- printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n");
kvm_inject_gp(vcpu, 0);
return;
}
if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) {
- printk(KERN_DEBUG "set_cr0: #GP, set PG flag "
- "and a clear PE flag\n");
kvm_inject_gp(vcpu, 0);
return;
}
int cs_db, cs_l;
if (!is_pae(vcpu)) {
- printk(KERN_DEBUG "set_cr0: #GP, start paging "
- "in long mode while PAE is disabled\n");
kvm_inject_gp(vcpu, 0);
return;
}
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
if (cs_l) {
- printk(KERN_DEBUG "set_cr0: #GP, start paging "
- "in long mode while CS.L == 1\n");
kvm_inject_gp(vcpu, 0);
return;
} else
#endif
if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->arch.cr3)) {
- printk(KERN_DEBUG "set_cr0: #GP, pdptrs "
- "reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE;
if (cr4 & CR4_RESERVED_BITS) {
- printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
if (is_long_mode(vcpu)) {
if (!(cr4 & X86_CR4_PAE)) {
- printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while "
- "in long mode\n");
kvm_inject_gp(vcpu, 0);
return;
}
} else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE)
&& ((cr4 ^ old_cr4) & pdptr_bits)
&& !load_pdptrs(vcpu, vcpu->arch.cr3)) {
- printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
if (cr4 & X86_CR4_VMXE) {
- printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n");
kvm_inject_gp(vcpu, 0);
return;
}
if (is_long_mode(vcpu)) {
if (cr3 & CR3_L_MODE_RESERVED_BITS) {
- printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
} else {
if (is_pae(vcpu)) {
if (cr3 & CR3_PAE_RESERVED_BITS) {
- printk(KERN_DEBUG
- "set_cr3: #GP, reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) {
- printk(KERN_DEBUG "set_cr3: #GP, pdptrs "
- "reserved bits\n");
kvm_inject_gp(vcpu, 0);
return;
}
void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
if (cr8 & CR8_RESERVED_BITS) {
- printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8);
kvm_inject_gp(vcpu, 0);
return;
}
static void set_efer(struct kvm_vcpu *vcpu, u64 efer)
{
if (efer & efer_reserved_bits) {
- printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n",
- efer);
kvm_inject_gp(vcpu, 0);
return;
}
if (is_paging(vcpu)
&& (vcpu->arch.efer & EFER_LME) != (efer & EFER_LME)) {
- printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n");
kvm_inject_gp(vcpu, 0);
return;
}
feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
if (!feat || !(feat->edx & bit(X86_FEATURE_FXSR_OPT))) {
- printk(KERN_DEBUG "set_efer: #GP, enable FFXSR w/o CPUID capability\n");
kvm_inject_gp(vcpu, 0);
return;
}
feat = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
if (!feat || !(feat->ecx & bit(X86_FEATURE_SVM))) {
- printk(KERN_DEBUG "set_efer: #GP, enable SVM w/o SVM\n");
kvm_inject_gp(vcpu, 0);
return;
}
if (msr >= MSR_IA32_MC0_CTL &&
msr < MSR_IA32_MC0_CTL + 4 * bank_num) {
u32 offset = msr - MSR_IA32_MC0_CTL;
- /* only 0 or all 1s can be written to IA32_MCi_CTL */
+ /* only 0 or all 1s can be written to IA32_MCi_CTL
+ * some Linux kernels though clear bit 10 in bank 4 to
+ * workaround a BIOS/GART TBL issue on AMD K8s, ignore
+ * this to avoid an uncatched #GP in the guest
+ */
if ((offset & 0x3) == 0 &&
- data != 0 && data != ~(u64)0)
+ data != 0 && (data | (1 << 10)) != ~(u64)0)
return -1;
vcpu->arch.mce_banks[offset] = data;
break;
int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_dirty_log *log)
{
- int r, n, i;
+ int r, i;
struct kvm_memory_slot *memslot;
+ unsigned long n;
unsigned long is_dirty = 0;
unsigned long *dirty_bitmap = NULL;
if (!memslot->dirty_bitmap)
goto out;
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ n = kvm_dirty_bitmap_bytes(memslot);
r = -ENOMEM;
dirty_bitmap = vmalloc(n);
kvm_set_cr8(vcpu, kvm_run->cr8);
if (vcpu->arch.pio.cur_count) {
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
r = complete_pio(vcpu);
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
if (r)
goto out;
}
int ret = 0;
u32 old_tss_base = get_segment_base(vcpu, VCPU_SREG_TR);
u16 old_tss_sel = get_segment_selector(vcpu, VCPU_SREG_TR);
+ u32 desc_limit;
old_tss_base = kvm_mmu_gva_to_gpa_write(vcpu, old_tss_base, NULL);
}
}
- if (!nseg_desc.p || get_desc_limit(&nseg_desc) < 0x67) {
+ desc_limit = get_desc_limit(&nseg_desc);
+ if (!nseg_desc.p ||
+ ((desc_limit < 0x67 && (nseg_desc.type & 8)) ||
+ desc_limit < 0x2b)) {
kvm_queue_exception_e(vcpu, TS_VECTOR, tss_selector & 0xfffc);
return 1;
}
local_irq_save(flags);
if (lguest_data.hcall_status[next_call] != 0xFF) {
/* Table full, so do normal hcall which will flush table. */
- kvm_hypercall4(call, arg1, arg2, arg3, arg4);
+ hcall(call, arg1, arg2, arg3, arg4);
} else {
lguest_data.hcalls[next_call].arg0 = call;
lguest_data.hcalls[next_call].arg1 = arg1;
* So, when we're in lazy mode, we call async_hcall() to store the call for
* future processing:
*/
-static void lazy_hcall1(unsigned long call,
- unsigned long arg1)
+static void lazy_hcall1(unsigned long call, unsigned long arg1)
{
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
- kvm_hypercall1(call, arg1);
+ hcall(call, arg1, 0, 0, 0);
else
async_hcall(call, arg1, 0, 0, 0);
}
/* You can imagine what lazy_hcall2, 3 and 4 look like. :*/
static void lazy_hcall2(unsigned long call,
- unsigned long arg1,
- unsigned long arg2)
+ unsigned long arg1,
+ unsigned long arg2)
{
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
- kvm_hypercall2(call, arg1, arg2);
+ hcall(call, arg1, arg2, 0, 0);
else
async_hcall(call, arg1, arg2, 0, 0);
}
static void lazy_hcall3(unsigned long call,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3)
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3)
{
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
- kvm_hypercall3(call, arg1, arg2, arg3);
+ hcall(call, arg1, arg2, arg3, 0);
else
async_hcall(call, arg1, arg2, arg3, 0);
}
#ifdef CONFIG_X86_PAE
static void lazy_hcall4(unsigned long call,
- unsigned long arg1,
- unsigned long arg2,
- unsigned long arg3,
- unsigned long arg4)
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4)
{
if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE)
- kvm_hypercall4(call, arg1, arg2, arg3, arg4);
+ hcall(call, arg1, arg2, arg3, arg4);
else
async_hcall(call, arg1, arg2, arg3, arg4);
}
:*/
static void lguest_leave_lazy_mmu_mode(void)
{
- kvm_hypercall0(LHCALL_FLUSH_ASYNC);
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0, 0);
paravirt_leave_lazy_mmu();
}
static void lguest_end_context_switch(struct task_struct *next)
{
- kvm_hypercall0(LHCALL_FLUSH_ASYNC);
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0, 0);
paravirt_end_context_switch(next);
}
/* Keep the local copy up to date. */
native_write_idt_entry(dt, entrynum, g);
/* Tell Host about this new entry. */
- kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]);
+ hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1], 0);
}
/*
struct desc_struct *idt = (void *)desc->address;
for (i = 0; i < (desc->size+1)/8; i++)
- kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+ hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b, 0);
}
/*
struct desc_struct *gdt = (void *)desc->address;
for (i = 0; i < (desc->size+1)/8; i++)
- kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b);
+ hcall(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b, 0);
}
/*
{
native_write_gdt_entry(dt, entrynum, desc, type);
/* Tell Host about this new entry. */
- kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, entrynum,
- dt[entrynum].a, dt[entrynum].b);
+ hcall(LHCALL_LOAD_GDT_ENTRY, entrynum,
+ dt[entrynum].a, dt[entrynum].b, 0);
}
/*
}
/* Please wake us this far in the future. */
- kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta);
+ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0, 0);
return 0;
}
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* A 0 argument shuts the clock down. */
- kvm_hypercall0(LHCALL_SET_CLOCKEVENT);
+ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0, 0);
break;
case CLOCK_EVT_MODE_ONESHOT:
/* This is what we expect. */
/* STOP! Until an interrupt comes in. */
static void lguest_safe_halt(void)
{
- kvm_hypercall0(LHCALL_HALT);
+ hcall(LHCALL_HALT, 0, 0, 0, 0);
}
/*
*/
static void lguest_power_off(void)
{
- kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"),
- LGUEST_SHUTDOWN_POWEROFF);
+ hcall(LHCALL_SHUTDOWN, __pa("Power down"),
+ LGUEST_SHUTDOWN_POWEROFF, 0, 0);
}
/*
*/
static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
{
- kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF);
+ hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0, 0);
/* The hcall won't return, but to keep gcc happy, we're "done". */
return NOTIFY_DONE;
}
len = sizeof(scratch) - 1;
scratch[len] = '\0';
memcpy(scratch, buf, len);
- kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch));
+ hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0, 0);
/* This routine returns the number of bytes actually written. */
return len;
*/
static void lguest_restart(char *reason)
{
- kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART);
+ hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0, 0);
}
/*G:050
*/
movl $LHCALL_LGUEST_INIT, %eax
movl $lguest_data - __PAGE_OFFSET, %ebx
- .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
+ int $LGUEST_TRAP_ENTRY
/* Set up the initial stack so we can run C code. */
movl $(init_thread_union+THREAD_SIZE),%esp
/* allow full data read from EC address space */
if (obj_desc->field.region_obj->region.space_id ==
ACPI_ADR_SPACE_EC) {
- if (obj_desc->common_field.bit_length > 8)
- obj_desc->common_field.access_bit_width =
- ACPI_ROUND_UP(obj_desc->common_field.
- bit_length, 8);
+ if (obj_desc->common_field.bit_length > 8) {
+ unsigned width =
+ ACPI_ROUND_BITS_UP_TO_BYTES(
+ obj_desc->common_field.bit_length);
+ // access_bit_width is u8, don't overflow it
+ if (width > 8)
+ width = 8;
obj_desc->common_field.access_byte_width =
- ACPI_DIV_8(obj_desc->common_field.
- access_bit_width);
+ width;
+ obj_desc->common_field.access_bit_width =
+ 8 * width;
+ }
}
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ struct request_queue *q = qc->scsicmd->device->request_queue;
+ unsigned long flags;
WARN_ON(!ap->ops->error_handler);
* Note that ATA_QCFLAG_FAILED is unconditionally set after
* this function completes.
*/
+ spin_lock_irqsave(q->queue_lock, flags);
blk_abort_request(qc->scsicmd->request);
+ spin_unlock_irqrestore(q->queue_lock, flags);
}
/**
}
/* okay, this error is ours */
+ memset(&tf, 0, sizeof(tf));
rc = ata_eh_read_log_10h(dev, &tag, &tf);
if (rc) {
ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
/* clear any possible error conditions */
pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
-
- intel_i830_setup_flush();
return 0;
}
.agp_destroy_page = agp_generic_destroy_page,
.agp_destroy_pages = agp_generic_destroy_pages,
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
- .chipset_flush = intel_i830_chipset_flush,
};
static const struct agp_bridge_driver intel_850_driver = {
xoutb(0, REG_FLAGS1(iobase)); /* clear detectCMM */
/* last check before exit */
- if (!io_detect_cm4000(iobase, dev))
- count = -ENODEV;
+ if (!io_detect_cm4000(iobase, dev)) {
+ rc = -ENODEV;
+ goto release_io;
+ }
if (test_bit(IS_INVREV, &dev->flags) && count > 0)
str_invert_revert(dev->rbuf, count);
if (copy_to_user(buf, dev->rbuf, count))
- return -EFAULT;
+ rc = -EFAULT;
release_io:
clear_bit(LOCK_IO, &dev->flags);
u.packet.header_length = GET_HEADER_LENGTH(control);
if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
+ if (u.packet.header_length % 4 != 0)
+ return -EINVAL;
header_length = u.packet.header_length;
} else {
/*
if (ctx->header_size == 0) {
if (u.packet.header_length > 0)
return -EINVAL;
- } else if (u.packet.header_length % ctx->header_size != 0) {
+ } else if (u.packet.header_length == 0 ||
+ u.packet.header_length % ctx->header_size != 0) {
return -EINVAL;
}
header_length = 0;
return -ENODEV;
if (_IOC_TYPE(cmd) != '#' ||
- _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
+ _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers) ||
+ _IOC_SIZE(cmd) > sizeof(buffer))
return -EINVAL;
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- if (_IOC_SIZE(cmd) > sizeof(buffer) ||
- copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
+ if (_IOC_DIR(cmd) == _IOC_READ)
+ memset(&buffer, 0, _IOC_SIZE(cmd));
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
return -EFAULT;
- }
ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer);
if (ret < 0)
return ret;
- if (_IOC_DIR(cmd) & _IOC_READ) {
- if (_IOC_SIZE(cmd) > sizeof(buffer) ||
- copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ if (copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
return -EFAULT;
- }
return ret;
}
for (try = 0; try < 5; try++) {
new = allocate ? old - bandwidth : old + bandwidth;
if (new < 0 || new > BANDWIDTH_AVAILABLE_INITIAL)
- break;
+ return -EBUSY;
data[0] = cpu_to_be32(old);
data[1] = cpu_to_be32(new);
u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
{
__be32 c, all, old;
- int i, retry = 5;
+ int i, ret = -EIO, retry = 5;
old = all = allocate ? cpu_to_be32(~0) : 0;
if (!(channels_mask & 1 << i))
continue;
+ ret = -EBUSY;
+
c = cpu_to_be32(1 << (31 - i));
if ((old & c) != (all & c))
continue;
/* 1394-1995 IRM, fall through to retry. */
default:
- if (retry--)
+ if (retry) {
+ retry--;
i--;
+ } else {
+ ret = -EIO;
+ }
}
}
- return -EIO;
+ return ret;
}
static void deallocate_channel(struct fw_card *card, int irm_id,
struct fw_packet *packet, u32 csr)
{
struct fw_packet response;
- int tcode, length, ext_tcode, sel;
+ int tcode, length, ext_tcode, sel, try;
__be32 *payload, lock_old;
u32 lock_arg, lock_data;
reg_write(ohci, OHCI1394_CSRCompareData, lock_arg);
reg_write(ohci, OHCI1394_CSRControl, sel);
- if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
- lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData));
- else
- fw_notify("swap not done yet\n");
+ for (try = 0; try < 20; try++)
+ if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) {
+ lock_old = cpu_to_be32(reg_read(ohci,
+ OHCI1394_CSRData));
+ fw_fill_response(&response, packet->header,
+ RCODE_COMPLETE,
+ &lock_old, sizeof(lock_old));
+ goto out;
+ }
+
+ fw_error("swap not done (CSR lock timeout)\n");
+ fw_fill_response(&response, packet->header, RCODE_BUSY, NULL, 0);
- fw_fill_response(&response, packet->header,
- RCODE_COMPLETE, &lock_old, sizeof(lock_old));
out:
fw_core_handle_response(&ohci->card, &response);
}
static void handle_local_request(struct context *ctx, struct fw_packet *packet)
{
- u64 offset;
- u32 csr;
+ u64 offset, csr;
if (ctx == &ctx->ohci->at_request_ctx) {
packet->ack = ACK_PENDING;
}
driver = dev->driver;
- drm_vblank_cleanup(dev);
-
drm_lastclose(dev);
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
dev->agp = NULL;
}
+ drm_vblank_cleanup(dev);
+
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_rmmap(dev, r_list->map);
drm_ht_remove(&dev->map_hash);
} else {
struct drm_i915_gem_object *obj_priv;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
seq_printf(m, "Fenced object[%2d] = %p: %s "
"%08x %08zx %08x %s %08x %08x %d",
i, obj, get_pin_flag(obj_priv),
dev_priv->cfb_size = size;
+ dev_priv->compressed_fb = compressed_fb;
+
if (IS_GM45(dev)) {
g4x_disable_fbc(dev);
I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
i8xx_disable_fbc(dev);
I915_WRITE(FBC_CFB_BASE, cfb_base);
I915_WRITE(FBC_LL_BASE, ll_base);
+ dev_priv->compressed_llb = compressed_llb;
}
DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base,
ll_base, size >> 20);
}
+static void i915_cleanup_compression(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ drm_mm_put_block(dev_priv->compressed_fb);
+ if (!IS_GM45(dev))
+ drm_mm_put_block(dev_priv->compressed_llb);
+}
+
/* true = enable decode, false = disable decoder */
static unsigned int i915_vga_set_decode(void *cookie, bool state)
{
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
+ if (I915_HAS_FBC(dev) && i915_powersave)
+ i915_cleanup_compression(dev);
drm_mm_takedown(&dev_priv->vram);
i915_gem_lastclose(dev);
};
const static struct intel_device_info intel_i85x_info = {
- .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+ .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+ .cursor_needs_physical = 1,
};
const static struct intel_device_info intel_i865g_info = {
.is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
};
const static struct intel_device_info intel_i915gm_info = {
- .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1,
+ .is_i9xx = 1, .is_mobile = 1,
.cursor_needs_physical = 1,
};
const static struct intel_device_info intel_i945g_info = {
.is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
};
const static struct intel_device_info intel_i945gm_info = {
- .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1,
+ .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
.has_hotplug = 1, .cursor_needs_physical = 1,
};
INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),
- INTEL_VGA_DEVICE(0x35e8, &intel_i85x_info),
+ INTEL_VGA_DEVICE(0x358e, &intel_i85x_info),
INTEL_VGA_DEVICE(0x2572, &intel_i865g_info),
INTEL_VGA_DEVICE(0x2582, &intel_i915g_info),
INTEL_VGA_DEVICE(0x258a, &intel_i915g_info),
!dev_priv->mm.suspended) {
drm_i915_ring_buffer_t *ring = &dev_priv->ring;
struct drm_gem_object *obj = ring->ring_obj;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
dev_priv->mm.suspended = 0;
/* Stop the ring if it's running. */
struct intel_device_info {
u8 is_mobile : 1;
u8 is_i8xx : 1;
+ u8 is_i85x : 1;
u8 is_i915g : 1;
u8 is_i9xx : 1;
u8 is_i945gm : 1;
drm_dma_handle_t *status_page_dmah;
void *hw_status_page;
+ void *seqno_page;
dma_addr_t dma_status_page;
uint32_t counter;
unsigned int status_gfx_addr;
+ unsigned int seqno_gfx_addr;
drm_local_map_t hws_map;
struct drm_gem_object *hws_obj;
+ struct drm_gem_object *seqno_obj;
struct drm_gem_object *pwrctx;
struct resource mch_res;
/* Reclocking support */
bool render_reclock_avail;
bool lvds_downclock_avail;
+ /* indicate whether the LVDS EDID is OK */
+ bool lvds_edid_good;
/* indicates the reduced downclock for LVDS*/
int lvds_downclock;
struct work_struct idle_work;
u8 max_delay;
enum no_fbc_reason no_fbc_reason;
+
+ struct drm_mm_node *compressed_fb;
+ struct drm_mm_node *compressed_llb;
} drm_i915_private_t;
/** driver private structure attached to each drm_gem_object */
atomic_t pending_flip;
};
+#define to_intel_bo(x) ((struct drm_i915_gem_object *) (x)->driver_private)
+
/**
* Request queue structure.
*
#define IS_I830(dev) ((dev)->pci_device == 0x3577)
#define IS_845G(dev) ((dev)->pci_device == 0x2562)
-#define IS_I85X(dev) ((dev)->pci_device == 0x3582)
+#define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x)
#define IS_I865G(dev) ((dev)->pci_device == 0x2572)
#define IS_GEN2(dev) (INTEL_INFO(dev)->is_i8xx)
#define IS_I915G(dev) (INTEL_INFO(dev)->is_i915g)
#define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
IS_GEN6(dev))
+#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
{
drm_i915_private_t *dev_priv = obj->dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
obj_priv->tiling_mode != I915_TILING_NONE;
struct drm_i915_gem_pread *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
ssize_t remain;
loff_t offset, page_base;
char __user *user_data;
if (ret != 0)
goto fail_put_pages;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = args->offset;
while (remain > 0) {
struct drm_i915_gem_pread *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct mm_struct *mm = current->mm;
struct page **user_pages;
ssize_t remain;
if (ret != 0)
goto fail_put_pages;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = args->offset;
while (remain > 0) {
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EBADF;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
/* Bounds check source.
*
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
drm_i915_private_t *dev_priv = dev->dev_private;
ssize_t remain;
loff_t offset, page_base;
if (ret)
goto fail;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = obj_priv->gtt_offset + args->offset;
while (remain > 0) {
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
drm_i915_private_t *dev_priv = dev->dev_private;
ssize_t remain;
loff_t gtt_page_base, offset;
if (ret)
goto out_unpin_object;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = obj_priv->gtt_offset + args->offset;
while (remain > 0) {
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
ssize_t remain;
loff_t offset, page_base;
char __user *user_data;
if (ret != 0)
goto fail_put_pages;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = args->offset;
obj_priv->dirty = 1;
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct mm_struct *mm = current->mm;
struct page **user_pages;
ssize_t remain;
if (ret != 0)
goto fail_put_pages;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
offset = args->offset;
obj_priv->dirty = 1;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EBADF;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
/* Bounds check destination.
*
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EBADF;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
mutex_lock(&dev->struct_mutex);
DRM_INFO("%s: sw_finish %d (%p %zd)\n",
__func__, args->handle, obj, obj->size);
#endif
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
/* Pinned buffers may be scanout, so flush the cache */
if (obj_priv->pin_count)
struct drm_gem_object *obj = vma->vm_private_data;
struct drm_device *dev = obj->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
pgoff_t page_offset;
unsigned long pfn;
int ret = 0;
{
struct drm_device *dev = obj->dev;
struct drm_gem_mm *mm = dev->mm_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_map_list *list;
struct drm_local_map *map;
int ret = 0;
i915_gem_release_mmap(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if (dev->dev_mapping)
unmap_mapping_range(dev->dev_mapping,
i915_gem_free_mmap_offset(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_gem_mm *mm = dev->mm_private;
struct drm_map_list *list;
i915_gem_get_gtt_alignment(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int start, i;
/*
mutex_lock(&dev->struct_mutex);
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (obj_priv->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to mmap a purgeable buffer\n");
void
i915_gem_object_put_pages(struct drm_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page_count = obj->size / PAGE_SIZE;
int i;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
/* Add a reference if we're newly entering the active list. */
if (!obj_priv->active) {
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
BUG_ON(!obj_priv->active);
list_move_tail(&obj_priv->list, &dev_priv->mm.flushing_list);
static void
i915_gem_object_truncate(struct drm_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct inode *inode;
inode = obj->filp->f_path.dentry->d_inode;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
i915_verify_inactive(dev, __FILE__, __LINE__);
if (obj_priv->pin_count != 0)
}
}
+#define PIPE_CONTROL_FLUSH(addr) \
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
+ PIPE_CONTROL_DEPTH_STALL); \
+ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
+ OUT_RING(0); \
+ OUT_RING(0); \
+
/**
* Creates a new sequence number, emitting a write of it to the status page
* plus an interrupt, which will trigger i915_user_interrupt_handler.
if (dev_priv->mm.next_gem_seqno == 0)
dev_priv->mm.next_gem_seqno++;
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(seqno);
+ if (HAS_PIPE_CONTROL(dev)) {
+ u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
- OUT_RING(MI_USER_INTERRUPT);
- ADVANCE_LP_RING();
+ /*
+ * Workaround qword write incoherence by flushing the
+ * PIPE_NOTIFY buffers out to memory before requesting
+ * an interrupt.
+ */
+ BEGIN_LP_RING(32);
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+ OUT_RING(seqno);
+ OUT_RING(0);
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128; /* write to separate cachelines */
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
+ PIPE_CONTROL_NOTIFY);
+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+ OUT_RING(seqno);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(4);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(seqno);
+
+ OUT_RING(MI_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+ }
DRM_DEBUG_DRIVER("%d\n", seqno);
{
drm_i915_private_t *dev_priv = dev->dev_private;
- return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
+ if (HAS_PIPE_CONTROL(dev))
+ return ((volatile u32 *)(dev_priv->seqno_page))[0];
+ else
+ return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
}
/**
i915_gem_object_wait_rendering(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
/* This function only exists to support waiting for existing rendering,
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret = 0;
#if WATCH_BUF
#if WATCH_LRU
DRM_INFO("%s: evicting %p\n", __func__, obj);
#endif
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
BUG_ON(obj_priv->pin_count != 0);
BUG_ON(obj_priv->active);
i915_gem_object_get_pages(struct drm_gem_object *obj,
gfp_t gfpmask)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page_count, i;
struct address_space *mapping;
struct inode *inode;
struct drm_gem_object *obj = reg->obj;
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int regnum = obj_priv->fence_reg;
uint64_t val;
struct drm_gem_object *obj = reg->obj;
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int regnum = obj_priv->fence_reg;
uint64_t val;
struct drm_gem_object *obj = reg->obj;
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int regnum = obj_priv->fence_reg;
int tile_width;
uint32_t fence_reg, val;
pitch_val = obj_priv->stride / tile_width;
pitch_val = ffs(pitch_val) - 1;
+ if (obj_priv->tiling_mode == I915_TILING_Y &&
+ HAS_128_BYTE_Y_TILING(dev))
+ WARN_ON(pitch_val > I830_FENCE_MAX_PITCH_VAL);
+ else
+ WARN_ON(pitch_val > I915_FENCE_MAX_PITCH_VAL);
+
val = obj_priv->gtt_offset;
if (obj_priv->tiling_mode == I915_TILING_Y)
val |= 1 << I830_FENCE_TILING_Y_SHIFT;
struct drm_gem_object *obj = reg->obj;
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int regnum = obj_priv->fence_reg;
uint32_t val;
uint32_t pitch_val;
if (!reg->obj)
return i;
- obj_priv = reg->obj->driver_private;
+ obj_priv = to_intel_bo(reg->obj);
if (!obj_priv->pin_count)
avail++;
}
{
struct drm_device *dev = obj->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_i915_fence_reg *reg = NULL;
int ret;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if (IS_GEN6(dev)) {
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 +
i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
return 0;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_mm_node *free_space;
gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
int ret;
void
i915_gem_clflush_object(struct drm_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
/* If we don't have a page list set up, then we're not pinned
* to GPU, and we can ignore the cache flush because it'll happen
int
i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_write_domain, old_read_domains;
int ret;
i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_write_domain, old_read_domains;
int ret;
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t invalidate_domains = 0;
uint32_t flush_domains = 0;
uint32_t old_read_domains;
static void
i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if (!obj_priv->page_cpu_valid)
return;
i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj,
uint64_t offset, uint64_t size)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_read_domains;
int i, ret;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int i, ret;
void __iomem *reloc_page;
bool need_fence;
i915_gem_object_unpin(obj);
return -EBADF;
}
- target_obj_priv = target_obj->driver_private;
+ target_obj_priv = to_intel_bo(target_obj);
#if WATCH_RELOC
DRM_INFO("%s: obj %p offset %08x target %d "
prepare_to_wait(&dev_priv->pending_flip_queue,
&wait, TASK_INTERRUPTIBLE);
for (i = 0; i < count; i++) {
- obj_priv = object_list[i]->driver_private;
+ obj_priv = to_intel_bo(object_list[i]);
if (atomic_read(&obj_priv->pending_flip) > 0)
break;
}
goto err;
}
- obj_priv = object_list[i]->driver_private;
+ obj_priv = to_intel_bo(object_list[i]);
if (obj_priv->in_execbuffer) {
DRM_ERROR("Object %p appears more than once in object list\n",
object_list[i]);
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = obj->pending_write_domain;
for (i = 0; i < args->buffer_count; i++) {
if (object_list[i]) {
- obj_priv = object_list[i]->driver_private;
+ obj_priv = to_intel_bo(object_list[i]);
obj_priv->in_execbuffer = false;
}
drm_gem_object_unreference(object_list[i]);
i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
i915_verify_inactive(dev, __FILE__, __LINE__);
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
i915_verify_inactive(dev, __FILE__, __LINE__);
obj_priv->pin_count--;
mutex_unlock(&dev->struct_mutex);
return -EBADF;
}
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (obj_priv->madv != I915_MADV_WILLNEED) {
DRM_ERROR("Attempting to pin a purgeable buffer\n");
return -EBADF;
}
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (obj_priv->pin_filp != file_priv) {
DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
args->handle);
*/
i915_gem_retire_requests(dev);
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
/* Don't count being on the flushing list against the object being
* done. Otherwise, a buffer left on the flushing list but not getting
* flushed (because nobody's flushing that domain) won't ever return
}
mutex_lock(&dev->struct_mutex);
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (obj_priv->pin_count) {
drm_gem_object_unreference(obj);
void i915_gem_free_object(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
trace_i915_gem_object_destroy(obj);
return 0;
}
+/*
+ * 965+ support PIPE_CONTROL commands, which provide finer grained control
+ * over cache flushing.
+ */
+static int
+i915_gem_init_pipe_control(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ obj = drm_gem_object_alloc(dev, 4096);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate seqno page\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ obj_priv = to_intel_bo(obj);
+ obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+
+ ret = i915_gem_object_pin(obj, 4096);
+ if (ret)
+ goto err_unref;
+
+ dev_priv->seqno_gfx_addr = obj_priv->gtt_offset;
+ dev_priv->seqno_page = kmap(obj_priv->pages[0]);
+ if (dev_priv->seqno_page == NULL)
+ goto err_unpin;
+
+ dev_priv->seqno_obj = obj;
+ memset(dev_priv->seqno_page, 0, PAGE_SIZE);
+
+ return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+err_unref:
+ drm_gem_object_unreference(obj);
+err:
+ return ret;
+}
+
static int
i915_gem_init_hws(struct drm_device *dev)
{
obj = drm_gem_object_alloc(dev, 4096);
if (obj == NULL) {
DRM_ERROR("Failed to allocate status page\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err;
}
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
ret = i915_gem_object_pin(obj, 4096);
if (ret != 0) {
drm_gem_object_unreference(obj);
- return ret;
+ goto err_unref;
}
dev_priv->status_gfx_addr = obj_priv->gtt_offset;
if (dev_priv->hw_status_page == NULL) {
DRM_ERROR("Failed to map status page.\n");
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_unpin;
}
+
+ if (HAS_PIPE_CONTROL(dev)) {
+ ret = i915_gem_init_pipe_control(dev);
+ if (ret)
+ goto err_unpin;
+ }
+
dev_priv->hws_obj = obj;
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
if (IS_GEN6(dev)) {
DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+err_unref:
+ drm_gem_object_unreference(obj);
+err:
+ return 0;
+}
+
+static void
+i915_gem_cleanup_pipe_control(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj = dev_priv->seqno_obj;
+ obj_priv = to_intel_bo(obj);
+ kunmap(obj_priv->pages[0]);
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
+ dev_priv->seqno_obj = NULL;
+
+ dev_priv->seqno_page = NULL;
}
static void
return;
obj = dev_priv->hws_obj;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
kunmap(obj_priv->pages[0]);
i915_gem_object_unpin(obj);
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
dev_priv->hw_status_page = NULL;
+ if (HAS_PIPE_CONTROL(dev))
+ i915_gem_cleanup_pipe_control(dev);
+
/* Write high address into HWS_PGA when disabling. */
I915_WRITE(HWS_PGA, 0x1ffff000);
}
i915_gem_cleanup_hws(dev);
return -ENOMEM;
}
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
ret = i915_gem_object_pin(obj, 4096);
if (ret != 0) {
int ret;
int page_count;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (!obj_priv->phys_obj)
return;
if (id > I915_MAX_PHYS_OBJECT)
return -EINVAL;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (obj_priv->phys_obj) {
if (obj_priv->phys_obj->id == id)
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
void *obj_addr;
int ret;
char __user *user_data;
i915_gem_dump_object(struct drm_gem_object *obj, int len,
const char *where, uint32_t mark)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page;
DRM_INFO("%s: object at offset %08x\n", where, obj_priv->gtt_offset);
i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page;
uint32_t *gtt_mapping;
uint32_t *backing_map = NULL;
* reg, so dont bother to check the size */
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
return false;
- } else if (IS_I9XX(dev)) {
- uint32_t pitch_val = ffs(stride / tile_width) - 1;
-
- /* XXX: For Y tiling, FENCE_MAX_PITCH_VAL is actually 6 (8KB)
- * instead of 4 (2KB) on 945s.
- */
- if (pitch_val > I915_FENCE_MAX_PITCH_VAL ||
- size > (I830_FENCE_MAX_SIZE_VAL << 20))
+ } else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+ if (stride > 8192)
return false;
- } else {
- uint32_t pitch_val = ffs(stride / tile_width) - 1;
- if (pitch_val > I830_FENCE_MAX_PITCH_VAL ||
- size > (I830_FENCE_MAX_SIZE_VAL << 19))
- return false;
+ if (IS_GEN3(dev)) {
+ if (size > I830_FENCE_MAX_SIZE_VAL << 20)
+ return false;
+ } else {
+ if (size > I830_FENCE_MAX_SIZE_VAL << 19)
+ return false;
+ }
}
/* 965+ just needs multiples of tile width */
i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode)
{
struct drm_device *dev = obj->dev;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if (obj_priv->gtt_space == NULL)
return true;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EINVAL;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) {
drm_gem_object_unreference_unlocked(obj);
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL)
return -EINVAL;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
mutex_lock(&dev->struct_mutex);
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page_count = obj->size >> PAGE_SHIFT;
int i;
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int page_count = obj->size >> PAGE_SHIFT;
int i;
if (mode_config->num_connector) {
list_for_each_entry(connector, &mode_config->connector_list, head) {
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- if (intel_output->hot_plug)
- (*intel_output->hot_plug) (intel_output);
+ if (intel_encoder->hot_plug)
+ (*intel_encoder->hot_plug) (intel_encoder);
}
}
/* Just fire off a uevent and let userspace tell us what to do */
READ_BREADCRUMB(dev_priv);
}
- if (gt_iir & GT_USER_INTERRUPT) {
+ if (gt_iir & GT_PIPE_NOTIFY) {
u32 seqno = i915_get_gem_seqno(dev);
dev_priv->mm.irq_gem_seqno = seqno;
trace_i915_gem_request_complete(dev, seqno);
if (src == NULL)
return NULL;
- src_priv = src->driver_private;
+ src_priv = to_intel_bo(src);
if (src_priv->pages == NULL)
return NULL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
if (HAS_PCH_SPLIT(dev))
- ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+ ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
else
i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
}
BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
if (HAS_PCH_SPLIT(dev))
- ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
+ ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
else
i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
}
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
- u32 render_mask = GT_USER_INTERRUPT;
+ u32 render_mask = GT_PIPE_NOTIFY;
u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
struct drm_connector *connector;
+ acpi_handle handle;
+ struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
+ unsigned long long device_id;
+ acpi_status status;
int i = 0;
+ handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
+ if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev)))
+ return;
+
+ if (acpi_is_video_device(acpi_dev))
+ acpi_video_bus = acpi_dev;
+ else {
+ list_for_each_entry(acpi_cdev, &acpi_dev->children, node) {
+ if (acpi_is_video_device(acpi_cdev)) {
+ acpi_video_bus = acpi_cdev;
+ break;
+ }
+ }
+ }
+
+ if (!acpi_video_bus) {
+ printk(KERN_WARNING "No ACPI video bus found\n");
+ return;
+ }
+
+ list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
+ if (i >= 8) {
+ dev_printk (KERN_ERR, &dev->pdev->dev,
+ "More than 8 outputs detected\n");
+ return;
+ }
+ status =
+ acpi_evaluate_integer(acpi_cdev->handle, "_ADR",
+ NULL, &device_id);
+ if (ACPI_SUCCESS(status)) {
+ if (!device_id)
+ goto blind_set;
+ opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+ i++;
+ }
+ }
+
+end:
+ /* If fewer than 8 outputs, the list must be null terminated */
+ if (i < 8)
+ opregion->acpi->didl[i] = 0;
+ return;
+
+blind_set:
+ i = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
int output_type = ACPI_OTHER_OUTPUT;
if (i >= 8) {
opregion->acpi->didl[i] |= (1<<31) | output_type | i;
i++;
}
-
- /* If fewer than 8 outputs, the list must be null terminated */
- if (i < 8)
- opregion->acpi->didl[i] = 0;
+ goto end;
}
int intel_opregion_init(struct drm_device *dev, int resume)
#define ASYNC_FLIP (1<<22)
#define DISPLAY_PLANE_A (0<<20)
#define DISPLAY_PLANE_B (1<<20)
+#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
+#define PIPE_CONTROL_QW_WRITE (1<<14)
+#define PIPE_CONTROL_DEPTH_STALL (1<<13)
+#define PIPE_CONTROL_WC_FLUSH (1<<12)
+#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
+#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
+#define PIPE_CONTROL_ISP_DIS (1<<9)
+#define PIPE_CONTROL_NOTIFY (1<<8)
+#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
+#define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */
/*
* Fence registers
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
#define I830_FENCE_PITCH_SHIFT 4
#define I830_FENCE_REG_VALID (1<<0)
-#define I915_FENCE_MAX_PITCH_VAL 0x10
+#define I915_FENCE_MAX_PITCH_VAL 4
#define I830_FENCE_MAX_PITCH_VAL 6
#define I830_FENCE_MAX_SIZE_VAL (1<<8)
#define DEIER 0x4400c
/* GT interrupt */
+#define GT_PIPE_NOTIFY (1 << 4)
#define GT_SYNC_STATUS (1 << 2)
#define GT_USER_INTERRUPT (1 << 0)
static bool intel_crt_detect_ddc(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
/* CRT should always be at 0, but check anyway */
- if (intel_output->type != INTEL_OUTPUT_ANALOG)
+ if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
return false;
- return intel_ddc_probe(intel_output);
+ return intel_ddc_probe(intel_encoder);
}
static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_output *intel_output)
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
{
- struct drm_encoder *encoder = &intel_output->enc;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output = to_intel_output(connector);
- struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_crtc *crtc;
int dpms_mode;
enum drm_connector_status status;
/* for pre-945g platforms use load detect */
if (encoder->crtc && encoder->crtc->enabled) {
- status = intel_crt_load_detect(encoder->crtc, intel_output);
+ status = intel_crt_load_detect(encoder->crtc, intel_encoder);
} else {
- crtc = intel_get_load_detect_pipe(intel_output,
+ crtc = intel_get_load_detect_pipe(intel_encoder,
NULL, &dpms_mode);
if (crtc) {
- status = intel_crt_load_detect(crtc, intel_output);
- intel_release_load_detect_pipe(intel_output, dpms_mode);
+ status = intel_crt_load_detect(crtc, intel_encoder);
+ intel_release_load_detect_pipe(intel_encoder, dpms_mode);
} else
status = connector_status_unknown;
}
static void intel_crt_destroy(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- intel_i2c_destroy(intel_output->ddc_bus);
+ intel_i2c_destroy(intel_encoder->ddc_bus);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
kfree(connector);
static int intel_crt_get_modes(struct drm_connector *connector)
{
int ret;
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
struct i2c_adapter *ddcbus;
struct drm_device *dev = connector->dev;
- ret = intel_ddc_get_modes(intel_output);
+ ret = intel_ddc_get_modes(intel_encoder);
if (ret || !IS_G4X(dev))
goto end;
- ddcbus = intel_output->ddc_bus;
+ ddcbus = intel_encoder->ddc_bus;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
- intel_output->ddc_bus =
+ intel_encoder->ddc_bus =
intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
- if (!intel_output->ddc_bus) {
- intel_output->ddc_bus = ddcbus;
+ if (!intel_encoder->ddc_bus) {
+ intel_encoder->ddc_bus = ddcbus;
dev_printk(KERN_ERR, &connector->dev->pdev->dev,
"DDC bus registration failed for CRTDDC_D.\n");
goto end;
}
/* Try to get modes by GPIOD port */
- ret = intel_ddc_get_modes(intel_output);
+ ret = intel_ddc_get_modes(intel_encoder);
intel_i2c_destroy(ddcbus);
end:
void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 i2c_reg;
- intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
- if (!intel_output)
+ intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
+ if (!intel_encoder)
return;
- connector = &intel_output->base;
- drm_connector_init(dev, &intel_output->base,
+ connector = &intel_encoder->base;
+ drm_connector_init(dev, &intel_encoder->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
- drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC);
- drm_mode_connector_attach_encoder(&intel_output->base,
- &intel_output->enc);
+ drm_mode_connector_attach_encoder(&intel_encoder->base,
+ &intel_encoder->enc);
/* Set up the DDC bus. */
if (HAS_PCH_SPLIT(dev))
if (dev_priv->crt_ddc_bus != 0)
i2c_reg = dev_priv->crt_ddc_bus;
}
- intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
- if (!intel_output->ddc_bus) {
+ intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
+ if (!intel_encoder->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
return;
}
- intel_output->type = INTEL_OUTPUT_ANALOG;
- intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ intel_encoder->type = INTEL_OUTPUT_ANALOG;
+ intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
- drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
list_for_each_entry(l_entry, &mode_config->connector_list, head) {
if (l_entry->encoder &&
l_entry->encoder->crtc == crtc) {
- struct intel_output *intel_output = to_intel_output(l_entry);
- if (intel_output->type == type)
+ struct intel_encoder *intel_encoder = to_intel_encoder(l_entry);
+ if (intel_encoder->type == type)
return true;
}
}
return false;
}
-struct drm_connector *
-intel_pipe_get_output (struct drm_crtc *crtc)
+static struct drm_connector *
+intel_pipe_get_connector (struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane, i;
u32 fbc_ctl, fbc_ctl2;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj_priv = intel_fb->obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
DPFC_CTL_PLANEB);
return;
intel_fb = to_intel_framebuffer(fb);
- obj_priv = intel_fb->obj->driver_private;
+ obj_priv = to_intel_bo(intel_fb->obj);
/*
* If FBC is already on, we just have to verify that we can
static int
intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
{
- struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
u32 alignment;
int ret;
intel_fb = to_intel_framebuffer(crtc->fb);
obj = intel_fb->obj;
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev, obj);
if (old_fb) {
intel_fb = to_intel_framebuffer(old_fb);
- obj_priv = intel_fb->obj->driver_private;
+ obj_priv = to_intel_bo(intel_fb->obj);
i915_gem_object_unpin(intel_fb->obj);
}
intel_increase_pllclock(crtc, true);
int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
- int refclk, num_outputs = 0;
+ int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
drm_vblank_pre_modeset(dev, pipe);
list_for_each_entry(connector, &mode_config->connector_list, head) {
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
if (!connector->encoder || connector->encoder->crtc != crtc)
continue;
- switch (intel_output->type) {
+ switch (intel_encoder->type) {
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
case INTEL_OUTPUT_SDVO:
case INTEL_OUTPUT_HDMI:
is_sdvo = true;
- if (intel_output->needs_tv_clock)
+ if (intel_encoder->needs_tv_clock)
is_tv = true;
break;
case INTEL_OUTPUT_DVO:
break;
}
- num_outputs++;
+ num_connectors++;
}
- if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) {
+ if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
refclk = dev_priv->lvds_ssc_freq * 1000;
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
refclk / 1000);
if (is_edp) {
struct drm_connector *edp;
target_clock = mode->clock;
- edp = intel_pipe_get_output(crtc);
- intel_edp_link_config(to_intel_output(edp),
+ edp = intel_pipe_get_connector(crtc);
+ intel_edp_link_config(to_intel_encoder(edp),
&lane, &link_bw);
} else {
/* DP over FDI requires target mode clock
/* XXX: just matching BIOS for now */
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
- else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2)
+ else if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
dpll |= PLL_REF_INPUT_DREFCLK;
if (!bo)
return -ENOENT;
- obj_priv = bo->driver_private;
+ obj_priv = to_intel_bo(bo);
if (bo->size < width * height * 4) {
DRM_ERROR("buffer is to small\n");
* detection.
*
* It will be up to the load-detect code to adjust the pipe as appropriate for
- * its requirements. The pipe will be connected to no other outputs.
+ * its requirements. The pipe will be connected to no other encoders.
*
- * Currently this code will only succeed if there is a pipe with no outputs
+ * Currently this code will only succeed if there is a pipe with no encoders
* configured for it. In the future, it could choose to temporarily disable
* some outputs to free up a pipe for its use.
*
704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
};
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
+struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode,
int *dpms_mode)
{
struct intel_crtc *intel_crtc;
struct drm_crtc *possible_crtc;
struct drm_crtc *supported_crtc =NULL;
- struct drm_encoder *encoder = &intel_output->enc;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_crtc *crtc = NULL;
struct drm_device *dev = encoder->dev;
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
}
encoder->crtc = crtc;
- intel_output->base.encoder = encoder;
- intel_output->load_detect_temp = true;
+ intel_encoder->base.encoder = encoder;
+ intel_encoder->load_detect_temp = true;
intel_crtc = to_intel_crtc(crtc);
*dpms_mode = intel_crtc->dpms_mode;
return crtc;
}
-void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_mode)
+void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder, int dpms_mode)
{
- struct drm_encoder *encoder = &intel_output->enc;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_device *dev = encoder->dev;
struct drm_crtc *crtc = encoder->crtc;
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- if (intel_output->load_detect_temp) {
+ if (intel_encoder->load_detect_temp) {
encoder->crtc = NULL;
- intel_output->base.encoder = NULL;
- intel_output->load_detect_temp = false;
+ intel_encoder->base.encoder = NULL;
+ intel_encoder->load_detect_temp = false;
crtc->enabled = drm_helper_crtc_in_use(crtc);
drm_helper_disable_unused_functions(dev);
}
- /* Switch crtc and output back off if necessary */
+ /* Switch crtc and encoder back off if necessary */
if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
if (encoder->crtc == crtc)
encoder_funcs->dpms(encoder, dpms_mode);
work = intel_crtc->unpin_work;
if (work == NULL || !work->pending) {
if (work && !work->pending) {
- obj_priv = work->pending_flip_obj->driver_private;
+ obj_priv = to_intel_bo(work->pending_flip_obj);
DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n",
obj_priv,
atomic_read(&obj_priv->pending_flip));
spin_unlock_irqrestore(&dev->event_lock, flags);
- obj_priv = work->pending_flip_obj->driver_private;
+ obj_priv = to_intel_bo(work->pending_flip_obj);
/* Initial scanout buffer will have a 0 pending flip count */
if ((atomic_read(&obj_priv->pending_flip) == 0) ||
ret = intel_pin_and_fence_fb_obj(dev, obj);
if (ret != 0) {
DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
- obj->driver_private);
+ to_intel_bo(obj));
kfree(work);
intel_crtc->unpin_work = NULL;
mutex_unlock(&dev->struct_mutex);
crtc->fb = fb;
i915_gem_object_flush_write_domain(obj);
drm_vblank_get(dev, intel_crtc->pipe);
- obj_priv = obj->driver_private;
+ obj_priv = to_intel_bo(obj);
atomic_inc(&obj_priv->pending_flip);
work->pending_flip_obj = obj;
int entry = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct intel_output *intel_output = to_intel_output(connector);
- if (type_mask & intel_output->clone_mask)
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ if (type_mask & intel_encoder->clone_mask)
index_mask |= (1 << entry);
entry++;
}
intel_tv_init(dev);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- struct intel_output *intel_output = to_intel_output(connector);
- struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct drm_encoder *encoder = &intel_encoder->enc;
- encoder->possible_crtcs = intel_output->crtc_mask;
+ encoder->possible_crtcs = intel_encoder->crtc_mask;
encoder->possible_clones = intel_connector_clones(dev,
- intel_output->clone_mask);
+ intel_encoder->clone_mask);
}
}
struct drm_i915_gem_object *obj_priv = NULL;
if (dev_priv->pwrctx) {
- obj_priv = dev_priv->pwrctx->driver_private;
+ obj_priv = to_intel_bo(dev_priv->pwrctx);
} else {
struct drm_gem_object *pwrctx;
pwrctx = intel_alloc_power_context(dev);
if (pwrctx) {
dev_priv->pwrctx = pwrctx;
- obj_priv = pwrctx->driver_private;
+ obj_priv = to_intel_bo(pwrctx);
}
}
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
dev_priv->display.enable_fbc = g4x_enable_fbc;
dev_priv->display.disable_fbc = g4x_disable_fbc;
- } else if (IS_I965GM(dev) || IS_I945GM(dev) || IS_I915GM(dev)) {
+ } else if (IS_I965GM(dev)) {
dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
dev_priv->display.enable_fbc = i8xx_enable_fbc;
dev_priv->display.disable_fbc = i8xx_disable_fbc;
dev_priv->display.update_wm = g4x_update_wm;
else if (IS_I965G(dev))
dev_priv->display.update_wm = i965_update_wm;
- else if (IS_I9XX(dev) || IS_MOBILE(dev)) {
+ else if (IS_I9XX(dev)) {
dev_priv->display.update_wm = i9xx_update_wm;
dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+ } else if (IS_I85X(dev)) {
+ dev_priv->display.update_wm = i9xx_update_wm;
+ dev_priv->display.get_fifo_size = i85x_get_fifo_size;
} else {
- if (IS_I85X(dev))
- dev_priv->display.get_fifo_size = i85x_get_fifo_size;
- else if (IS_845G(dev))
+ dev_priv->display.update_wm = i830_update_wm;
+ if (IS_845G(dev))
dev_priv->display.get_fifo_size = i845_get_fifo_size;
else
dev_priv->display.get_fifo_size = i830_get_fifo_size;
- dev_priv->display.update_wm = i830_update_wm;
}
}
if (dev_priv->pwrctx) {
struct drm_i915_gem_object *obj_priv;
- obj_priv = dev_priv->pwrctx->driver_private;
+ obj_priv = to_intel_bo(dev_priv->pwrctx);
I915_WRITE(PWRCTXA, obj_priv->gtt_offset &~ PWRCTX_EN);
I915_READ(PWRCTXA);
i915_gem_object_unpin(dev_priv->pwrctx);
*/
struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- return &intel_output->enc;
+ return &intel_encoder->enc;
}
/*
uint8_t link_bw;
uint8_t lane_count;
uint8_t dpcd[4];
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo;
};
static void
-intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]);
static void
-intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
+intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP);
void
-intel_edp_link_config (struct intel_output *intel_output,
+intel_edp_link_config (struct intel_encoder *intel_encoder,
int *lane_num, int *link_bw)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
*lane_num = dp_priv->lane_count;
if (dp_priv->link_bw == DP_LINK_BW_1_62)
}
static int
-intel_dp_max_lane_count(struct intel_output *intel_output)
+intel_dp_max_lane_count(struct intel_encoder *intel_encoder)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int max_lane_count = 4;
if (dp_priv->dpcd[0] >= 0x11) {
}
static int
-intel_dp_max_link_bw(struct intel_output *intel_output)
+intel_dp_max_link_bw(struct intel_encoder *intel_encoder)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int max_link_bw = dp_priv->dpcd[1];
switch (max_link_bw) {
/* I think this is a fiction */
static int
intel_dp_link_required(struct drm_device *dev,
- struct intel_output *intel_output, int pixel_clock)
+ struct intel_encoder *intel_encoder, int pixel_clock)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_eDP(intel_output))
+ if (IS_eDP(intel_encoder))
return (pixel_clock * dev_priv->edp_bpp) / 8;
else
return pixel_clock * 3;
intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct intel_output *intel_output = to_intel_output(connector);
- int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
- int max_lanes = intel_dp_max_lane_count(intel_output);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder));
+ int max_lanes = intel_dp_max_lane_count(intel_encoder);
- if (intel_dp_link_required(connector->dev, intel_output, mode->clock)
+ if (intel_dp_link_required(connector->dev, intel_encoder, mode->clock)
> max_link_clock * max_lanes)
return MODE_CLOCK_HIGH;
}
static int
-intel_dp_aux_ch(struct intel_output *intel_output,
+intel_dp_aux_ch(struct intel_encoder *intel_encoder,
uint8_t *send, int send_bytes,
uint8_t *recv, int recv_size)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
uint32_t output_reg = dp_priv->output_reg;
- struct drm_device *dev = intel_output->base.dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t ch_ctl = output_reg + 0x10;
uint32_t ch_data = ch_ctl + 4;
* and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that
*/
- if (IS_eDP(intel_output))
+ if (IS_eDP(intel_encoder))
aux_clock_divider = 225; /* eDP input clock at 450Mhz */
else if (HAS_PCH_SPLIT(dev))
aux_clock_divider = 62; /* IRL input clock fixed at 125Mhz */
/* Write data to the aux channel in native mode */
static int
-intel_dp_aux_native_write(struct intel_output *intel_output,
+intel_dp_aux_native_write(struct intel_encoder *intel_encoder,
uint16_t address, uint8_t *send, int send_bytes)
{
int ret;
memcpy(&msg[4], send, send_bytes);
msg_bytes = send_bytes + 4;
for (;;) {
- ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, &ack, 1);
+ ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes, &ack, 1);
if (ret < 0)
return ret;
if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
/* Write a single byte to the aux channel in native mode */
static int
-intel_dp_aux_native_write_1(struct intel_output *intel_output,
+intel_dp_aux_native_write_1(struct intel_encoder *intel_encoder,
uint16_t address, uint8_t byte)
{
- return intel_dp_aux_native_write(intel_output, address, &byte, 1);
+ return intel_dp_aux_native_write(intel_encoder, address, &byte, 1);
}
/* read bytes from a native aux channel */
static int
-intel_dp_aux_native_read(struct intel_output *intel_output,
+intel_dp_aux_native_read(struct intel_encoder *intel_encoder,
uint16_t address, uint8_t *recv, int recv_bytes)
{
uint8_t msg[4];
reply_bytes = recv_bytes + 1;
for (;;) {
- ret = intel_dp_aux_ch(intel_output, msg, msg_bytes,
+ ret = intel_dp_aux_ch(intel_encoder, msg, msg_bytes,
reply, reply_bytes);
if (ret == 0)
return -EPROTO;
struct intel_dp_priv *dp_priv = container_of(adapter,
struct intel_dp_priv,
adapter);
- struct intel_output *intel_output = dp_priv->intel_output;
+ struct intel_encoder *intel_encoder = dp_priv->intel_encoder;
uint16_t address = algo_data->address;
uint8_t msg[5];
uint8_t reply[2];
}
for (;;) {
- ret = intel_dp_aux_ch(intel_output,
+ ret = intel_dp_aux_ch(intel_encoder,
msg, msg_bytes,
reply, reply_bytes);
if (ret < 0) {
}
static int
-intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
+intel_dp_i2c_init(struct intel_encoder *intel_encoder, const char *name)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
DRM_DEBUG_KMS("i2c_init %s\n", name);
dp_priv->algo.running = false;
strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1);
dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0';
dp_priv->adapter.algo_data = &dp_priv->algo;
- dp_priv->adapter.dev.parent = &intel_output->base.kdev;
+ dp_priv->adapter.dev.parent = &intel_encoder->base.kdev;
return i2c_dp_aux_add_bus(&dp_priv->adapter);
}
intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int lane_count, clock;
- int max_lane_count = intel_dp_max_lane_count(intel_output);
- int max_clock = intel_dp_max_link_bw(intel_output) == DP_LINK_BW_2_7 ? 1 : 0;
+ int max_lane_count = intel_dp_max_lane_count(intel_encoder);
+ int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
- if (intel_dp_link_required(encoder->dev, intel_output, mode->clock)
+ if (intel_dp_link_required(encoder->dev, intel_encoder, mode->clock)
<= link_avail) {
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
struct intel_dp_m_n m_n;
/*
- * Find the lane count in the intel_output private
+ * Find the lane count in the intel_encoder private
*/
list_for_each_entry(connector, &mode_config->connector_list, head) {
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
if (!connector->encoder || connector->encoder->crtc != crtc)
continue;
- if (intel_output->type == INTEL_OUTPUT_DISPLAYPORT) {
+ if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
lane_count = dp_priv->lane_count;
break;
}
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
- struct drm_crtc *crtc = intel_output->enc.crtc;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+ struct drm_crtc *crtc = intel_encoder->enc.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
dp_priv->DP = (DP_LINK_TRAIN_OFF |
if (intel_crtc->pipe == 1)
dp_priv->DP |= DP_PIPEB_SELECT;
- if (IS_eDP(intel_output)) {
+ if (IS_eDP(intel_encoder)) {
/* don't miss out required setting for eDP */
dp_priv->DP |= DP_PLL_ENABLE;
if (adjusted_mode->clock < 200000)
static void
intel_dp_dpms(struct drm_encoder *encoder, int mode)
{
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
- struct drm_device *dev = intel_output->base.dev;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t dp_reg = I915_READ(dp_priv->output_reg);
if (mode != DRM_MODE_DPMS_ON) {
if (dp_reg & DP_PORT_EN) {
- intel_dp_link_down(intel_output, dp_priv->DP);
- if (IS_eDP(intel_output))
+ intel_dp_link_down(intel_encoder, dp_priv->DP);
+ if (IS_eDP(intel_encoder))
ironlake_edp_backlight_off(dev);
}
} else {
if (!(dp_reg & DP_PORT_EN)) {
- intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
- if (IS_eDP(intel_output))
+ intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
+ if (IS_eDP(intel_encoder))
ironlake_edp_backlight_on(dev);
}
}
* link status information
*/
static bool
-intel_dp_get_link_status(struct intel_output *intel_output,
+intel_dp_get_link_status(struct intel_encoder *intel_encoder,
uint8_t link_status[DP_LINK_STATUS_SIZE])
{
int ret;
- ret = intel_dp_aux_native_read(intel_output,
+ ret = intel_dp_aux_native_read(intel_encoder,
DP_LANE0_1_STATUS,
link_status, DP_LINK_STATUS_SIZE);
if (ret != DP_LINK_STATUS_SIZE)
static void
intel_dp_save(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct drm_device *dev = intel_output->base.dev;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
dp_priv->save_DP = I915_READ(dp_priv->output_reg);
- intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET,
+ intel_dp_aux_native_read(intel_encoder, DP_LINK_BW_SET,
dp_priv->save_link_configuration,
sizeof (dp_priv->save_link_configuration));
}
}
static void
-intel_get_adjust_train(struct intel_output *intel_output,
+intel_get_adjust_train(struct intel_encoder *intel_encoder,
uint8_t link_status[DP_LINK_STATUS_SIZE],
int lane_count,
uint8_t train_set[4])
}
static bool
-intel_dp_set_link_train(struct intel_output *intel_output,
+intel_dp_set_link_train(struct intel_encoder *intel_encoder,
uint32_t dp_reg_value,
uint8_t dp_train_pat,
uint8_t train_set[4],
bool first)
{
- struct drm_device *dev = intel_output->base.dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
int ret;
I915_WRITE(dp_priv->output_reg, dp_reg_value);
if (first)
intel_wait_for_vblank(dev);
- intel_dp_aux_native_write_1(intel_output,
+ intel_dp_aux_native_write_1(intel_encoder,
DP_TRAINING_PATTERN_SET,
dp_train_pat);
- ret = intel_dp_aux_native_write(intel_output,
+ ret = intel_dp_aux_native_write(intel_encoder,
DP_TRAINING_LANE0_SET, train_set, 4);
if (ret != 4)
return false;
}
static void
-intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+intel_dp_link_train(struct intel_encoder *intel_encoder, uint32_t DP,
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
{
- struct drm_device *dev = intel_output->base.dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
uint8_t train_set[4];
uint8_t link_status[DP_LINK_STATUS_SIZE];
int i;
int tries;
/* Write the link configuration data */
- intel_dp_aux_native_write(intel_output, 0x100,
+ intel_dp_aux_native_write(intel_encoder, 0x100,
link_configuration, DP_LINK_CONFIGURATION_SIZE);
DP |= DP_PORT_EN;
uint32_t signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
- if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_1,
+ if (!intel_dp_set_link_train(intel_encoder, DP | DP_LINK_TRAIN_PAT_1,
DP_TRAINING_PATTERN_1, train_set, first))
break;
first = false;
/* Set training pattern 1 */
udelay(100);
- if (!intel_dp_get_link_status(intel_output, link_status))
+ if (!intel_dp_get_link_status(intel_encoder, link_status))
break;
if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) {
voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new train_set as requested by target */
- intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+ intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set);
}
/* channel equalization */
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
/* channel eq pattern */
- if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_2,
+ if (!intel_dp_set_link_train(intel_encoder, DP | DP_LINK_TRAIN_PAT_2,
DP_TRAINING_PATTERN_2, train_set,
false))
break;
udelay(400);
- if (!intel_dp_get_link_status(intel_output, link_status))
+ if (!intel_dp_get_link_status(intel_encoder, link_status))
break;
if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) {
break;
/* Compute new train_set as requested by target */
- intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+ intel_get_adjust_train(intel_encoder, link_status, dp_priv->lane_count, train_set);
++tries;
}
I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
POSTING_READ(dp_priv->output_reg);
- intel_dp_aux_native_write_1(intel_output,
+ intel_dp_aux_native_write_1(intel_encoder,
DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
}
static void
-intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
+intel_dp_link_down(struct intel_encoder *intel_encoder, uint32_t DP)
{
- struct drm_device *dev = intel_output->base.dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
DRM_DEBUG_KMS("\n");
- if (IS_eDP(intel_output)) {
+ if (IS_eDP(intel_encoder)) {
DP &= ~DP_PLL_ENABLE;
I915_WRITE(dp_priv->output_reg, DP);
POSTING_READ(dp_priv->output_reg);
udelay(17000);
- if (IS_eDP(intel_output))
+ if (IS_eDP(intel_encoder))
DP |= DP_LINK_TRAIN_OFF;
I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(dp_priv->output_reg);
static void
intel_dp_restore(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
if (dp_priv->save_DP & DP_PORT_EN)
- intel_dp_link_train(intel_output, dp_priv->save_DP, dp_priv->save_link_configuration);
+ intel_dp_link_train(intel_encoder, dp_priv->save_DP, dp_priv->save_link_configuration);
else
- intel_dp_link_down(intel_output, dp_priv->save_DP);
+ intel_dp_link_down(intel_encoder, dp_priv->save_DP);
}
/*
*/
static void
-intel_dp_check_link_status(struct intel_output *intel_output)
+intel_dp_check_link_status(struct intel_encoder *intel_encoder)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
uint8_t link_status[DP_LINK_STATUS_SIZE];
- if (!intel_output->enc.crtc)
+ if (!intel_encoder->enc.crtc)
return;
- if (!intel_dp_get_link_status(intel_output, link_status)) {
- intel_dp_link_down(intel_output, dp_priv->DP);
+ if (!intel_dp_get_link_status(intel_encoder, link_status)) {
+ intel_dp_link_down(intel_encoder, dp_priv->DP);
return;
}
if (!intel_channel_eq_ok(link_status, dp_priv->lane_count))
- intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+ intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
}
static enum drm_connector_status
ironlake_dp_detect(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
enum drm_connector_status status;
status = connector_status_disconnected;
- if (intel_dp_aux_native_read(intel_output,
+ if (intel_dp_aux_native_read(intel_encoder,
0x000, dp_priv->dpcd,
sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
{
static enum drm_connector_status
intel_dp_detect(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct drm_device *dev = intel_output->base.dev;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
uint32_t temp, bit;
enum drm_connector_status status;
return connector_status_disconnected;
status = connector_status_disconnected;
- if (intel_dp_aux_native_read(intel_output,
+ if (intel_dp_aux_native_read(intel_encoder,
0x000, dp_priv->dpcd,
sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
{
static int intel_dp_get_modes(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct drm_device *dev = intel_output->base.dev;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
/* We should parse the EDID data and find out if it has an audio sink
*/
- ret = intel_ddc_get_modes(intel_output);
+ ret = intel_ddc_get_modes(intel_encoder);
if (ret)
return ret;
/* if eDP has no EDID, try to use fixed panel mode from VBT */
- if (IS_eDP(intel_output)) {
+ if (IS_eDP(intel_encoder)) {
if (dev_priv->panel_fixed_mode != NULL) {
struct drm_display_mode *mode;
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
static void
intel_dp_destroy (struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- if (intel_output->i2c_bus)
- intel_i2c_destroy(intel_output->i2c_bus);
+ if (intel_encoder->i2c_bus)
+ intel_i2c_destroy(intel_encoder->i2c_bus);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
}
static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
};
void
-intel_dp_hot_plug(struct intel_output *intel_output)
+intel_dp_hot_plug(struct intel_encoder *intel_encoder)
{
- struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct intel_dp_priv *dp_priv = intel_encoder->dev_priv;
if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
- intel_dp_check_link_status(intel_output);
+ intel_dp_check_link_status(intel_encoder);
}
void
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_dp_priv *dp_priv;
const char *name = NULL;
- intel_output = kcalloc(sizeof(struct intel_output) +
+ intel_encoder = kcalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
- if (!intel_output)
+ if (!intel_encoder)
return;
- dp_priv = (struct intel_dp_priv *)(intel_output + 1);
+ dp_priv = (struct intel_dp_priv *)(intel_encoder + 1);
- connector = &intel_output->base;
+ connector = &intel_encoder->base;
drm_connector_init(dev, connector, &intel_dp_connector_funcs,
DRM_MODE_CONNECTOR_DisplayPort);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
if (output_reg == DP_A)
- intel_output->type = INTEL_OUTPUT_EDP;
+ intel_encoder->type = INTEL_OUTPUT_EDP;
else
- intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+ intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
if (output_reg == DP_B || output_reg == PCH_DP_B)
- intel_output->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
+ intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
else if (output_reg == DP_C || output_reg == PCH_DP_C)
- intel_output->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
+ intel_encoder->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
else if (output_reg == DP_D || output_reg == PCH_DP_D)
- intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
+ intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
- if (IS_eDP(intel_output))
- intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
+ if (IS_eDP(intel_encoder))
+ intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
- dp_priv->intel_output = intel_output;
+ dp_priv->intel_encoder = intel_encoder;
dp_priv->output_reg = output_reg;
dp_priv->has_audio = false;
dp_priv->dpms_mode = DRM_MODE_DPMS_ON;
- intel_output->dev_priv = dp_priv;
+ intel_encoder->dev_priv = dp_priv;
- drm_encoder_init(dev, &intel_output->enc, &intel_dp_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(&intel_output->enc, &intel_dp_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_output->base,
- &intel_output->enc);
+ drm_mode_connector_attach_encoder(&intel_encoder->base,
+ &intel_encoder->enc);
drm_sysfs_connector_add(connector);
/* Set up the DDC bus. */
break;
}
- intel_dp_i2c_init(intel_output, name);
+ intel_dp_i2c_init(intel_encoder, name);
- intel_output->ddc_bus = &dp_priv->adapter;
- intel_output->hot_plug = intel_dp_hot_plug;
+ intel_encoder->ddc_bus = &dp_priv->adapter;
+ intel_encoder->hot_plug = intel_dp_hot_plug;
if (output_reg == DP_A) {
/* initialize panel mode from VBT if available for eDP */
};
-struct intel_output {
+struct intel_encoder {
struct drm_connector base;
struct drm_encoder enc;
bool load_detect_temp;
bool needs_tv_clock;
void *dev_priv;
- void (*hot_plug)(struct intel_output *);
+ void (*hot_plug)(struct intel_encoder *);
int crtc_mask;
int clone_mask;
};
};
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
-#define to_intel_output(x) container_of(x, struct intel_output, base)
-#define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
+#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
const char *name);
void intel_i2c_destroy(struct i2c_adapter *adapter);
-int intel_ddc_get_modes(struct intel_output *intel_output);
-extern bool intel_ddc_probe(struct intel_output *intel_output);
+int intel_ddc_get_modes(struct intel_encoder *intel_encoder);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
void intel_i2c_reset_gmbus(struct drm_device *dev);
void
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
-extern void intel_edp_link_config (struct intel_output *, int *, int *);
+extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
extern int intel_panel_fitter_pipe (struct drm_device *dev);
struct drm_file *file_priv);
extern void intel_wait_for_vblank(struct drm_device *dev);
extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output,
+extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_display_mode *mode,
int *dpms_mode);
-extern void intel_release_load_detect_pipe(struct intel_output *intel_output,
+extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
int dpms_mode);
extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
u32 dvo_reg = dvo->dvo_reg;
u32 temp = I915_READ(dvo_reg);
static void intel_dvo_save(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
/* Each output should probably just save the registers it touches,
* but for now, use more overkill.
static void intel_dvo_restore(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = connector->dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
dvo->dev_ops->restore(dvo);
static int intel_dvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
/* If we have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
int pipe = intel_crtc->pipe;
u32 dvo_val;
u32 dvo_reg = dvo->dvo_reg, dvo_srcdim_reg;
*/
static enum drm_connector_status intel_dvo_detect(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
return dvo->dev_ops->detect(dvo);
}
static int intel_dvo_get_modes(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
/* We should probably have an i2c driver get_modes function for those
* devices which will have a fixed set of modes determined by the chip
* (TV-out, for example), but for now with just TMDS and LVDS,
* that's not the case.
*/
- intel_ddc_get_modes(intel_output);
+ intel_ddc_get_modes(intel_encoder);
if (!list_empty(&connector->probed_modes))
return 1;
static void intel_dvo_destroy (struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
if (dvo) {
if (dvo->dev_ops->destroy)
/* no need, in i830_dvoices[] now */
//kfree(dvo);
}
- if (intel_output->i2c_bus)
- intel_i2c_destroy(intel_output->i2c_bus);
- if (intel_output->ddc_bus)
- intel_i2c_destroy(intel_output->ddc_bus);
+ if (intel_encoder->i2c_bus)
+ intel_i2c_destroy(intel_encoder->i2c_bus);
+ if (intel_encoder->ddc_bus)
+ intel_i2c_destroy(intel_encoder->ddc_bus);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
}
#ifdef RANDR_GET_CRTC_INTERFACE
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
int pipe = !!(I915_READ(dvo->dvo_reg) & SDVO_PIPE_B_SELECT);
return intel_pipe_to_crtc(pScrn, pipe);
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_dvo_device *dvo = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_dvo_device *dvo = intel_encoder->dev_priv;
uint32_t dvo_reg = dvo->dvo_reg;
uint32_t dvo_val = I915_READ(dvo_reg);
struct drm_display_mode *mode = NULL;
void intel_dvo_init(struct drm_device *dev)
{
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_dvo_device *dvo;
struct i2c_adapter *i2cbus = NULL;
int ret = 0;
int i;
int encoder_type = DRM_MODE_ENCODER_NONE;
- intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL);
- if (!intel_output)
+ intel_encoder = kzalloc (sizeof(struct intel_encoder), GFP_KERNEL);
+ if (!intel_encoder)
return;
/* Set up the DDC bus */
- intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
- if (!intel_output->ddc_bus)
+ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
+ if (!intel_encoder->ddc_bus)
goto free_intel;
/* Now, try to find a controller */
for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
- struct drm_connector *connector = &intel_output->base;
+ struct drm_connector *connector = &intel_encoder->base;
int gpio;
dvo = &intel_dvo_devices[i];
if (!ret)
continue;
- intel_output->type = INTEL_OUTPUT_DVO;
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->type = INTEL_OUTPUT_DVO;
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
switch (dvo->type) {
case INTEL_DVO_CHIP_TMDS:
- intel_output->clone_mask =
+ intel_encoder->clone_mask =
(1 << INTEL_DVO_TMDS_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
drm_connector_init(dev, connector,
encoder_type = DRM_MODE_ENCODER_TMDS;
break;
case INTEL_DVO_CHIP_LVDS:
- intel_output->clone_mask =
+ intel_encoder->clone_mask =
(1 << INTEL_DVO_LVDS_CLONE_BIT);
drm_connector_init(dev, connector,
&intel_dvo_connector_funcs,
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- intel_output->dev_priv = dvo;
- intel_output->i2c_bus = i2cbus;
+ intel_encoder->dev_priv = dvo;
+ intel_encoder->i2c_bus = i2cbus;
- drm_encoder_init(dev, &intel_output->enc,
+ drm_encoder_init(dev, &intel_encoder->enc,
&intel_dvo_enc_funcs, encoder_type);
- drm_encoder_helper_add(&intel_output->enc,
+ drm_encoder_helper_add(&intel_encoder->enc,
&intel_dvo_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_output->base,
- &intel_output->enc);
+ drm_mode_connector_attach_encoder(&intel_encoder->base,
+ &intel_encoder->enc);
if (dvo->type == INTEL_DVO_CHIP_LVDS) {
/* For our LVDS chipsets, we should hopefully be able
* to dig the fixed panel mode out of the BIOS data.
return;
}
- intel_i2c_destroy(intel_output->ddc_bus);
+ intel_i2c_destroy(intel_encoder->ddc_bus);
/* Didn't find a chip, so tear down. */
if (i2cbus != NULL)
intel_i2c_destroy(i2cbus);
free_intel:
- kfree(intel_output);
+ kfree(intel_encoder);
}
ret = -ENOMEM;
goto out;
}
- obj_priv = fbo->driver_private;
+ obj_priv = to_intel_bo(fbo);
mutex_lock(&dev->struct_mutex);
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 sdvox;
sdvox = SDVO_ENCODING_HDMI |
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
u32 temp;
temp = I915_READ(hdmi_priv->sdvox_reg);
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
hdmi_priv->save_SDVOX = I915_READ(hdmi_priv->sdvox_reg);
}
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
I915_WRITE(hdmi_priv->sdvox_reg, hdmi_priv->save_SDVOX);
POSTING_READ(hdmi_priv->sdvox_reg);
static enum drm_connector_status
intel_hdmi_detect(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv;
struct edid *edid = NULL;
enum drm_connector_status status = connector_status_disconnected;
hdmi_priv->has_hdmi_sink = false;
- edid = drm_get_edid(&intel_output->base,
- intel_output->ddc_bus);
+ edid = drm_get_edid(&intel_encoder->base,
+ intel_encoder->ddc_bus);
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
status = connector_status_connected;
hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
}
- intel_output->base.display_info.raw_edid = NULL;
+ intel_encoder->base.display_info.raw_edid = NULL;
kfree(edid);
}
static int intel_hdmi_get_modes(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
/* We should parse the EDID data and find out if it's an HDMI sink so
* we can send audio to it.
*/
- return intel_ddc_get_modes(intel_output);
+ return intel_ddc_get_modes(intel_encoder);
}
static void intel_hdmi_destroy(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- if (intel_output->i2c_bus)
- intel_i2c_destroy(intel_output->i2c_bus);
+ if (intel_encoder->i2c_bus)
+ intel_i2c_destroy(intel_encoder->i2c_bus);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
}
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_hdmi_priv *hdmi_priv;
- intel_output = kcalloc(sizeof(struct intel_output) +
+ intel_encoder = kcalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL);
- if (!intel_output)
+ if (!intel_encoder)
return;
- hdmi_priv = (struct intel_hdmi_priv *)(intel_output + 1);
+ hdmi_priv = (struct intel_hdmi_priv *)(intel_encoder + 1);
- connector = &intel_output->base;
+ connector = &intel_encoder->base;
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
- intel_output->type = INTEL_OUTPUT_HDMI;
+ intel_encoder->type = INTEL_OUTPUT_HDMI;
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
/* Set up the DDC bus. */
if (sdvox_reg == SDVOB) {
- intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
- intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
+ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == SDVOC) {
- intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
- intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
+ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIB) {
- intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
- intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
+ intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
+ intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
"HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIC) {
- intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
- intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
+ intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
+ intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
"HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMID) {
- intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
- intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
+ intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
+ intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
"HDMID");
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
}
- if (!intel_output->ddc_bus)
+ if (!intel_encoder->ddc_bus)
goto err_connector;
hdmi_priv->sdvox_reg = sdvox_reg;
- intel_output->dev_priv = hdmi_priv;
+ intel_encoder->dev_priv = hdmi_priv;
- drm_encoder_init(dev, &intel_output->enc, &intel_hdmi_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
DRM_MODE_ENCODER_TMDS);
- drm_encoder_helper_add(&intel_output->enc, &intel_hdmi_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_output->base,
- &intel_output->enc);
+ drm_mode_connector_attach_encoder(&intel_encoder->base,
+ &intel_encoder->enc);
drm_sysfs_connector_add(connector);
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
err_connector:
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
return;
}
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct drm_encoder *tmp_encoder;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
u32 pfit_control = 0, pfit_pgm_ratios = 0;
int left_border = 0, right_border = 0, top_border = 0;
int bottom_border = 0;
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
/*
* The LVDS pin pair will already have been turned on in the
static int intel_lvds_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
struct drm_i915_private *dev_priv = dev->dev_private;
int ret = 0;
- ret = intel_ddc_get_modes(intel_output);
+ if (dev_priv->lvds_edid_good) {
+ ret = intel_ddc_get_modes(intel_encoder);
- if (ret)
- return ret;
+ if (ret)
+ return ret;
+ }
/* Didn't get an EDID, so
* Set wide sync ranges so we get all modes
static void intel_lvds_destroy(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
struct drm_i915_private *dev_priv = dev->dev_private;
- if (intel_output->ddc_bus)
- intel_i2c_destroy(intel_output->ddc_bus);
+ if (intel_encoder->ddc_bus)
+ intel_i2c_destroy(intel_encoder->ddc_bus);
if (dev_priv->lid_notifier.notifier_call)
acpi_lid_notifier_unregister(&dev_priv->lid_notifier);
drm_sysfs_connector_remove(connector);
uint64_t value)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output =
- to_intel_output(connector);
+ struct intel_encoder *intel_encoder =
+ to_intel_encoder(connector);
if (property == dev->mode_config.scaling_mode_property &&
connector->encoder) {
struct drm_crtc *crtc = connector->encoder->crtc;
- struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+ struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv;
if (value == DRM_MODE_SCALE_NONE) {
DRM_DEBUG_KMS("no scaling not supported\n");
return 0;
DMI_MATCH(DMI_PRODUCT_VERSION, "AO00001JW"),
},
},
+ {
+ .callback = intel_no_lvds_dmi_callback,
+ .ident = "Clientron U800",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Clientron"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "U800"),
+ },
+ },
{ } /* terminating entry */
};
void intel_lvds_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_display_mode *scan; /* *modes, *bios_mode; */
gpio = PCH_GPIOC;
}
- intel_output = kzalloc(sizeof(struct intel_output) +
+ intel_encoder = kzalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_lvds_priv), GFP_KERNEL);
- if (!intel_output) {
+ if (!intel_encoder) {
return;
}
- connector = &intel_output->base;
- encoder = &intel_output->enc;
- drm_connector_init(dev, &intel_output->base, &intel_lvds_connector_funcs,
+ connector = &intel_encoder->base;
+ encoder = &intel_encoder->enc;
+ drm_connector_init(dev, &intel_encoder->base, &intel_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
- drm_encoder_init(dev, &intel_output->enc, &intel_lvds_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
DRM_MODE_ENCODER_LVDS);
- drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
- intel_output->type = INTEL_OUTPUT_LVDS;
+ drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
+ intel_encoder->type = INTEL_OUTPUT_LVDS;
- intel_output->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
- intel_output->crtc_mask = (1 << 1);
+ intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
+ intel_encoder->crtc_mask = (1 << 1);
drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
- lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
- intel_output->dev_priv = lvds_priv;
+ lvds_priv = (struct intel_lvds_priv *)(intel_encoder + 1);
+ intel_encoder->dev_priv = lvds_priv;
/* create the scaling mode property */
drm_mode_create_scaling_mode_property(dev);
/*
* the initial panel fitting mode will be FULL_SCREEN.
*/
- drm_connector_attach_property(&intel_output->base,
+ drm_connector_attach_property(&intel_encoder->base,
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_FULLSCREEN);
lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN;
*/
/* Set up the DDC bus. */
- intel_output->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
- if (!intel_output->ddc_bus) {
+ intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
+ if (!intel_encoder->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
goto failed;
* Attempt to get the fixed panel mode from DDC. Assume that the
* preferred mode is the right one.
*/
- intel_ddc_get_modes(intel_output);
+ dev_priv->lvds_edid_good = true;
+
+ if (!intel_ddc_get_modes(intel_encoder))
+ dev_priv->lvds_edid_good = false;
list_for_each_entry(scan, &connector->probed_modes, head) {
mutex_lock(&dev->mode_config.mutex);
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
- if (intel_output->ddc_bus)
- intel_i2c_destroy(intel_output->ddc_bus);
+ if (intel_encoder->ddc_bus)
+ intel_i2c_destroy(intel_encoder->ddc_bus);
drm_connector_cleanup(connector);
drm_encoder_cleanup(encoder);
- kfree(intel_output);
+ kfree(intel_encoder);
}
* intel_ddc_probe
*
*/
-bool intel_ddc_probe(struct intel_output *intel_output)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder)
{
u8 out_buf[] = { 0x0, 0x0};
u8 buf[2];
}
};
- intel_i2c_quirk_set(intel_output->base.dev, true);
- ret = i2c_transfer(intel_output->ddc_bus, msgs, 2);
- intel_i2c_quirk_set(intel_output->base.dev, false);
+ intel_i2c_quirk_set(intel_encoder->base.dev, true);
+ ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
+ intel_i2c_quirk_set(intel_encoder->base.dev, false);
if (ret == 2)
return true;
*
* Fetch the EDID information from @connector using the DDC bus.
*/
-int intel_ddc_get_modes(struct intel_output *intel_output)
+int intel_ddc_get_modes(struct intel_encoder *intel_encoder)
{
struct edid *edid;
int ret = 0;
- intel_i2c_quirk_set(intel_output->base.dev, true);
- edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus);
- intel_i2c_quirk_set(intel_output->base.dev, false);
+ intel_i2c_quirk_set(intel_encoder->base.dev, true);
+ edid = drm_get_edid(&intel_encoder->base, intel_encoder->ddc_bus);
+ intel_i2c_quirk_set(intel_encoder->base.dev, false);
if (edid) {
- drm_mode_connector_update_edid_property(&intel_output->base,
+ drm_mode_connector_update_edid_property(&intel_encoder->base,
edid);
- ret = drm_add_edid_modes(&intel_output->base, edid);
- intel_output->base.display_info.raw_edid = NULL;
+ ret = drm_add_edid_modes(&intel_encoder->base, edid);
+ intel_encoder->base.display_info.raw_edid = NULL;
kfree(edid);
}
int ret, tmp_width;
struct overlay_registers *regs;
bool scale_changed = false;
- struct drm_i915_gem_object *bo_priv = new_bo->driver_private;
+ struct drm_i915_gem_object *bo_priv = to_intel_bo(new_bo);
struct drm_device *dev = overlay->dev;
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
intel_overlay_continue(overlay, scale_changed);
overlay->old_vid_bo = overlay->vid_bo;
- overlay->vid_bo = new_bo->driver_private;
+ overlay->vid_bo = to_intel_bo(new_bo);
return 0;
reg_bo = drm_gem_object_alloc(dev, PAGE_SIZE);
if (!reg_bo)
goto out_free;
- overlay->reg_bo = reg_bo->driver_private;
+ overlay->reg_bo = to_intel_bo(reg_bo);
if (OVERLAY_NONPHYSICAL(dev)) {
ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
u8 slave_addr;
/* Register for the SDVO device: SDVOB or SDVOC */
- int output_device;
+ int sdvo_reg;
/* Active outputs controlled by this SDVO output */
uint16_t controlled_output;
*/
struct intel_sdvo_encode encode;
- /* DDC bus used by this SDVO output */
+ /* DDC bus used by this SDVO encoder */
uint8_t ddc_bus;
/* Mac mini hack -- use the same DDC as the analog connector */
};
static bool
-intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags);
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags);
/**
* Writes the SDVOB or SDVOC with the given value, but always writes both
* SDVOB and SDVOC to work around apparent hardware issues (according to
* comments in the BIOS).
*/
-static void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val)
+static void intel_sdvo_write_sdvox(struct intel_encoder *intel_encoder, u32 val)
{
- struct drm_device *dev = intel_output->base.dev;
+ struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u32 bval = val, cval = val;
int i;
- if (sdvo_priv->output_device == SDVOB) {
+ if (sdvo_priv->sdvo_reg == SDVOB) {
cval = I915_READ(SDVOC);
} else {
bval = I915_READ(SDVOB);
}
}
-static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
+static bool intel_sdvo_read_byte(struct intel_encoder *intel_encoder, u8 addr,
u8 *ch)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u8 out_buf[2];
u8 buf[2];
int ret;
out_buf[0] = addr;
out_buf[1] = 0;
- if ((ret = i2c_transfer(intel_output->i2c_bus, msgs, 2)) == 2)
+ if ((ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 2)) == 2)
{
*ch = buf[0];
return true;
return false;
}
-static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
+static bool intel_sdvo_write_byte(struct intel_encoder *intel_encoder, int addr,
u8 ch)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u8 out_buf[2];
struct i2c_msg msgs[] = {
{
out_buf[0] = addr;
out_buf[1] = ch;
- if (i2c_transfer(intel_output->i2c_bus, msgs, 1) == 1)
+ if (i2c_transfer(intel_encoder->i2c_bus, msgs, 1) == 1)
{
return true;
}
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
};
-#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
-#define SDVO_PRIV(output) ((struct intel_sdvo_priv *) (output)->dev_priv)
+#define SDVO_NAME(dev_priv) ((dev_priv)->sdvo_reg == SDVOB ? "SDVOB" : "SDVOC")
+#define SDVO_PRIV(encoder) ((struct intel_sdvo_priv *) (encoder)->dev_priv)
-static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
+static void intel_sdvo_debug_write(struct intel_encoder *intel_encoder, u8 cmd,
void *args, int args_len)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int i;
DRM_DEBUG_KMS("%s: W: %02X ",
DRM_LOG_KMS("\n");
}
-static void intel_sdvo_write_cmd(struct intel_output *intel_output, u8 cmd,
+static void intel_sdvo_write_cmd(struct intel_encoder *intel_encoder, u8 cmd,
void *args, int args_len)
{
int i;
- intel_sdvo_debug_write(intel_output, cmd, args, args_len);
+ intel_sdvo_debug_write(intel_encoder, cmd, args, args_len);
for (i = 0; i < args_len; i++) {
- intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0 - i,
+ intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0 - i,
((u8*)args)[i]);
}
- intel_sdvo_write_byte(intel_output, SDVO_I2C_OPCODE, cmd);
+ intel_sdvo_write_byte(intel_encoder, SDVO_I2C_OPCODE, cmd);
}
static const char *cmd_status_names[] = {
"Scaling not supported"
};
-static void intel_sdvo_debug_response(struct intel_output *intel_output,
+static void intel_sdvo_debug_response(struct intel_encoder *intel_encoder,
void *response, int response_len,
u8 status)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int i;
DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(sdvo_priv));
DRM_LOG_KMS("\n");
}
-static u8 intel_sdvo_read_response(struct intel_output *intel_output,
+static u8 intel_sdvo_read_response(struct intel_encoder *intel_encoder,
void *response, int response_len)
{
int i;
while (retry--) {
/* Read the command response */
for (i = 0; i < response_len; i++) {
- intel_sdvo_read_byte(intel_output,
+ intel_sdvo_read_byte(intel_encoder,
SDVO_I2C_RETURN_0 + i,
&((u8 *)response)[i]);
}
/* read the return status */
- intel_sdvo_read_byte(intel_output, SDVO_I2C_CMD_STATUS,
+ intel_sdvo_read_byte(intel_encoder, SDVO_I2C_CMD_STATUS,
&status);
- intel_sdvo_debug_response(intel_output, response, response_len,
+ intel_sdvo_debug_response(intel_encoder, response, response_len,
status);
if (status != SDVO_CMD_STATUS_PENDING)
return status;
* another I2C transaction after issuing the DDC bus switch, it will be
* switched to the internal SDVO register.
*/
-static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
+static void intel_sdvo_set_control_bus_switch(struct intel_encoder *intel_encoder,
u8 target)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
struct i2c_msg msgs[] = {
{
},
};
- intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+ intel_sdvo_debug_write(intel_encoder, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
&target, 1);
/* write the DDC switch command argument */
- intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target);
+ intel_sdvo_write_byte(intel_encoder, SDVO_I2C_ARG_0, target);
out_buf[0] = SDVO_I2C_OPCODE;
out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
ret_value[0] = 0;
ret_value[1] = 0;
- ret = i2c_transfer(intel_output->i2c_bus, msgs, 3);
+ ret = i2c_transfer(intel_encoder->i2c_bus, msgs, 3);
if (ret != 3) {
/* failure in I2C transfer */
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
return;
}
-static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
+static bool intel_sdvo_set_target_input(struct intel_encoder *intel_encoder, bool target_0, bool target_1)
{
struct intel_sdvo_set_target_input_args targets = {0};
u8 status;
if (target_1)
targets.target_1 = 1;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_INPUT, &targets,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_INPUT, &targets,
sizeof(targets));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
* This function is making an assumption about the layout of the response,
* which should be checked against the docs.
*/
-static bool intel_sdvo_get_trained_inputs(struct intel_output *intel_output, bool *input_1, bool *input_2)
+static bool intel_sdvo_get_trained_inputs(struct intel_encoder *intel_encoder, bool *input_1, bool *input_2)
{
struct intel_sdvo_get_trained_inputs_response response;
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &response, sizeof(response));
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &response, sizeof(response));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return true;
}
-static bool intel_sdvo_get_active_outputs(struct intel_output *intel_output,
+static bool intel_sdvo_get_active_outputs(struct intel_encoder *intel_encoder,
u16 *outputs)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
- status = intel_sdvo_read_response(intel_output, outputs, sizeof(*outputs));
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, outputs, sizeof(*outputs));
return (status == SDVO_CMD_STATUS_SUCCESS);
}
-static bool intel_sdvo_set_active_outputs(struct intel_output *intel_output,
+static bool intel_sdvo_set_active_outputs(struct intel_encoder *intel_encoder,
u16 outputs)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs,
sizeof(outputs));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
-static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output,
+static bool intel_sdvo_set_encoder_power_state(struct intel_encoder *intel_encoder,
int mode)
{
u8 status, state = SDVO_ENCODER_STATE_ON;
break;
}
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
sizeof(state));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
-static bool intel_sdvo_get_input_pixel_clock_range(struct intel_output *intel_output,
+static bool intel_sdvo_get_input_pixel_clock_range(struct intel_encoder *intel_encoder,
int *clock_min,
int *clock_max)
{
struct intel_sdvo_pixel_clock_range clocks;
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
NULL, 0);
- status = intel_sdvo_read_response(intel_output, &clocks, sizeof(clocks));
+ status = intel_sdvo_read_response(intel_encoder, &clocks, sizeof(clocks));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return true;
}
-static bool intel_sdvo_set_target_output(struct intel_output *intel_output,
+static bool intel_sdvo_set_target_output(struct intel_encoder *intel_encoder,
u16 outputs)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TARGET_OUTPUT, &outputs,
sizeof(outputs));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
-static bool intel_sdvo_get_timing(struct intel_output *intel_output, u8 cmd,
+static bool intel_sdvo_get_timing(struct intel_encoder *intel_encoder, u8 cmd,
struct intel_sdvo_dtd *dtd)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, cmd, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &dtd->part1,
+ intel_sdvo_write_cmd(intel_encoder, cmd, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &dtd->part1,
sizeof(dtd->part1));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
- intel_sdvo_write_cmd(intel_output, cmd + 1, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &dtd->part2,
+ intel_sdvo_write_cmd(intel_encoder, cmd + 1, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &dtd->part2,
sizeof(dtd->part2));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return true;
}
-static bool intel_sdvo_get_input_timing(struct intel_output *intel_output,
+static bool intel_sdvo_get_input_timing(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd *dtd)
{
- return intel_sdvo_get_timing(intel_output,
+ return intel_sdvo_get_timing(intel_encoder,
SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
}
-static bool intel_sdvo_get_output_timing(struct intel_output *intel_output,
+static bool intel_sdvo_get_output_timing(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd *dtd)
{
- return intel_sdvo_get_timing(intel_output,
+ return intel_sdvo_get_timing(intel_encoder,
SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd);
}
-static bool intel_sdvo_set_timing(struct intel_output *intel_output, u8 cmd,
+static bool intel_sdvo_set_timing(struct intel_encoder *intel_encoder, u8 cmd,
struct intel_sdvo_dtd *dtd)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, cmd, &dtd->part1, sizeof(dtd->part1));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ intel_sdvo_write_cmd(intel_encoder, cmd, &dtd->part1, sizeof(dtd->part1));
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
- intel_sdvo_write_cmd(intel_output, cmd + 1, &dtd->part2, sizeof(dtd->part2));
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ intel_sdvo_write_cmd(intel_encoder, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return true;
}
-static bool intel_sdvo_set_input_timing(struct intel_output *intel_output,
+static bool intel_sdvo_set_input_timing(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd *dtd)
{
- return intel_sdvo_set_timing(intel_output,
+ return intel_sdvo_set_timing(intel_encoder,
SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
}
-static bool intel_sdvo_set_output_timing(struct intel_output *intel_output,
+static bool intel_sdvo_set_output_timing(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd *dtd)
{
- return intel_sdvo_set_timing(intel_output,
+ return intel_sdvo_set_timing(intel_encoder,
SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
}
static bool
-intel_sdvo_create_preferred_input_timing(struct intel_output *output,
+intel_sdvo_create_preferred_input_timing(struct intel_encoder *intel_encoder,
uint16_t clock,
uint16_t width,
uint16_t height)
{
struct intel_sdvo_preferred_input_timing_args args;
- struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
uint8_t status;
memset(&args, 0, sizeof(args));
sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
args.scaled = 1;
- intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
+ intel_sdvo_write_cmd(intel_encoder,
+ SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
&args, sizeof(args));
- status = intel_sdvo_read_response(output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return true;
}
-static bool intel_sdvo_get_preferred_input_timing(struct intel_output *output,
+static bool intel_sdvo_get_preferred_input_timing(struct intel_encoder *intel_encoder,
struct intel_sdvo_dtd *dtd)
{
bool status;
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
NULL, 0);
- status = intel_sdvo_read_response(output, &dtd->part1,
+ status = intel_sdvo_read_response(intel_encoder, &dtd->part1,
sizeof(dtd->part1));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
NULL, 0);
- status = intel_sdvo_read_response(output, &dtd->part2,
+ status = intel_sdvo_read_response(intel_encoder, &dtd->part2,
sizeof(dtd->part2));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
return false;
}
-static int intel_sdvo_get_clock_rate_mult(struct intel_output *intel_output)
+static int intel_sdvo_get_clock_rate_mult(struct intel_encoder *intel_encoder)
{
u8 response, status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &response, 1);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &response, 1);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Couldn't get SDVO clock rate multiplier\n");
return response;
}
-static bool intel_sdvo_set_clock_rate_mult(struct intel_output *intel_output, u8 val)
+static bool intel_sdvo_set_clock_rate_mult(struct intel_encoder *intel_encoder, u8 val)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
- status = intel_sdvo_read_response(intel_output, NULL, 0);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
mode->flags |= DRM_MODE_FLAG_PVSYNC;
}
-static bool intel_sdvo_get_supp_encode(struct intel_output *output,
+static bool intel_sdvo_get_supp_encode(struct intel_encoder *intel_encoder,
struct intel_sdvo_encode *encode)
{
uint8_t status;
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0);
- status = intel_sdvo_read_response(output, encode, sizeof(*encode));
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPP_ENCODE, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, encode, sizeof(*encode));
if (status != SDVO_CMD_STATUS_SUCCESS) { /* non-support means DVI */
memset(encode, 0, sizeof(*encode));
return false;
return true;
}
-static bool intel_sdvo_set_encode(struct intel_output *output, uint8_t mode)
+static bool intel_sdvo_set_encode(struct intel_encoder *intel_encoder,
+ uint8_t mode)
{
uint8_t status;
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODE, &mode, 1);
- status = intel_sdvo_read_response(output, NULL, 0);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ENCODE, &mode, 1);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
-static bool intel_sdvo_set_colorimetry(struct intel_output *output,
+static bool intel_sdvo_set_colorimetry(struct intel_encoder *intel_encoder,
uint8_t mode)
{
uint8_t status;
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
- status = intel_sdvo_read_response(output, NULL, 0);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
return (status == SDVO_CMD_STATUS_SUCCESS);
}
#if 0
-static void intel_sdvo_dump_hdmi_buf(struct intel_output *output)
+static void intel_sdvo_dump_hdmi_buf(struct intel_encoder *intel_encoder)
{
int i, j;
uint8_t set_buf_index[2];
uint8_t buf[48];
uint8_t *pos;
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0);
- intel_sdvo_read_response(output, &av_split, 1);
+ intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_AV_SPLIT, NULL, 0);
+ intel_sdvo_read_response(encoder, &av_split, 1);
for (i = 0; i <= av_split; i++) {
set_buf_index[0] = i; set_buf_index[1] = 0;
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX,
+ intel_sdvo_write_cmd(encoder, SDVO_CMD_SET_HBUF_INDEX,
set_buf_index, 2);
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
- intel_sdvo_read_response(output, &buf_size, 1);
+ intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_INFO, NULL, 0);
+ intel_sdvo_read_response(encoder, &buf_size, 1);
pos = buf;
for (j = 0; j <= buf_size; j += 8) {
- intel_sdvo_write_cmd(output, SDVO_CMD_GET_HBUF_DATA,
+ intel_sdvo_write_cmd(encoder, SDVO_CMD_GET_HBUF_DATA,
NULL, 0);
- intel_sdvo_read_response(output, pos, 8);
+ intel_sdvo_read_response(encoder, pos, 8);
pos += 8;
}
}
}
#endif
-static void intel_sdvo_set_hdmi_buf(struct intel_output *output, int index,
- uint8_t *data, int8_t size, uint8_t tx_rate)
+static void intel_sdvo_set_hdmi_buf(struct intel_encoder *intel_encoder,
+ int index,
+ uint8_t *data, int8_t size, uint8_t tx_rate)
{
uint8_t set_buf_index[2];
set_buf_index[0] = index;
set_buf_index[1] = 0;
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_INDEX, set_buf_index, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_INDEX,
+ set_buf_index, 2);
for (; size > 0; size -= 8) {
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_DATA, data, 8);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_DATA, data, 8);
data += 8;
}
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_HBUF_TXRATE, &tx_rate, 1);
}
static uint8_t intel_sdvo_calc_hbuf_csum(uint8_t *data, uint8_t size)
} __attribute__ ((packed)) u;
} __attribute__((packed));
-static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
+static void intel_sdvo_set_avi_infoframe(struct intel_encoder *intel_encoder,
struct drm_display_mode * mode)
{
struct dip_infoframe avi_if = {
avi_if.checksum = intel_sdvo_calc_hbuf_csum((uint8_t *)&avi_if,
4 + avi_if.len);
- intel_sdvo_set_hdmi_buf(output, 1, (uint8_t *)&avi_if, 4 + avi_if.len,
+ intel_sdvo_set_hdmi_buf(intel_encoder, 1, (uint8_t *)&avi_if,
+ 4 + avi_if.len,
SDVO_HBUF_TX_VSYNC);
}
-static void intel_sdvo_set_tv_format(struct intel_output *output)
+static void intel_sdvo_set_tv_format(struct intel_encoder *intel_encoder)
{
struct intel_sdvo_tv_format format;
- struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
uint32_t format_map, i;
uint8_t status;
memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
sizeof(format) : sizeof(format_map));
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, &format_map,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_TV_FORMAT, &format_map,
sizeof(format));
- status = intel_sdvo_read_response(output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS)
DRM_DEBUG_KMS("%s: Failed to set TV format\n",
SDVO_NAME(sdvo_priv));
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct intel_output *output = enc_to_intel_output(encoder);
- struct intel_sdvo_priv *dev_priv = output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_sdvo_priv *dev_priv = intel_encoder->dev_priv;
if (dev_priv->is_tv) {
struct intel_sdvo_dtd output_dtd;
/* Set output timings */
intel_sdvo_get_dtd_from_mode(&output_dtd, mode);
- intel_sdvo_set_target_output(output,
+ intel_sdvo_set_target_output(intel_encoder,
dev_priv->controlled_output);
- intel_sdvo_set_output_timing(output, &output_dtd);
+ intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
/* Set the input timing to the screen. Assume always input 0. */
- intel_sdvo_set_target_input(output, true, false);
+ intel_sdvo_set_target_input(intel_encoder, true, false);
- success = intel_sdvo_create_preferred_input_timing(output,
+ success = intel_sdvo_create_preferred_input_timing(intel_encoder,
mode->clock / 10,
mode->hdisplay,
mode->vdisplay);
if (success) {
struct intel_sdvo_dtd input_dtd;
- intel_sdvo_get_preferred_input_timing(output,
+ intel_sdvo_get_preferred_input_timing(intel_encoder,
&input_dtd);
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
intel_sdvo_get_dtd_from_mode(&output_dtd,
dev_priv->sdvo_lvds_fixed_mode);
- intel_sdvo_set_target_output(output,
+ intel_sdvo_set_target_output(intel_encoder,
dev_priv->controlled_output);
- intel_sdvo_set_output_timing(output, &output_dtd);
+ intel_sdvo_set_output_timing(intel_encoder, &output_dtd);
/* Set the input timing to the screen. Assume always input 0. */
- intel_sdvo_set_target_input(output, true, false);
+ intel_sdvo_set_target_input(intel_encoder, true, false);
success = intel_sdvo_create_preferred_input_timing(
- output,
+ intel_encoder,
mode->clock / 10,
mode->hdisplay,
mode->vdisplay);
if (success) {
struct intel_sdvo_dtd input_dtd;
- intel_sdvo_get_preferred_input_timing(output,
+ intel_sdvo_get_preferred_input_timing(intel_encoder,
&input_dtd);
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_output *output = enc_to_intel_output(encoder);
- struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u32 sdvox = 0;
int sdvo_pixel_multiply;
struct intel_sdvo_in_out_map in_out;
in_out.in0 = sdvo_priv->controlled_output;
in_out.in1 = 0;
- intel_sdvo_write_cmd(output, SDVO_CMD_SET_IN_OUT_MAP,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_IN_OUT_MAP,
&in_out, sizeof(in_out));
- status = intel_sdvo_read_response(output, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, NULL, 0);
if (sdvo_priv->is_hdmi) {
- intel_sdvo_set_avi_infoframe(output, mode);
+ intel_sdvo_set_avi_infoframe(intel_encoder, mode);
sdvox |= SDVO_AUDIO_ENABLE;
}
*/
if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
/* Set the output timing to the screen */
- intel_sdvo_set_target_output(output,
+ intel_sdvo_set_target_output(intel_encoder,
sdvo_priv->controlled_output);
- intel_sdvo_set_output_timing(output, &input_dtd);
+ intel_sdvo_set_output_timing(intel_encoder, &input_dtd);
}
/* Set the input timing to the screen. Assume always input 0. */
- intel_sdvo_set_target_input(output, true, false);
+ intel_sdvo_set_target_input(intel_encoder, true, false);
if (sdvo_priv->is_tv)
- intel_sdvo_set_tv_format(output);
+ intel_sdvo_set_tv_format(intel_encoder);
/* We would like to use intel_sdvo_create_preferred_input_timing() to
* provide the device with a timing it can support, if it supports that
* output the preferred timing, and we don't support that currently.
*/
#if 0
- success = intel_sdvo_create_preferred_input_timing(output, clock,
+ success = intel_sdvo_create_preferred_input_timing(encoder, clock,
width, height);
if (success) {
struct intel_sdvo_dtd *input_dtd;
- intel_sdvo_get_preferred_input_timing(output, &input_dtd);
- intel_sdvo_set_input_timing(output, &input_dtd);
+ intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
+ intel_sdvo_set_input_timing(encoder, &input_dtd);
}
#else
- intel_sdvo_set_input_timing(output, &input_dtd);
+ intel_sdvo_set_input_timing(intel_encoder, &input_dtd);
#endif
switch (intel_sdvo_get_pixel_multiplier(mode)) {
case 1:
- intel_sdvo_set_clock_rate_mult(output,
+ intel_sdvo_set_clock_rate_mult(intel_encoder,
SDVO_CLOCK_RATE_MULT_1X);
break;
case 2:
- intel_sdvo_set_clock_rate_mult(output,
+ intel_sdvo_set_clock_rate_mult(intel_encoder,
SDVO_CLOCK_RATE_MULT_2X);
break;
case 4:
- intel_sdvo_set_clock_rate_mult(output,
+ intel_sdvo_set_clock_rate_mult(intel_encoder,
SDVO_CLOCK_RATE_MULT_4X);
break;
}
SDVO_VSYNC_ACTIVE_HIGH |
SDVO_HSYNC_ACTIVE_HIGH;
} else {
- sdvox |= I915_READ(sdvo_priv->output_device);
- switch (sdvo_priv->output_device) {
+ sdvox |= I915_READ(sdvo_priv->sdvo_reg);
+ switch (sdvo_priv->sdvo_reg) {
case SDVOB:
sdvox &= SDVOB_PRESERVE_MASK;
break;
if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
sdvox |= SDVO_STALL_SELECT;
- intel_sdvo_write_sdvox(output, sdvox);
+ intel_sdvo_write_sdvox(intel_encoder, sdvox);
}
static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
u32 temp;
if (mode != DRM_MODE_DPMS_ON) {
- intel_sdvo_set_active_outputs(intel_output, 0);
+ intel_sdvo_set_active_outputs(intel_encoder, 0);
if (0)
- intel_sdvo_set_encoder_power_state(intel_output, mode);
+ intel_sdvo_set_encoder_power_state(intel_encoder, mode);
if (mode == DRM_MODE_DPMS_OFF) {
- temp = I915_READ(sdvo_priv->output_device);
+ temp = I915_READ(sdvo_priv->sdvo_reg);
if ((temp & SDVO_ENABLE) != 0) {
- intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE);
+ intel_sdvo_write_sdvox(intel_encoder, temp & ~SDVO_ENABLE);
}
}
} else {
int i;
u8 status;
- temp = I915_READ(sdvo_priv->output_device);
+ temp = I915_READ(sdvo_priv->sdvo_reg);
if ((temp & SDVO_ENABLE) == 0)
- intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE);
+ intel_sdvo_write_sdvox(intel_encoder, temp | SDVO_ENABLE);
for (i = 0; i < 2; i++)
intel_wait_for_vblank(dev);
- status = intel_sdvo_get_trained_inputs(intel_output, &input1,
+ status = intel_sdvo_get_trained_inputs(intel_encoder, &input1,
&input2);
}
if (0)
- intel_sdvo_set_encoder_power_state(intel_output, mode);
- intel_sdvo_set_active_outputs(intel_output, sdvo_priv->controlled_output);
+ intel_sdvo_set_encoder_power_state(intel_encoder, mode);
+ intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->controlled_output);
}
return;
}
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int o;
- sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_output);
- intel_sdvo_get_active_outputs(intel_output, &sdvo_priv->save_active_outputs);
+ sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(intel_encoder);
+ intel_sdvo_get_active_outputs(intel_encoder, &sdvo_priv->save_active_outputs);
if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
- intel_sdvo_set_target_input(intel_output, true, false);
- intel_sdvo_get_input_timing(intel_output,
+ intel_sdvo_set_target_input(intel_encoder, true, false);
+ intel_sdvo_get_input_timing(intel_encoder,
&sdvo_priv->save_input_dtd_1);
}
if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
- intel_sdvo_set_target_input(intel_output, false, true);
- intel_sdvo_get_input_timing(intel_output,
+ intel_sdvo_set_target_input(intel_encoder, false, true);
+ intel_sdvo_get_input_timing(intel_encoder,
&sdvo_priv->save_input_dtd_2);
}
u16 this_output = (1 << o);
if (sdvo_priv->caps.output_flags & this_output)
{
- intel_sdvo_set_target_output(intel_output, this_output);
- intel_sdvo_get_output_timing(intel_output,
+ intel_sdvo_set_target_output(intel_encoder, this_output);
+ intel_sdvo_get_output_timing(intel_encoder,
&sdvo_priv->save_output_dtd[o]);
}
}
/* XXX: Save TV format/enhancements. */
}
- sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+ sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->sdvo_reg);
}
static void intel_sdvo_restore(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int o;
int i;
bool input1, input2;
u8 status;
- intel_sdvo_set_active_outputs(intel_output, 0);
+ intel_sdvo_set_active_outputs(intel_encoder, 0);
for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
{
u16 this_output = (1 << o);
if (sdvo_priv->caps.output_flags & this_output) {
- intel_sdvo_set_target_output(intel_output, this_output);
- intel_sdvo_set_output_timing(intel_output, &sdvo_priv->save_output_dtd[o]);
+ intel_sdvo_set_target_output(intel_encoder, this_output);
+ intel_sdvo_set_output_timing(intel_encoder, &sdvo_priv->save_output_dtd[o]);
}
}
if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
- intel_sdvo_set_target_input(intel_output, true, false);
- intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_1);
+ intel_sdvo_set_target_input(intel_encoder, true, false);
+ intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_1);
}
if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
- intel_sdvo_set_target_input(intel_output, false, true);
- intel_sdvo_set_input_timing(intel_output, &sdvo_priv->save_input_dtd_2);
+ intel_sdvo_set_target_input(intel_encoder, false, true);
+ intel_sdvo_set_input_timing(intel_encoder, &sdvo_priv->save_input_dtd_2);
}
- intel_sdvo_set_clock_rate_mult(intel_output, sdvo_priv->save_sdvo_mult);
+ intel_sdvo_set_clock_rate_mult(intel_encoder, sdvo_priv->save_sdvo_mult);
if (sdvo_priv->is_tv) {
/* XXX: Restore TV format/enhancements. */
}
- intel_sdvo_write_sdvox(intel_output, sdvo_priv->save_SDVOX);
+ intel_sdvo_write_sdvox(intel_encoder, sdvo_priv->save_SDVOX);
if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
{
for (i = 0; i < 2; i++)
intel_wait_for_vblank(dev);
- status = intel_sdvo_get_trained_inputs(intel_output, &input1, &input2);
+ status = intel_sdvo_get_trained_inputs(intel_encoder, &input1, &input2);
if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
DRM_DEBUG_KMS("First %s output reported failure to "
"sync\n", SDVO_NAME(sdvo_priv));
}
- intel_sdvo_set_active_outputs(intel_output, sdvo_priv->save_active_outputs);
+ intel_sdvo_set_active_outputs(intel_encoder, sdvo_priv->save_active_outputs);
}
static int intel_sdvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
return MODE_OK;
}
-static bool intel_sdvo_get_capabilities(struct intel_output *intel_output, struct intel_sdvo_caps *caps)
+static bool intel_sdvo_get_capabilities(struct intel_encoder *intel_encoder, struct intel_sdvo_caps *caps)
{
u8 status;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0);
- status = intel_sdvo_read_response(intel_output, caps, sizeof(*caps));
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, caps, sizeof(*caps));
if (status != SDVO_CMD_STATUS_SUCCESS)
return false;
struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
{
struct drm_connector *connector = NULL;
- struct intel_output *iout = NULL;
+ struct intel_encoder *iout = NULL;
struct intel_sdvo_priv *sdvo;
/* find the sdvo connector */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- iout = to_intel_output(connector);
+ iout = to_intel_encoder(connector);
if (iout->type != INTEL_OUTPUT_SDVO)
continue;
sdvo = iout->dev_priv;
- if (sdvo->output_device == SDVOB && sdvoB)
+ if (sdvo->sdvo_reg == SDVOB && sdvoB)
return connector;
- if (sdvo->output_device == SDVOC && !sdvoB)
+ if (sdvo->sdvo_reg == SDVOC && !sdvoB)
return connector;
}
{
u8 response[2];
u8 status;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
DRM_DEBUG_KMS("\n");
if (!connector)
return 0;
- intel_output = to_intel_output(connector);
+ intel_encoder = to_intel_encoder(connector);
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &response, 2);
if (response[0] !=0)
return 1;
{
u8 response[2];
u8 status;
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_output, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ intel_sdvo_read_response(intel_encoder, &response, 2);
if (on) {
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
- status = intel_sdvo_read_response(intel_output, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+ status = intel_sdvo_read_response(intel_encoder, &response, 2);
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
} else {
response[0] = 0;
response[1] = 0;
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
}
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
- intel_sdvo_read_response(intel_output, &response, 2);
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+ intel_sdvo_read_response(intel_encoder, &response, 2);
}
static bool
-intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
+intel_sdvo_multifunc_encoder(struct intel_encoder *intel_encoder)
{
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int caps = 0;
if (sdvo_priv->caps.output_flags &
intel_find_analog_connector(struct drm_device *dev)
{
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- intel_output = to_intel_output(connector);
- if (intel_output->type == INTEL_OUTPUT_ANALOG)
+ intel_encoder = to_intel_encoder(connector);
+ if (intel_encoder->type == INTEL_OUTPUT_ANALOG)
return connector;
}
return NULL;
enum drm_connector_status
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
enum drm_connector_status status = connector_status_connected;
struct edid *edid = NULL;
- edid = drm_get_edid(&intel_output->base,
- intel_output->ddc_bus);
+ edid = drm_get_edid(&intel_encoder->base,
+ intel_encoder->ddc_bus);
/* This is only applied to SDVO cards with multiple outputs */
- if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) {
+ if (edid == NULL && intel_sdvo_multifunc_encoder(intel_encoder)) {
uint8_t saved_ddc, temp_ddc;
saved_ddc = sdvo_priv->ddc_bus;
temp_ddc = sdvo_priv->ddc_bus >> 1;
*/
while(temp_ddc > 1) {
sdvo_priv->ddc_bus = temp_ddc;
- edid = drm_get_edid(&intel_output->base,
- intel_output->ddc_bus);
+ edid = drm_get_edid(&intel_encoder->base,
+ intel_encoder->ddc_bus);
if (edid) {
/*
* When we can get the EDID, maybe it is the
*/
if (edid == NULL &&
sdvo_priv->analog_ddc_bus &&
- !intel_analog_is_connected(intel_output->base.dev))
- edid = drm_get_edid(&intel_output->base,
+ !intel_analog_is_connected(intel_encoder->base.dev))
+ edid = drm_get_edid(&intel_encoder->base,
sdvo_priv->analog_ddc_bus);
if (edid != NULL) {
/* Don't report the output as connected if it's a DVI-I
}
kfree(edid);
- intel_output->base.display_info.raw_edid = NULL;
+ intel_encoder->base.display_info.raw_edid = NULL;
} else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
status = connector_status_disconnected;
{
uint16_t response;
u8 status;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
if (sdvo_priv->is_tv) {
/* add 30ms delay when the output type is SDVO-TV */
mdelay(30);
}
- status = intel_sdvo_read_response(intel_output, &response, 2);
+ status = intel_sdvo_read_response(intel_encoder, &response, 2);
DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
if (response == 0)
return connector_status_disconnected;
- if (intel_sdvo_multifunc_encoder(intel_output) &&
+ if (intel_sdvo_multifunc_encoder(intel_encoder) &&
sdvo_priv->attached_output != response) {
if (sdvo_priv->controlled_output != response &&
- intel_sdvo_output_setup(intel_output, response) != true)
+ intel_sdvo_output_setup(intel_encoder, response) != true)
return connector_status_unknown;
sdvo_priv->attached_output = response;
}
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
int num_modes;
/* set the bus switch and get the modes */
- num_modes = intel_ddc_get_modes(intel_output);
+ num_modes = intel_ddc_get_modes(intel_encoder);
/*
* Mac mini hack. On this device, the DVI-I connector shares one DDC
*/
if (num_modes == 0 &&
sdvo_priv->analog_ddc_bus &&
- !intel_analog_is_connected(intel_output->base.dev)) {
+ !intel_analog_is_connected(intel_encoder->base.dev)) {
struct i2c_adapter *digital_ddc_bus;
/* Switch to the analog ddc bus and try that
*/
- digital_ddc_bus = intel_output->ddc_bus;
- intel_output->ddc_bus = sdvo_priv->analog_ddc_bus;
+ digital_ddc_bus = intel_encoder->ddc_bus;
+ intel_encoder->ddc_bus = sdvo_priv->analog_ddc_bus;
- (void) intel_ddc_get_modes(intel_output);
+ (void) intel_ddc_get_modes(intel_encoder);
- intel_output->ddc_bus = digital_ddc_bus;
+ intel_encoder->ddc_bus = digital_ddc_bus;
}
}
static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
{
- struct intel_output *output = to_intel_output(connector);
+ struct intel_encoder *output = to_intel_encoder(connector);
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
struct intel_sdvo_sdtv_resolution_request tv_res;
uint32_t reply = 0, format_map = 0;
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
struct drm_display_mode *newmode;
/*
* Assume that the preferred modes are
* arranged in priority order.
*/
- intel_ddc_get_modes(intel_output);
+ intel_ddc_get_modes(intel_encoder);
if (list_empty(&connector->probed_modes) == false)
goto end;
static int intel_sdvo_get_modes(struct drm_connector *connector)
{
- struct intel_output *output = to_intel_output(connector);
+ struct intel_encoder *output = to_intel_encoder(connector);
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
if (sdvo_priv->is_tv)
static
void intel_sdvo_destroy_enhance_property(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
struct drm_device *dev = connector->dev;
if (sdvo_priv->is_tv) {
static void intel_sdvo_destroy(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
- if (intel_output->i2c_bus)
- intel_i2c_destroy(intel_output->i2c_bus);
- if (intel_output->ddc_bus)
- intel_i2c_destroy(intel_output->ddc_bus);
+ if (intel_encoder->i2c_bus)
+ intel_i2c_destroy(intel_encoder->i2c_bus);
+ if (intel_encoder->ddc_bus)
+ intel_i2c_destroy(intel_encoder->ddc_bus);
if (sdvo_priv->analog_ddc_bus)
intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
}
static int
struct drm_property *property,
uint64_t val)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
- struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_crtc *crtc = encoder->crtc;
int ret = 0;
bool changed = false;
sdvo_priv->cur_brightness = temp_value;
}
if (cmd) {
- intel_sdvo_write_cmd(intel_output, cmd, &temp_value, 2);
- status = intel_sdvo_read_response(intel_output,
+ intel_sdvo_write_cmd(intel_encoder, cmd, &temp_value, 2);
+ status = intel_sdvo_read_response(intel_encoder,
NULL, 0);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO command \n");
}
static bool
-intel_sdvo_get_digital_encoding_mode(struct intel_output *output)
+intel_sdvo_get_digital_encoding_mode(struct intel_encoder *output)
{
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
uint8_t status;
return true;
}
-static struct intel_output *
-intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
+static struct intel_encoder *
+intel_sdvo_chan_to_intel_encoder(struct intel_i2c_chan *chan)
{
struct drm_device *dev = chan->drm_dev;
struct drm_connector *connector;
- struct intel_output *intel_output = NULL;
+ struct intel_encoder *intel_encoder = NULL;
list_for_each_entry(connector,
&dev->mode_config.connector_list, head) {
- if (to_intel_output(connector)->ddc_bus == &chan->adapter) {
- intel_output = to_intel_output(connector);
+ if (to_intel_encoder(connector)->ddc_bus == &chan->adapter) {
+ intel_encoder = to_intel_encoder(connector);
break;
}
}
- return intel_output;
+ return intel_encoder;
}
static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_sdvo_priv *sdvo_priv;
struct i2c_algo_bit_data *algo_data;
const struct i2c_algorithm *algo;
algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
- intel_output =
- intel_sdvo_chan_to_intel_output(
+ intel_encoder =
+ intel_sdvo_chan_to_intel_encoder(
(struct intel_i2c_chan *)(algo_data->data));
- if (intel_output == NULL)
+ if (intel_encoder == NULL)
return -EINVAL;
- sdvo_priv = intel_output->dev_priv;
- algo = intel_output->i2c_bus->algo;
+ sdvo_priv = intel_encoder->dev_priv;
+ algo = intel_encoder->i2c_bus->algo;
- intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
+ intel_sdvo_set_control_bus_switch(intel_encoder, sdvo_priv->ddc_bus);
return algo->master_xfer(i2c_adap, msgs, num);
}
};
static u8
-intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
+intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct sdvo_device_mapping *my_mapping, *other_mapping;
- if (output_device == SDVOB) {
+ if (sdvo_reg == SDVOB) {
my_mapping = &dev_priv->sdvo_mappings[0];
other_mapping = &dev_priv->sdvo_mappings[1];
} else {
/* No SDVO device info is found for another DVO port,
* so use mapping assumption we had before BIOS parsing.
*/
- if (output_device == SDVOB)
+ if (sdvo_reg == SDVOB)
return 0x70;
else
return 0x72;
};
static bool
-intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
+intel_sdvo_output_setup(struct intel_encoder *intel_encoder, uint16_t flags)
{
- struct drm_connector *connector = &intel_output->base;
- struct drm_encoder *encoder = &intel_output->enc;
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct drm_connector *connector = &intel_encoder->base;
+ struct drm_encoder *encoder = &intel_encoder->enc;
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
bool ret = true, registered = false;
sdvo_priv->is_tv = false;
- intel_output->needs_tv_clock = false;
+ intel_encoder->needs_tv_clock = false;
sdvo_priv->is_lvds = false;
if (device_is_registered(&connector->kdev)) {
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
- if (intel_sdvo_get_supp_encode(intel_output,
+ if (intel_sdvo_get_supp_encode(intel_encoder,
&sdvo_priv->encode) &&
- intel_sdvo_get_digital_encoding_mode(intel_output) &&
+ intel_sdvo_get_digital_encoding_mode(intel_encoder) &&
sdvo_priv->is_hdmi) {
/* enable hdmi encoding mode if supported */
- intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
- intel_sdvo_set_colorimetry(intel_output,
+ intel_sdvo_set_encode(intel_encoder, SDVO_ENCODE_HDMI);
+ intel_sdvo_set_colorimetry(intel_encoder,
SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
- intel_output->clone_mask =
+ intel_encoder->clone_mask =
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
}
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
sdvo_priv->is_tv = true;
- intel_output->needs_tv_clock = true;
- intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+ intel_encoder->needs_tv_clock = true;
+ intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
} else if (flags & SDVO_OUTPUT_RGB0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
- intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
} else if (flags & SDVO_OUTPUT_RGB1) {
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
- intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+ intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
(1 << INTEL_ANALOG_CLONE_BIT);
} else if (flags & SDVO_OUTPUT_CVBS0) {
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
sdvo_priv->is_tv = true;
- intel_output->needs_tv_clock = true;
- intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
+ intel_encoder->needs_tv_clock = true;
+ intel_encoder->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
} else if (flags & SDVO_OUTPUT_LVDS0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
- intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
+ intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
} else if (flags & SDVO_OUTPUT_LVDS1) {
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true;
- intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
+ intel_encoder->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
} else {
bytes[0], bytes[1]);
ret = false;
}
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
if (ret && registered)
ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
static void intel_sdvo_tv_create_property(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
struct intel_sdvo_tv_format format;
uint32_t format_map, i;
uint8_t status;
- intel_sdvo_set_target_output(intel_output,
+ intel_sdvo_set_target_output(intel_encoder,
sdvo_priv->controlled_output);
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&format, sizeof(format));
if (status != SDVO_CMD_STATUS_SUCCESS)
return;
static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_sdvo_priv *sdvo_priv = intel_encoder->dev_priv;
struct intel_sdvo_enhancements_reply sdvo_data;
struct drm_device *dev = connector->dev;
uint8_t status;
uint16_t response, data_value[2];
- intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+ intel_sdvo_write_cmd(intel_encoder, SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
NULL, 0);
- status = intel_sdvo_read_response(intel_output, &sdvo_data,
+ status = intel_sdvo_read_response(intel_encoder, &sdvo_data,
sizeof(sdvo_data));
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS(" incorrect response is returned\n");
* property
*/
if (sdvo_data.overscan_h) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_OVERSCAN_H, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO max "
"h_overscan\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_OVERSCAN_H, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO h_overscan\n");
data_value[0], data_value[1], response);
}
if (sdvo_data.overscan_v) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_OVERSCAN_V, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO max "
"v_overscan\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_OVERSCAN_V, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO v_overscan\n");
data_value[0], data_value[1], response);
}
if (sdvo_data.position_h) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_POSITION_H, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max h_pos\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_POSITION_H, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get h_postion\n");
data_value[0], data_value[1], response);
}
if (sdvo_data.position_v) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_POSITION_V, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max v_pos\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_POSITION_V, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get v_postion\n");
}
if (sdvo_priv->is_tv) {
if (sdvo_data.saturation) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_SATURATION, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max sat\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_SATURATION, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get sat\n");
data_value[0], data_value[1], response);
}
if (sdvo_data.contrast) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_CONTRAST, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max contrast\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_CONTRAST, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get contrast\n");
data_value[0], data_value[1], response);
}
if (sdvo_data.hue) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_HUE, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max hue\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_HUE, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get hue\n");
}
if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
if (sdvo_data.brightness) {
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_MAX_BRIGHTNESS, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&data_value, 4);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO Max bright\n");
return;
}
- intel_sdvo_write_cmd(intel_output,
+ intel_sdvo_write_cmd(intel_encoder,
SDVO_CMD_GET_BRIGHTNESS, NULL, 0);
- status = intel_sdvo_read_response(intel_output,
+ status = intel_sdvo_read_response(intel_encoder,
&response, 2);
if (status != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("Incorrect SDVO get brigh\n");
return;
}
-bool intel_sdvo_init(struct drm_device *dev, int output_device)
+bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_sdvo_priv *sdvo_priv;
u8 ch[0x40];
int i;
- intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
- if (!intel_output) {
+ intel_encoder = kcalloc(sizeof(struct intel_encoder)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
+ if (!intel_encoder) {
return false;
}
- sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
- sdvo_priv->output_device = output_device;
+ sdvo_priv = (struct intel_sdvo_priv *)(intel_encoder + 1);
+ sdvo_priv->sdvo_reg = sdvo_reg;
- intel_output->dev_priv = sdvo_priv;
- intel_output->type = INTEL_OUTPUT_SDVO;
+ intel_encoder->dev_priv = sdvo_priv;
+ intel_encoder->type = INTEL_OUTPUT_SDVO;
/* setup the DDC bus. */
- if (output_device == SDVOB)
- intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+ if (sdvo_reg == SDVOB)
+ intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
else
- intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+ intel_encoder->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
- if (!intel_output->i2c_bus)
+ if (!intel_encoder->i2c_bus)
goto err_inteloutput;
- sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
+ sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
/* Save the bit-banging i2c functionality for use by the DDC wrapper */
- intel_sdvo_i2c_bit_algo.functionality = intel_output->i2c_bus->algo->functionality;
+ intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
- if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
+ if (!intel_sdvo_read_byte(intel_encoder, i, &ch[i])) {
DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
- output_device == SDVOB ? 'B' : 'C');
+ sdvo_reg == SDVOB ? 'B' : 'C');
goto err_i2c;
}
}
/* setup the DDC bus. */
- if (output_device == SDVOB) {
- intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
+ if (sdvo_reg == SDVOB) {
+ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOB/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
} else {
- intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+ intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOC/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
}
- if (intel_output->ddc_bus == NULL)
+ if (intel_encoder->ddc_bus == NULL)
goto err_i2c;
/* Wrap with our custom algo which switches to DDC mode */
- intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
+ intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
/* In default case sdvo lvds is false */
- intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
+ intel_sdvo_get_capabilities(intel_encoder, &sdvo_priv->caps);
- if (intel_sdvo_output_setup(intel_output,
+ if (intel_sdvo_output_setup(intel_encoder,
sdvo_priv->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
- output_device == SDVOB ? 'B' : 'C');
+ sdvo_reg == SDVOB ? 'B' : 'C');
goto err_i2c;
}
- connector = &intel_output->base;
+ connector = &intel_encoder->base;
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
connector->connector_type);
connector->doublescan_allowed = 0;
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
- drm_encoder_init(dev, &intel_output->enc,
- &intel_sdvo_enc_funcs, intel_output->enc.encoder_type);
+ drm_encoder_init(dev, &intel_encoder->enc,
+ &intel_sdvo_enc_funcs, intel_encoder->enc.encoder_type);
- drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
- drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+ drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
if (sdvo_priv->is_tv)
intel_sdvo_tv_create_property(connector);
intel_sdvo_select_ddc_bus(sdvo_priv);
/* Set the input timing to the screen. Assume always input 0. */
- intel_sdvo_set_target_input(intel_output, true, false);
+ intel_sdvo_set_target_input(intel_encoder, true, false);
- intel_sdvo_get_input_pixel_clock_range(intel_output,
+ intel_sdvo_get_input_pixel_clock_range(intel_encoder,
&sdvo_priv->pixel_clock_min,
&sdvo_priv->pixel_clock_max);
err_i2c:
if (sdvo_priv->analog_ddc_bus != NULL)
intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
- if (intel_output->ddc_bus != NULL)
- intel_i2c_destroy(intel_output->ddc_bus);
- if (intel_output->i2c_bus != NULL)
- intel_i2c_destroy(intel_output->i2c_bus);
+ if (intel_encoder->ddc_bus != NULL)
+ intel_i2c_destroy(intel_encoder->ddc_bus);
+ if (intel_encoder->i2c_bus != NULL)
+ intel_i2c_destroy(intel_encoder->i2c_bus);
err_inteloutput:
- kfree(intel_output);
+ kfree(intel_encoder);
return false;
}
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
int i;
tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
struct drm_crtc *crtc = connector->encoder->crtc;
struct intel_crtc *intel_crtc;
int i;
}
static const struct tv_mode *
-intel_tv_mode_find (struct intel_output *intel_output)
+intel_tv_mode_find (struct intel_encoder *intel_encoder)
{
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
return intel_tv_mode_lookup(tv_priv->tv_format);
}
static enum drm_mode_status
intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
{
- struct intel_output *intel_output = to_intel_output(connector);
- const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
/* Ensure TV refresh is close to desired refresh */
if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
{
struct drm_device *dev = encoder->dev;
struct drm_mode_config *drm_config = &dev->mode_config;
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- const struct tv_mode *tv_mode = intel_tv_mode_find (intel_output);
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ const struct tv_mode *tv_mode = intel_tv_mode_find (intel_encoder);
struct drm_encoder *other_encoder;
if (!tv_mode)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = encoder->crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_output *intel_output = enc_to_intel_output(encoder);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
- const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+ struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
u32 tv_ctl;
u32 hctl1, hctl2, hctl3;
u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
* \return false if TV is disconnected.
*/
static int
-intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
+intel_tv_detect_type (struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
{
- struct drm_encoder *encoder = &intel_output->enc;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
*/
static void intel_tv_find_better_format(struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
- const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
int i;
if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) ==
{
struct drm_crtc *crtc;
struct drm_display_mode mode;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
- struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
+ struct drm_encoder *encoder = &intel_encoder->enc;
int dpms_mode;
int type = tv_priv->type;
drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
if (encoder->crtc && encoder->crtc->enabled) {
- type = intel_tv_detect_type(encoder->crtc, intel_output);
+ type = intel_tv_detect_type(encoder->crtc, intel_encoder);
} else {
- crtc = intel_get_load_detect_pipe(intel_output, &mode, &dpms_mode);
+ crtc = intel_get_load_detect_pipe(intel_encoder, &mode, &dpms_mode);
if (crtc) {
- type = intel_tv_detect_type(crtc, intel_output);
- intel_release_load_detect_pipe(intel_output, dpms_mode);
+ type = intel_tv_detect_type(crtc, intel_encoder);
+ intel_release_load_detect_pipe(intel_encoder, dpms_mode);
} else
type = -1;
}
intel_tv_chose_preferred_modes(struct drm_connector *connector,
struct drm_display_mode *mode_ptr)
{
- struct intel_output *intel_output = to_intel_output(connector);
- const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
intel_tv_get_modes(struct drm_connector *connector)
{
struct drm_display_mode *mode_ptr;
- struct intel_output *intel_output = to_intel_output(connector);
- const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ const struct tv_mode *tv_mode = intel_tv_mode_find(intel_encoder);
int j, count = 0;
u64 tmp;
static void
intel_tv_destroy (struct drm_connector *connector)
{
- struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
- kfree(intel_output);
+ kfree(intel_encoder);
}
uint64_t val)
{
struct drm_device *dev = connector->dev;
- struct intel_output *intel_output = to_intel_output(connector);
- struct intel_tv_priv *tv_priv = intel_output->dev_priv;
- struct drm_encoder *encoder = &intel_output->enc;
+ struct intel_encoder *intel_encoder = to_intel_encoder(connector);
+ struct intel_tv_priv *tv_priv = intel_encoder->dev_priv;
+ struct drm_encoder *encoder = &intel_encoder->enc;
struct drm_crtc *crtc = encoder->crtc;
int ret = 0;
bool changed = false;
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
- struct intel_output *intel_output;
+ struct intel_encoder *intel_encoder;
struct intel_tv_priv *tv_priv;
u32 tv_dac_on, tv_dac_off, save_tv_dac;
char **tv_format_names;
(tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
return;
- intel_output = kzalloc(sizeof(struct intel_output) +
+ intel_encoder = kzalloc(sizeof(struct intel_encoder) +
sizeof(struct intel_tv_priv), GFP_KERNEL);
- if (!intel_output) {
+ if (!intel_encoder) {
return;
}
- connector = &intel_output->base;
+ connector = &intel_encoder->base;
drm_connector_init(dev, connector, &intel_tv_connector_funcs,
DRM_MODE_CONNECTOR_SVIDEO);
- drm_encoder_init(dev, &intel_output->enc, &intel_tv_enc_funcs,
+ drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
DRM_MODE_ENCODER_TVDAC);
- drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
- tv_priv = (struct intel_tv_priv *)(intel_output + 1);
- intel_output->type = INTEL_OUTPUT_TVOUT;
- intel_output->crtc_mask = (1 << 0) | (1 << 1);
- intel_output->clone_mask = (1 << INTEL_TV_CLONE_BIT);
- intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
- intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
- intel_output->dev_priv = tv_priv;
+ drm_mode_connector_attach_encoder(&intel_encoder->base, &intel_encoder->enc);
+ tv_priv = (struct intel_tv_priv *)(intel_encoder + 1);
+ intel_encoder->type = INTEL_OUTPUT_TVOUT;
+ intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
+ intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
+ intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
+ intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+ intel_encoder->dev_priv = tv_priv;
tv_priv->type = DRM_MODE_CONNECTOR_Unknown;
/* BIOS margin values */
tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
- drm_encoder_helper_add(&intel_output->enc, &intel_tv_helper_funcs);
+ drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst;
int dptr = *ptr;
+ uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ /* op needs to full dst value */
+ dst = saved;
shift = atom_get_src(ctx, attr, ptr);
SDEBUG(" shift: %d\n", shift);
dst <<= shift;
+ dst &= atom_arg_mask[dst_align];
+ dst >>= atom_arg_shift[dst_align];
SDEBUG(" dst: ");
atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
}
uint8_t attr = U8((*ptr)++), shift;
uint32_t saved, dst;
int dptr = *ptr;
+ uint32_t dst_align = atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3];
SDEBUG(" dst: ");
dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+ /* op needs to full dst value */
+ dst = saved;
shift = atom_get_src(ctx, attr, ptr);
SDEBUG(" shift: %d\n", shift);
dst >>= shift;
+ dst &= atom_arg_mask[dst_align];
+ dst >>= atom_arg_shift[dst_align];
SDEBUG(" dst: ");
atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
}
/* DVO wants 2x pixel clock if the DVO chip is in 12 bit mode */
if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
adjusted_clock = mode->clock * 2;
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
+ pll->algo = PLL_ALGO_LEGACY;
+ pll->flags |= RADEON_PLL_PREFER_CLOSEST_LOWER;
+ }
} else {
if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
pll->flags |= RADEON_PLL_NO_ODD_POST_DIV;
{
struct radeon_bo *robj;
unsigned long size;
- unsigned u, i, w, h;
+ unsigned u, i, w, h, d;
int ret;
for (u = 0; u < track->num_texture; u++) {
h = h / (1 << i);
if (track->textures[u].roundup_h)
h = roundup_pow_of_two(h);
+ if (track->textures[u].tex_coord_type == 1) {
+ d = (1 << track->textures[u].txdepth) / (1 << i);
+ if (!d)
+ d = 1;
+ } else {
+ d = 1;
+ }
if (track->textures[u].compress_format) {
- size += r100_track_compress_size(track->textures[u].compress_format, w, h);
+ size += r100_track_compress_size(track->textures[u].compress_format, w, h) * d;
/* compressed textures are block based */
} else
- size += w * h;
+ size += w * h * d;
}
size *= track->textures[u].cpp;
switch (track->textures[u].tex_coord_type) {
case 0:
- break;
case 1:
- size *= (1 << track->textures[u].txdepth);
break;
case 2:
if (track->separate_cube) {
}
}
prim_walk = (track->vap_vf_cntl >> 4) & 0x3;
- nverts = (track->vap_vf_cntl >> 16) & 0xFFFF;
+ if (track->vap_vf_cntl & (1 << 14)) {
+ nverts = track->vap_alt_nverts;
+ } else {
+ nverts = (track->vap_vf_cntl >> 16) & 0xFFFF;
+ }
switch (prim_walk) {
case 1:
for (i = 0; i < track->num_arrays; i++) {
unsigned maxy;
unsigned vtx_size;
unsigned vap_vf_cntl;
+ unsigned vap_alt_nverts;
unsigned immd_dwords;
unsigned num_arrays;
unsigned max_indx;
/* VAP_VF_MAX_VTX_INDX */
track->max_indx = idx_value & 0x00FFFFFFUL;
break;
+ case 0x2088:
+ /* VAP_ALT_NUM_VERTICES - only valid on r500 */
+ if (p->rdev->family < CHIP_RV515)
+ goto fail;
+ track->vap_alt_nverts = idx_value & 0xFFFFFF;
+ break;
case 0x43E4:
/* SC_SCISSOR1 */
track->maxy = ((idx_value >> 13) & 0x1FFF) + 1;
tmp = idx_value & ~(0x7 << 16);
tmp |= tile_flags;
ib[idx] = tmp;
-
i = (reg - 0x4E38) >> 2;
track->cb[i].pitch = idx_value & 0x3FFE;
switch (((idx_value >> 21) & 0xF)) {
break;
/* fallthrough do not move */
default:
- printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
- reg, idx);
- return -EINVAL;
+ goto fail;
}
return 0;
+fail:
+ printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
+ reg, idx);
+ return -EINVAL;
}
static int r300_packet3_check(struct radeon_cs_parser *p,
*/
static int r600_audio_chipset_supported(struct radeon_device *rdev)
{
- return rdev->family >= CHIP_R600
+ return (rdev->family >= CHIP_R600 && rdev->family < CHIP_CEDAR)
|| rdev->family == CHIP_RS600
|| rdev->family == CHIP_RS690
|| rdev->family == CHIP_RS740;
struct radeon_device *rdev = dev->dev_private;
uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
+ if (ASIC_IS_DCE4(rdev))
+ return;
+
if (!offset)
return;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ if (ASIC_IS_DCE4(rdev))
+ return;
+
if (!radeon_encoder->hdmi_offset) {
r600_hdmi_assign_block(encoder);
if (!radeon_encoder->hdmi_offset) {
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ if (ASIC_IS_DCE4(rdev))
+ return;
+
if (!radeon_encoder->hdmi_offset) {
dev_err(rdev->dev, "Disabling not enabled HDMI\n");
return;
{
struct drm_device *dev = connector->dev;
struct drm_connector *conflict;
+ struct radeon_connector *radeon_conflict;
int i;
list_for_each_entry(conflict, &dev->mode_config.connector_list, head) {
if (conflict == connector)
continue;
+ radeon_conflict = to_radeon_connector(conflict);
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (conflict->encoder_ids[i] == 0)
break;
if (conflict->status != connector_status_connected)
continue;
+ if (radeon_conflict->use_digital)
+ continue;
+
if (priority == true) {
DRM_INFO("1: conflicting encoders switching off %s\n", drm_get_connector_name(conflict));
DRM_INFO("in favor of %s\n", drm_get_connector_name(connector));
if (property == rdev->mode_info.coherent_mode_property) {
struct radeon_encoder_atom_dig *dig;
+ bool new_coherent_mode;
/* need to find digital encoder on connector */
encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
return 0;
dig = radeon_encoder->enc_priv;
- dig->coherent_mode = val ? true : false;
- radeon_property_change_mode(&radeon_encoder->base);
+ new_coherent_mode = val ? true : false;
+ if (dig->coherent_mode != new_coherent_mode) {
+ dig->coherent_mode = new_coherent_mode;
+ radeon_property_change_mode(&radeon_encoder->base);
+ }
}
if (property == rdev->mode_info.tv_std_property) {
#include "radeon.h"
#include "atom.h"
+static const char radeon_family_name[][16] = {
+ "R100",
+ "RV100",
+ "RS100",
+ "RV200",
+ "RS200",
+ "R200",
+ "RV250",
+ "RS300",
+ "RV280",
+ "R300",
+ "R350",
+ "RV350",
+ "RV380",
+ "R420",
+ "R423",
+ "RV410",
+ "RS400",
+ "RS480",
+ "RS600",
+ "RS690",
+ "RS740",
+ "RV515",
+ "R520",
+ "RV530",
+ "RV560",
+ "RV570",
+ "R580",
+ "R600",
+ "RV610",
+ "RV630",
+ "RV670",
+ "RV620",
+ "RV635",
+ "RS780",
+ "RS880",
+ "RV770",
+ "RV730",
+ "RV710",
+ "RV740",
+ "CEDAR",
+ "REDWOOD",
+ "JUNIPER",
+ "CYPRESS",
+ "HEMLOCK",
+ "LAST",
+};
+
/*
* Clear GPU surface registers.
*/
int r;
int dma_bits;
- DRM_INFO("radeon: Initializing kernel modesetting.\n");
rdev->shutdown = false;
rdev->dev = &pdev->dev;
rdev->ddev = ddev;
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
rdev->gpu_lockup = false;
rdev->accel_working = false;
+
+ DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n",
+ radeon_family_name[rdev->family], pdev->vendor, pdev->device);
+
/* mutex initialization are all done here so we
* can recall function without having locking issues */
mutex_init(&rdev->cs_mutex);
* - 2.0.0 - initial interface
* - 2.1.0 - add square tiling interface
* - 2.2.0 - add r6xx/r7xx const buffer support
+ * - 2.3.0 - add MSPOS + 3D texture + r500 VAP regs
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 2
+#define KMS_DRIVER_MINOR 3
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (dig->coherent_mode)
args.v3.acConfig.fCoherentMode = 1;
+ if (radeon_encoder->pixel_clock > 165000)
+ args.v3.acConfig.fDualLinkConnector = 1;
}
} else if (ASIC_IS_DCE32(rdev)) {
args.v2.acConfig.ucEncoderSel = dig->dig_encoder;
else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
if (dig->coherent_mode)
args.v2.acConfig.fCoherentMode = 1;
+ if (radeon_encoder->pixel_clock > 165000)
+ args.v2.acConfig.fDualLinkConnector = 1;
}
} else {
args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
case ENCODER_OBJECT_ID_INTERNAL_DAC2:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
atombios_dac_setup(encoder, ATOM_ENABLE);
- if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
- atombios_tv_setup(encoder, ATOM_ENABLE);
+ if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) {
+ if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
+ atombios_tv_setup(encoder, ATOM_ENABLE);
+ else
+ atombios_tv_setup(encoder, ATOM_DISABLE);
+ }
break;
}
atombios_apply_encoder_quirks(encoder, adjusted_mode);
* Radeon chip families
*/
enum radeon_family {
- CHIP_R100,
+ CHIP_R100 = 0,
CHIP_RV100,
CHIP_RS100,
CHIP_RV200,
RADEON_IS_PCI = 0x00800000UL,
RADEON_IS_IGPGART = 0x01000000UL,
};
+
#endif
0x4000 GB_VAP_RASTER_VTX_FMT_0
0x4004 GB_VAP_RASTER_VTX_FMT_1
0x4008 GB_ENABLE
+0x4010 GB_MSPOS0
+0x4014 GB_MSPOS1
0x401C GB_SELECT
0x4020 GB_AA_CONFIG
0x4024 GB_FIFO_SIZE
0x4000 GB_VAP_RASTER_VTX_FMT_0
0x4004 GB_VAP_RASTER_VTX_FMT_1
0x4008 GB_ENABLE
+0x4010 GB_MSPOS0
+0x4014 GB_MSPOS1
0x401C GB_SELECT
0x4020 GB_AA_CONFIG
0x4024 GB_FIFO_SIZE
0x4000 GB_VAP_RASTER_VTX_FMT_0
0x4004 GB_VAP_RASTER_VTX_FMT_1
0x4008 GB_ENABLE
+0x4010 GB_MSPOS0
+0x4014 GB_MSPOS1
0x401C GB_SELECT
0x4020 GB_AA_CONFIG
0x4024 GB_FIFO_SIZE
0x1DA8 VAP_VPORT_ZSCALE
0x1DAC VAP_VPORT_ZOFFSET
0x2080 VAP_CNTL
+0x208C VAP_INDEX_OFFSET
0x2090 VAP_OUT_VTX_FMT_0
0x2094 VAP_OUT_VTX_FMT_1
0x20B0 VAP_VTE_CNTL
0x4000 GB_VAP_RASTER_VTX_FMT_0
0x4004 GB_VAP_RASTER_VTX_FMT_1
0x4008 GB_ENABLE
+0x4010 GB_MSPOS0
+0x4014 GB_MSPOS1
0x401C GB_SELECT
0x4020 GB_AA_CONFIG
0x4024 GB_FIFO_SIZE
WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
- tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) & S_000100_INVALIDATE_L2_CACHE(1);
+ tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) | S_000100_INVALIDATE_L2_CACHE(1);
WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
"TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S",
"TN0C", "TN0D", "TN0H", "TS0C", "Tp0C", "Tp1C", "Tv0S", "Tv1S",
NULL },
+/* Set 17: iMac 9,1 */
+ { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TH0P", "TL0P",
+ "TN0D", "TN0H", "TN0P", "TO0P", "Tm0P", "Tp0P", NULL },
+/* Set 18: MacBook Pro 2,2 */
+ { "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "TM0P", "TTF0",
+ "Th0H", "Th1H", "Tm0P", "Ts0P", NULL },
};
/* List of keys used to read/write fan speeds */
{ .accelerometer = 1, .light = 1, .temperature_set = 15 },
/* MacPro3,1: temperature set 16 */
{ .accelerometer = 0, .light = 0, .temperature_set = 16 },
+/* iMac 9,1: light sensor only, temperature set 17 */
+ { .accelerometer = 0, .light = 0, .temperature_set = 17 },
+/* MacBook Pro 2,2: accelerometer, backlight and temperature set 18 */
+ { .accelerometer = 1, .light = 1, .temperature_set = 18 },
};
/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3") },
&applesmc_dmi_data[9]},
+ { applesmc_dmi_match, "Apple MacBook Pro 2,2", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple Computer, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2") },
+ &applesmc_dmi_data[18]},
{ applesmc_dmi_match, "Apple MacBook Pro", {
DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "MacPro") },
&applesmc_dmi_data[4]},
+ { applesmc_dmi_match, "Apple iMac 9,1", {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1") },
+ &applesmc_dmi_data[17]},
{ applesmc_dmi_match, "Apple iMac 8", {
DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "iMac8") },
int err;
list_for_each_entry(s, &data->sensor_list, list) {
+ sysfs_attr_init(&s->input_attr.attr);
err = device_create_file(data->hwmon_dev, &s->input_attr);
if (err)
return err;
+ sysfs_attr_init(&s->label_attr.attr);
err = device_create_file(data->hwmon_dev, &s->label_attr);
if (err)
return err;
+ sysfs_attr_init(&s->limit1_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit1_attr);
if (err)
return err;
+ sysfs_attr_init(&s->limit2_attr.attr);
err = device_create_file(data->hwmon_dev, &s->limit2_attr);
if (err)
return err;
struct it87_data *data = dev_get_drvdata(dev);
long val;
+ u8 reg;
if (strict_strtol(buf, 10, &val) < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
-
- data->sensor &= ~(1 << nr);
- data->sensor &= ~(8 << nr);
+ reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+ reg &= ~(1 << nr);
+ reg &= ~(8 << nr);
if (val == 2) { /* backwards compatibility */
dev_warn(dev, "Sensor type 2 is deprecated, please use 4 "
"instead\n");
}
/* 3 = thermal diode; 4 = thermistor; 0 = disabled */
if (val == 3)
- data->sensor |= 1 << nr;
+ reg |= 1 << nr;
else if (val == 4)
- data->sensor |= 8 << nr;
- else if (val != 0) {
- mutex_unlock(&data->update_lock);
+ reg |= 8 << nr;
+ else if (val != 0)
return -EINVAL;
- }
+
+ mutex_lock(&data->update_lock);
+ data->sensor = reg;
it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
+ data->valid = 0; /* Force cache refresh */
mutex_unlock(&data->update_lock);
return count;
}
it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
}
- /* Check if temperature channels are reset manually or by some reason */
- tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
- if ((tmp & 0x3f) == 0) {
- /* Temp1,Temp3=thermistor; Temp2=thermal diode */
- tmp = (tmp & 0xc0) | 0x2a;
- it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);
- }
- data->sensor = tmp;
+ /* Temperature channels are not forcibly enabled, as they can be
+ * set to two different sensor types and we can't guess which one
+ * is correct for a given system. These channels can be enabled at
+ * run-time through the temp{1-3}_type sysfs accessors if needed. */
/* Check if voltage monitors are reset manually or by some reason */
tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
**/
static inline int sht15_calc_temp(struct sht15_data *data)
{
- int d1 = 0;
+ int d1 = temppoints[0].d1;
int i;
- for (i = 1; i < ARRAY_SIZE(temppoints); i++)
+ for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
/* Find pointer to interpolate */
if (data->supply_uV > temppoints[i - 1].vdd) {
- d1 = (data->supply_uV/1000 - temppoints[i - 1].vdd)
+ d1 = (data->supply_uV - temppoints[i - 1].vdd)
* (temppoints[i].d1 - temppoints[i - 1].d1)
/ (temppoints[i].vdd - temppoints[i - 1].vdd)
+ temppoints[i - 1].d1;
/* If a regulator is available, query what the supply voltage actually is!*/
data->reg = regulator_get(data->dev, "vcc");
if (!IS_ERR(data->reg)) {
- data->supply_uV = regulator_get_voltage(data->reg);
+ int voltage;
+
+ voltage = regulator_get_voltage(data->reg);
+ if (voltage)
+ data->supply_uV = voltage;
+
regulator_enable(data->reg);
/* setup a notifier block to update this if another device
* causes the voltage to change */
"<%s> I2C Interrupted\n", __func__);
return -EINTR;
}
- if (time_after(jiffies, orig_jiffies + HZ / 1000)) {
+ if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&i2c_imx->adapter.dev,
"<%s> I2C bus is busy\n", __func__);
- return -EIO;
+ return -ETIMEDOUT;
}
schedule();
}
result = i2c_imx_read(i2c_imx, &msgs[i]);
else
result = i2c_imx_write(i2c_imx, &msgs[i]);
+ if (result)
+ goto fail0;
}
fail0:
platform_set_drvdata(pdev, dev);
+ if (cpu_is_omap7xx())
+ dev->reg_shift = 1;
+ else
+ dev->reg_shift = 2;
+
if ((r = omap_i2c_get_clocks(dev)) != 0)
goto err_iounmap;
dev->b_hw = 1; /* Enable hardware fixes */
}
- if (cpu_is_omap7xx())
- dev->reg_shift = 1;
- else
- dev->reg_shift = 2;
-
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
/* We still have something to talk about... */
val = *alg_data->mif.buf++;
+ if (alg_data->mif.len == 1)
+ val |= stop_bit;
+
alg_data->mif.len--;
iowrite32(val, I2C_REG_TX(alg_data));
__func__);
if (alg_data->mif.len == 1) {
+ /* Last byte, do not acknowledge next rcv. */
+ val |= stop_bit;
+
/*
* Enable interrupt RFDAIE (data in Rx fifo),
* and disable DRMIE (need data for Tx)
*/
tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ if (tmp > 0x3FF)
+ tmp = 0x3FF;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));
int i = 0;
/* Locate the apropriate clock setting */
- while (i < ARRAY_SIZE(stu300_clktable) &&
+ while (i < ARRAY_SIZE(stu300_clktable) - 1 &&
stu300_clktable[i].rate < clkrate)
i++;
PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x3e520e17),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x9351e59d),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
int input_get_keycode(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode)
{
- return dev->getkeycode(dev, scancode, keycode);
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ retval = dev->getkeycode(dev, scancode, keycode);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return retval;
}
EXPORT_SYMBOL(input_get_keycode);
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ input_dev->evbit[0] = BIT_MASK(EV_KEY);
+ if (!pdata->no_autorepeat)
+ input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_dev->open = matrix_keypad_start;
input_dev->close = matrix_keypad_stop;
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
+ { { 0x73, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, /* HP Pavilion dm3 */
{ { 0x52, 0x01, 0x14 }, 0xff, 0xff,
ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
};
.disconnect = bcm5974_disconnect,
.suspend = bcm5974_suspend,
.resume = bcm5974_resume,
- .reset_resume = bcm5974_resume,
.id_table = bcm5974_table,
.supports_autosuspend = 1,
};
static bool i8042_nomux;
module_param_named(nomux, i8042_nomux, bool, 0);
-MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing conrtoller is present.");
+MODULE_PARM_DESC(nomux, "Do not check whether an active multiplexing controller is present.");
static bool i8042_unlock;
module_param_named(unlock, i8042_unlock, bool, 0);
unsigned int scancode,
unsigned int *keycode)
{
- const struct key_entry *key =
- sparse_keymap_entry_from_scancode(dev, scancode);
+ const struct key_entry *key;
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
+ if (dev->keycode) {
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ if (key && key->type == KE_KEY) {
+ *keycode = key->keycode;
+ return 0;
+ }
}
return -EINVAL;
struct key_entry *key;
int old_keycode;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
- key = sparse_keymap_entry_from_scancode(dev, scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
+ if (dev->keycode) {
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ if (key && key->type == KE_KEY) {
+ old_keycode = key->keycode;
+ key->keycode = keycode;
+ set_bit(keycode, dev->keybit);
+ if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
+ clear_bit(old_keycode, dev->keybit);
+ return 0;
+ }
}
return -EINVAL;
return 0;
err_out:
- kfree(keymap);
+ kfree(map);
return error;
}
*
* This function is used to free memory allocated by sparse keymap
* in an input device that was set up by sparse_keymap_setup().
+ * NOTE: It is safe to cal this function while input device is
+ * still registered (however the drivers should care not to try to
+ * use freed keymap and thus have to shut off interrups/polling
+ * before freeing the keymap).
*/
void sparse_keymap_free(struct input_dev *dev)
{
+ unsigned long flags;
+
+ /*
+ * Take event lock to prevent racing with input_get_keycode()
+ * and input_set_keycode() if we are called while input device
+ * is still registered.
+ */
+ spin_lock_irqsave(&dev->event_lock, flags);
+
kfree(dev->keycode);
dev->keycode = NULL;
dev->keycodemax = 0;
- dev->getkeycode = NULL;
- dev->setkeycode = NULL;
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
EXPORT_SYMBOL(sparse_keymap_free);
int rv;
mutex_lock(&wacom->lock);
- if (wacom->open) {
+
+ /* switch to wacom mode first */
+ wacom_query_tablet_data(intf, features);
+
+ if (wacom->open)
rv = usb_submit_urb(wacom->irq, GFP_NOIO);
- /* switch to wacom mode if needed */
- if (!wacom_retrieve_hid_descriptor(intf, features))
- wacom_query_tablet_data(intf, features);
- } else
+ else
rv = 0;
+
mutex_unlock(&wacom->lock);
return rv;
{
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
- int x, y, prox;
- int rw = 0;
- int retval = 0;
+ int x, y, rw;
+ static int penData = 0;
if (data[0] != WACOM_REPORT_PENABLED) {
dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
- goto exit;
+ return 0;
}
- prox = data[1] & 0x80;
- if (prox || wacom->id[0]) {
- if (prox) {
- switch ((data[1] >> 5) & 3) {
+ if (data[1] & 0x80) {
+ /* in prox and not a pad data */
+ penData = 1;
+
+ switch ((data[1] >> 5) & 3) {
case 0: /* Pen */
wacom->tool[0] = BTN_TOOL_PEN;
case 2: /* Mouse with wheel */
wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
+ if (features->type == WACOM_G4 || features->type == WACOM_MO) {
+ rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
+ wacom_report_rel(wcombo, REL_WHEEL, -rw);
+ } else
+ wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
/* fall through */
case 3: /* Mouse without wheel */
wacom->tool[0] = BTN_TOOL_MOUSE;
wacom->id[0] = CURSOR_DEVICE_ID;
+ wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
+ if (features->type == WACOM_G4 || features->type == WACOM_MO)
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
+ else
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
break;
- }
}
x = wacom_le16_to_cpu(&data[2]);
y = wacom_le16_to_cpu(&data[4]);
wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
- } else {
- wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
- wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
- if (features->type == WACOM_G4 ||
- features->type == WACOM_MO) {
- wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
- rw = (signed)(data[7] & 0x04) - (data[7] & 0x03);
- } else {
- wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
- rw = -(signed)data[6];
- }
- wacom_report_rel(wcombo, REL_WHEEL, rw);
}
-
- if (!prox)
- wacom->id[0] = 0;
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
- wacom_report_key(wcombo, wacom->tool[0], prox);
- wacom_input_sync(wcombo); /* sync last event */
+ wacom_report_key(wcombo, wacom->tool[0], 1);
+ } else if (wacom->id[0]) {
+ wacom_report_abs(wcombo, ABS_X, 0);
+ wacom_report_abs(wcombo, ABS_Y, 0);
+ if (wacom->tool[0] == BTN_TOOL_MOUSE) {
+ wacom_report_key(wcombo, BTN_LEFT, 0);
+ wacom_report_key(wcombo, BTN_RIGHT, 0);
+ wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+ } else {
+ wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ wacom_report_key(wcombo, BTN_STYLUS, 0);
+ wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ }
+ wacom->id[0] = 0;
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_report_key(wcombo, wacom->tool[0], 0);
}
/* send pad data */
switch (features->type) {
case WACOM_G4:
- prox = data[7] & 0xf8;
- if (prox || wacom->id[1]) {
+ if (data[7] & 0xf8) {
+ if (penData) {
+ wacom_input_sync(wcombo); /* sync last event */
+ if (!wacom->id[0])
+ penData = 0;
+ }
wacom->id[1] = PAD_DEVICE_ID;
wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
wacom_report_rel(wcombo, REL_WHEEL, rw);
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
- if (!prox)
- wacom->id[1] = 0;
- wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ } else if (wacom->id[1]) {
+ if (penData) {
+ wacom_input_sync(wcombo); /* sync last event */
+ if (!wacom->id[0])
+ penData = 0;
+ }
+ wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+ wacom_report_rel(wcombo, REL_WHEEL, 0);
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
- retval = 1;
break;
case WACOM_MO:
- prox = (data[7] & 0xf8) || data[8];
- if (prox || wacom->id[1]) {
+ if ((data[7] & 0xf8) || (data[8] & 0xff)) {
+ if (penData) {
+ wacom_input_sync(wcombo); /* sync last event */
+ if (!wacom->id[0])
+ penData = 0;
+ }
wacom->id[1] = PAD_DEVICE_ID;
wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
- if (!prox)
- wacom->id[1] = 0;
wacom_report_abs(wcombo, ABS_MISC, wacom->id[1]);
wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ } else if (wacom->id[1]) {
+ if (penData) {
+ wacom_input_sync(wcombo); /* sync last event */
+ if (!wacom->id[0])
+ penData = 0;
+ }
+ wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x08));
+ wacom_report_key(wcombo, BTN_1, (data[7] & 0x20));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x10));
+ wacom_report_key(wcombo, BTN_5, (data[7] & 0x40));
+ wacom_report_abs(wcombo, ABS_WHEEL, (data[8] & 0x7f));
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
}
- retval = 1;
break;
}
-exit:
- return retval;
+ return 1;
}
static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
static void wacom_tpc_finger_in(struct wacom_wac *wacom, void *wcombo, char *data, int idx)
{
wacom_report_abs(wcombo, ABS_X,
- data[2 + idx * 2] | ((data[3 + idx * 2] & 0x7f) << 8));
+ (data[2 + idx * 2] & 0xff) | ((data[3 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_Y,
- data[6 + idx * 2] | ((data[7 + idx * 2] & 0x7f) << 8));
+ (data[6 + idx * 2] & 0xff) | ((data[7 + idx * 2] & 0x7f) << 8));
wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]);
wacom_report_key(wcombo, wacom->tool[idx], 1);
if (idx)
touchInProx = 0;
- if (!wacom->id[0]) { /* first in prox */
- /* Going into proximity select tool */
- wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- if (wacom->tool[0] == BTN_TOOL_PEN)
- wacom->id[0] = STYLUS_DEVICE_ID;
- else
- wacom->id[0] = ERASER_DEVICE_ID;
- }
- wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
- wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
- wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
- wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
- pressure = ((data[7] & 0x01) << 8) | data[6];
- if (pressure < 0)
- pressure = features->pressure_max + pressure + 1;
- wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
- wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
- if (!prox) { /* out-prox */
+ if (prox) { /* in prox */
+ if (!wacom->id[0]) {
+ /* Going into proximity select tool */
+ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ if (wacom->tool[0] == BTN_TOOL_PEN)
+ wacom->id[0] = STYLUS_DEVICE_ID;
+ else
+ wacom->id[0] = ERASER_DEVICE_ID;
+ }
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+ pressure = ((data[7] & 0x01) << 8) | data[6];
+ if (pressure < 0)
+ pressure = features->pressure_max + pressure + 1;
+ wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x05);
+ } else {
+ wacom_report_abs(wcombo, ABS_X, 0);
+ wacom_report_abs(wcombo, ABS_Y, 0);
+ wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+ wacom_report_key(wcombo, BTN_STYLUS, 0);
+ wacom_report_key(wcombo, BTN_STYLUS2, 0);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
wacom->id[0] = 0;
/* pen is out so touch can be enabled now */
touchInProx = 1;
*/
#include "gigaset.h"
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/timer.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
*/
#include "gigaset.h"
-#include <linux/slab.h>
-#include <linux/ctype.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/isdn/capilli.h>
*/
#include "gigaset.h"
-#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/slab.h>
/* Version Information */
#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/usb.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/ppp_defs.h>
#include "gigaset.h"
#include <linux/isdnif.h>
-#include <linux/slab.h>
#define HW_HDR_LEN 2 /* Header size used to store ack info */
#include "gigaset.h"
#include <linux/gigaset_dev.h>
-#include <linux/tty.h>
#include <linux/tty_flip.h>
/*** our ioctls ***/
*/
#include "gigaset.h"
-#include <linux/ctype.h>
static ssize_t show_cidmode(struct device *dev,
struct device_attribute *attr, char *buf)
*/
#include "gigaset.h"
-
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
-#include <linux/tty.h>
#include <linux/completion.h>
-#include <linux/slab.h>
/* Version Information */
#define DRIVER_AUTHOR "Tilman Schmidt"
*/
#include "gigaset.h"
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
/* We set the status. */
to_lgdev(vdev)->desc->status = status;
- kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset);
+ hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
}
static void lg_set_status(struct virtio_device *vdev, u8 status)
*/
struct lguest_vq_info *lvq = vq->priv;
- kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT);
+ hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
}
/* An extern declaration inside a C file is bad form. Don't do it. */
/* Decoding x86 instructions is icky. */
insn = lgread(cpu, physaddr, u8);
+ /*
+ * Around 2.6.33, the kernel started using an emulation for the
+ * cmpxchg8b instruction in early boot on many configurations. This
+ * code isn't paravirtualized, and it tries to disable interrupts.
+ * Ignore it, which will Mostly Work.
+ */
+ if (insn == 0xfa) {
+ /* "cli", or Clear Interrupt Enable instruction. Skip it. */
+ cpu->regs->eip++;
+ return 1;
+ }
+
/*
* 0x66 is an "operand prefix". It means it's using the upper 16 bits
* of the eax register.
int previous, int *dd_idx,
struct stripe_head *sh)
{
- long stripe;
- unsigned long chunk_number;
+ sector_t stripe, stripe2;
+ sector_t chunk_number;
unsigned int chunk_offset;
int pd_idx, qd_idx;
int ddf_layout = 0;
*/
chunk_offset = sector_div(r_sector, sectors_per_chunk);
chunk_number = r_sector;
- BUG_ON(r_sector != chunk_number);
/*
* Compute the stripe number
*/
- stripe = chunk_number / data_disks;
-
- /*
- * Compute the data disk and parity disk indexes inside the stripe
- */
- *dd_idx = chunk_number % data_disks;
-
+ stripe = chunk_number;
+ *dd_idx = sector_div(stripe, data_disks);
+ stripe2 = stripe;
/*
* Select the parity disk based on the user selected algorithm.
*/
case 5:
switch (algorithm) {
case ALGORITHM_LEFT_ASYMMETRIC:
- pd_idx = data_disks - stripe % raid_disks;
+ pd_idx = data_disks - sector_div(stripe2, raid_disks);
if (*dd_idx >= pd_idx)
(*dd_idx)++;
break;
case ALGORITHM_RIGHT_ASYMMETRIC:
- pd_idx = stripe % raid_disks;
+ pd_idx = sector_div(stripe2, raid_disks);
if (*dd_idx >= pd_idx)
(*dd_idx)++;
break;
case ALGORITHM_LEFT_SYMMETRIC:
- pd_idx = data_disks - stripe % raid_disks;
+ pd_idx = data_disks - sector_div(stripe2, raid_disks);
*dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
break;
case ALGORITHM_RIGHT_SYMMETRIC:
- pd_idx = stripe % raid_disks;
+ pd_idx = sector_div(stripe2, raid_disks);
*dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
break;
case ALGORITHM_PARITY_0:
switch (algorithm) {
case ALGORITHM_LEFT_ASYMMETRIC:
- pd_idx = raid_disks - 1 - (stripe % raid_disks);
+ pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks);
qd_idx = pd_idx + 1;
if (pd_idx == raid_disks-1) {
(*dd_idx)++; /* Q D D D P */
(*dd_idx) += 2; /* D D P Q D */
break;
case ALGORITHM_RIGHT_ASYMMETRIC:
- pd_idx = stripe % raid_disks;
+ pd_idx = sector_div(stripe2, raid_disks);
qd_idx = pd_idx + 1;
if (pd_idx == raid_disks-1) {
(*dd_idx)++; /* Q D D D P */
(*dd_idx) += 2; /* D D P Q D */
break;
case ALGORITHM_LEFT_SYMMETRIC:
- pd_idx = raid_disks - 1 - (stripe % raid_disks);
+ pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks);
qd_idx = (pd_idx + 1) % raid_disks;
*dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks;
break;
case ALGORITHM_RIGHT_SYMMETRIC:
- pd_idx = stripe % raid_disks;
+ pd_idx = sector_div(stripe2, raid_disks);
qd_idx = (pd_idx + 1) % raid_disks;
*dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks;
break;
/* Exactly the same as RIGHT_ASYMMETRIC, but or
* of blocks for computing Q is different.
*/
- pd_idx = stripe % raid_disks;
+ pd_idx = sector_div(stripe2, raid_disks);
qd_idx = pd_idx + 1;
if (pd_idx == raid_disks-1) {
(*dd_idx)++; /* Q D D D P */
* D D D P Q rather than
* Q D D D P
*/
- pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks);
+ stripe2 += 1;
+ pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks);
qd_idx = pd_idx + 1;
if (pd_idx == raid_disks-1) {
(*dd_idx)++; /* Q D D D P */
case ALGORITHM_ROTATING_N_CONTINUE:
/* Same as left_symmetric but Q is before P */
- pd_idx = raid_disks - 1 - (stripe % raid_disks);
+ pd_idx = raid_disks - 1 - sector_div(stripe2, raid_disks);
qd_idx = (pd_idx + raid_disks - 1) % raid_disks;
*dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
ddf_layout = 1;
case ALGORITHM_LEFT_ASYMMETRIC_6:
/* RAID5 left_asymmetric, with Q on last device */
- pd_idx = data_disks - stripe % (raid_disks-1);
+ pd_idx = data_disks - sector_div(stripe2, raid_disks-1);
if (*dd_idx >= pd_idx)
(*dd_idx)++;
qd_idx = raid_disks - 1;
break;
case ALGORITHM_RIGHT_ASYMMETRIC_6:
- pd_idx = stripe % (raid_disks-1);
+ pd_idx = sector_div(stripe2, raid_disks-1);
if (*dd_idx >= pd_idx)
(*dd_idx)++;
qd_idx = raid_disks - 1;
break;
case ALGORITHM_LEFT_SYMMETRIC_6:
- pd_idx = data_disks - stripe % (raid_disks-1);
+ pd_idx = data_disks - sector_div(stripe2, raid_disks-1);
*dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
qd_idx = raid_disks - 1;
break;
case ALGORITHM_RIGHT_SYMMETRIC_6:
- pd_idx = stripe % (raid_disks-1);
+ pd_idx = sector_div(stripe2, raid_disks-1);
*dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
qd_idx = raid_disks - 1;
break;
: conf->algorithm;
sector_t stripe;
int chunk_offset;
- int chunk_number, dummy1, dd_idx = i;
+ sector_t chunk_number;
+ int dummy1, dd_idx = i;
sector_t r_sector;
struct stripe_head sh2;
chunk_offset = sector_div(new_sector, sectors_per_chunk);
stripe = new_sector;
- BUG_ON(new_sector != stripe);
if (i == sh->pd_idx)
return 0;
}
chunk_number = stripe * data_disks + i;
- r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset;
+ r_sector = chunk_number * sectors_per_chunk + chunk_offset;
check = raid5_compute_sector(conf, r_sector,
previous, &dummy1, &sh2);
struct cnic_local *cp = dev->cnic_priv;
u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
- prefetch(cp->status_blk.bnx2x);
- prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+ if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
+ prefetch(cp->status_blk.bnx2x);
+ prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
- if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
tasklet_schedule(&cp->cnic_irq_task);
-
- cnic_chk_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
+ }
return 0;
}
i = 0;
}
+ if (i == tx_ring->next_to_use)
+ break;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
}
/* Limit the number of tx's outstanding for hw bug */
if (id->driver_data & DEV_NEED_TX_LIMIT) {
np->tx_limit = 1;
- if ((id->driver_data & DEV_NEED_TX_LIMIT2) &&
+ if (((id->driver_data & DEV_NEED_TX_LIMIT2) == DEV_NEED_TX_LIMIT2) &&
pci_dev->revision >= 0xA2)
np->tx_limit = 0;
}
retval = 0;
break;
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
/* quad port adapters only support WoL on port A */
if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) {
wol->supported = 0;
adapter->eeprom_wol = 0;
break;
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
/* if quad port adapter, disable WoL on all but port A */
if (global_quad_port_a != 0)
adapter->eeprom_wol = 0;
if (pause->tx_pause != mgp->pause)
return myri10ge_change_pause(mgp, pause->tx_pause);
if (pause->rx_pause != mgp->pause)
- return myri10ge_change_pause(mgp, pause->tx_pause);
+ return myri10ge_change_pause(mgp, pause->rx_pause);
if (pause->autoneg != 0)
return -EINVAL;
return 0;
{
unsigned int ioaddr = dev->base_addr;
struct smc_private *smc = netdev_priv(dev);
- u_int multicast_table[ 2 ] = { 0, };
+ unsigned char multicast_table[8];
unsigned long flags;
u_short rx_cfg_setting;
+ int i;
+
+ memset(multicast_table, 0, sizeof(multicast_table));
if (dev->flags & IFF_PROMISC) {
rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
netdev_for_each_mc_addr(mc_addr, dev) {
u_int position = ether_crc(6, mc_addr->dmi_addr);
-#ifndef final_version /* Verify multicast address. */
- if ((mc_addr->dmi_addr[0] & 1) == 0)
- continue;
-#endif
multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
}
}
/* Load MC table and Rx setting into the chip without interrupts. */
spin_lock_irqsave(&smc->lock, flags);
SMC_SELECT_BANK(3);
- outl(multicast_table[0], ioaddr + MULTICAST0);
- outl(multicast_table[1], ioaddr + MULTICAST4);
+ for (i = 0; i < 8; i++)
+ outb(multicast_table[i], ioaddr + MULTICAST0 + i);
SMC_SELECT_BANK(0);
outw(rx_cfg_setting, ioaddr + RCR);
SMC_SELECT_BANK(2);
u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
u32 mode = VPORT_MISS_MODE_DROP;
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
qlcnic_nic_add_mac(adapter, adapter->mac_addr);
qlcnic_nic_add_mac(adapter, bcast_addr);
#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor))
#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor))
#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */
-#define MCAST_MAX 4 /* Max number multicast addresses to filter */
+#define MCAST_MAX 3 /* Max number multicast addresses to filter */
/* Descriptor status */
#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */
crc >>= 26;
hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
}
- /* Write the index of the hash table */
- for (i = 0; i < 4; i++)
- iowrite16(hash_table[i] << 14, ioaddr + MCR1);
/* Fill the MAC hash tables with their values */
iowrite16(hash_table[0], ioaddr + MAR0);
iowrite16(hash_table[1], ioaddr + MAR1);
iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
} else {
- iowrite16(0xffff, ioaddr + MID_0L + 8 * i);
- iowrite16(0xffff, ioaddr + MID_0M + 8 * i);
- iowrite16(0xffff, ioaddr + MID_0H + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
+ iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
}
i++;
}
}
pr_info("done!\n");
- if (!request_mem_region(res->start, (res->end - res->start),
+ if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
pr_err("%s: ERROR: memory allocation failed"
"cannot get the I/O addr 0x%x\n",
goto out;
}
- addr = ioremap(res->start, (res->end - res->start));
+ addr = ioremap(res->start, resource_size(res));
if (!addr) {
- pr_err("%s: ERROR: memory mapping failed \n", __func__);
+ pr_err("%s: ERROR: memory mapping failed\n", __func__);
ret = -ENOMEM;
goto out;
}
out:
if (ret < 0) {
platform_set_drvdata(pdev, NULL);
- release_mem_region(res->start, (res->end - res->start));
+ release_mem_region(res->start, resource_size(res));
if (addr != NULL)
iounmap(addr);
}
iounmap((void *)ndev->base_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, (res->end - res->start));
+ release_mem_region(res->start, resource_size(res));
free_netdev(ndev);
}
}
+ /* Orphan the skb - required as we might hang on to it
+ * for indefinite time. */
+ skb_orphan(skb);
+
/* Enqueue packet */
skb_queue_tail(&tun->socket.sk->sk_receive_queue, skb);
dev->trans_start = jiffies;
struct scatterlist sg[2];
int err;
+ sg_init_table(sg, 2);
skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb))
return -ENOMEM;
char *p;
int i, err, offset;
+ sg_init_table(sg, MAX_SKB_FRAGS + 2);
/* page in sg[MAX_SKB_FRAGS + 1] is list tail */
for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
first = get_a_page(vi, gfp);
ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL);
}
+static void ppp_close(struct net_device *dev)
+{
+ ppp_tx_flush();
+}
+
static struct hdlc_proto proto = {
.start = ppp_start,
.stop = ppp_stop,
+ .close = ppp_close,
.type_trans = ppp_type_trans,
.ioctl = ppp_ioctl,
.netif_rx = ppp_rx,
all_wiphys_idle = ath9k_all_wiphys_idle(sc);
ath9k_set_wiphy_idle(aphy, idle);
- if (!idle && all_wiphys_idle)
- enable_radio = true;
+ enable_radio = (!idle && all_wiphys_idle);
/*
* After we unlock here its possible another wiphy
IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
"%d index %d\n", scd_ssn , index);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+ if (qc)
+ iwl_free_tfds_in_queue(priv, sta_id,
+ tid, freed);
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
tx_resp->failure_frame);
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
- iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+ if (qc && likely(sta_id != IWL_INVALID_STATION))
+ iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
+ else if (sta_id == IWL_INVALID_STATION)
+ IWL_DEBUG_TX_REPLY(priv, "Station not known\n");
if (priv->mac80211_registered &&
(iwl_queue_space(&txq->q) > txq->q.low_mark))
iwl_wake_queue(priv, txq_id);
}
-
- iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+ if (qc && likely(sta_id != IWL_INVALID_STATION))
+ iwl_txq_check_empty(priv, sta_id, tid, txq_id);
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n");
!!(rate_n_flags & RATE_MCS_ANT_C_MSK);
}
+/*
+ * Static function to get the expected throughput from an iwl_scale_tbl_info
+ * that wraps a NULL pointer check
+ */
+static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
+{
+ if (tbl->expected_tpt)
+ return tbl->expected_tpt[rs_index];
+ return 0;
+}
+
/**
* rs_collect_tx_data - Update the success/failure sliding window
*
* at this rate. window->data contains the bitmask of successful
* packets.
*/
-static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
- int scale_index, s32 tpt, int attempts,
- int successes)
+static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes)
{
struct iwl_rate_scale_data *window = NULL;
static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
- s32 fail_count;
+ s32 fail_count, tpt;
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
return -EINVAL;
/* Select window for current tx bit rate */
- window = &(windows[scale_index]);
+ window = &(tbl->win[scale_index]);
+
+ /* Get expected throughput */
+ tpt = get_expected_tpt(tbl, scale_index);
/*
* Keep track of only the latest 62 tx frame attempts in this rate's
return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
(a->is_SGI == b->is_SGI);
}
-/*
- * Static function to get the expected throughput from an iwl_scale_tbl_info
- * that wraps a NULL pointer check
- */
-static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
-{
- if (tbl->expected_tpt)
- return tbl->expected_tpt[rs_index];
- return 0;
-}
/*
* mac80211 sends us Tx status
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct iwl_rate_scale_data *window = NULL;
enum mac80211_rate_control_flags mac_flags;
u32 tx_rate;
struct iwl_scale_tbl_info tbl_type;
- struct iwl_scale_tbl_info *curr_tbl, *other_tbl;
- s32 tpt = 0;
+ struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
return;
}
- window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
/*
* Updating the frame history depends on whether packets were
tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
&rs_index);
- tpt = get_expected_tpt(curr_tbl, rs_index);
- rs_collect_tx_data(window, rs_index, tpt,
+ rs_collect_tx_data(curr_tbl, rs_index,
info->status.ampdu_ack_len,
info->status.ampdu_ack_map);
* table as active/search.
*/
if (table_type_matches(&tbl_type, curr_tbl))
- tpt = get_expected_tpt(curr_tbl, rs_index);
+ tmp_tbl = curr_tbl;
else if (table_type_matches(&tbl_type, other_tbl))
- tpt = get_expected_tpt(other_tbl, rs_index);
+ tmp_tbl = other_tbl;
else
continue;
-
- /* Constants mean 1 transmission, 0 successes */
- if (i < retries)
- rs_collect_tx_data(window, rs_index, tpt, 1,
- 0);
- else
- rs_collect_tx_data(window, rs_index, tpt, 1,
- legacy_success);
+ rs_collect_tx_data(tmp_tbl, rs_index, 1,
+ i < retries ? 0 : legacy_success);
}
/* Update success/fail counts if not searching for new mode */
}
}
+ /*
+ * The above algorithm sometimes fails when the ucode
+ * reports 0 for all chains. It's not clear why that
+ * happens to start with, but it is then causing trouble
+ * because this can make us enable more chains than the
+ * hardware really has.
+ *
+ * To be safe, simply mask out any chains that we know
+ * are not on the device.
+ */
+ active_chains &= priv->hw_params.valid_rx_ant;
+
num_tx_chains = 0;
for (i = 0; i < NUM_RX_CHAINS; i++) {
/* loops on all the bits of
spin_unlock_irqrestore(&priv->lock, flags);
- /* Allocate and init all Tx and Command queues */
- ret = iwl_txq_ctx_reset(priv);
- if (ret)
- return ret;
+ /* Allocate or reset and init all Tx and Command queues */
+ if (!priv->txq) {
+ ret = iwl_txq_ctx_alloc(priv);
+ if (ret)
+ return ret;
+ } else
+ iwl_txq_ctx_reset(priv);
set_bit(STATUS_INIT, &priv->status);
/*****************************************************
* TX
******************************************************/
-int iwl_txq_ctx_reset(struct iwl_priv *priv);
+int iwl_txq_ctx_alloc(struct iwl_priv *priv);
+void iwl_txq_ctx_reset(struct iwl_priv *priv);
void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
+void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+ int slots_num, u32 txq_id);
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
struct iwl_queue *q = &txq->q;
struct device *dev = &priv->pci_dev->dev;
int i;
+ bool huge = false;
if (q->n_bd == 0)
return;
+ for (; q->read_ptr != q->write_ptr;
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+ /* we have no way to tell if it is a huge cmd ATM */
+ i = get_cmd_index(q, q->read_ptr, 0);
+
+ if (txq->meta[i].flags & CMD_SIZE_HUGE) {
+ huge = true;
+ continue;
+ }
+
+ pci_unmap_single(priv->pci_dev,
+ pci_unmap_addr(&txq->meta[i], mapping),
+ pci_unmap_len(&txq->meta[i], len),
+ PCI_DMA_BIDIRECTIONAL);
+ }
+ if (huge) {
+ i = q->n_window;
+ pci_unmap_single(priv->pci_dev,
+ pci_unmap_addr(&txq->meta[i], mapping),
+ pci_unmap_len(&txq->meta[i], len),
+ PCI_DMA_BIDIRECTIONAL);
+ }
+
/* De-alloc array of command/tx buffers */
for (i = 0; i <= TFD_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
}
EXPORT_SYMBOL(iwl_tx_queue_init);
+void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
+ int slots_num, u32 txq_id)
+{
+ int actual_slots = slots_num;
+
+ if (txq_id == IWL_CMD_QUEUE_NUM)
+ actual_slots++;
+
+ memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
+
+ txq->need_update = 0;
+
+ /* Initialize queue's high/low-water marks, and head/tail indexes */
+ iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+ /* Tell device where to find queue */
+ priv->cfg->ops->lib->txq_init(priv, txq);
+}
+EXPORT_SYMBOL(iwl_tx_queue_reset);
+
/**
* iwl_hw_txq_ctx_free - Free TXQ Context
*
/* Tx queues */
if (priv->txq) {
- for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
- txq_id++)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_cmd_queue_free(priv);
else
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
/**
- * iwl_txq_ctx_reset - Reset TX queue context
- * Destroys all DMA structures and initialize them again
+ * iwl_txq_ctx_alloc - allocate TX queue context
+ * Allocate all Tx DMA structures and initialize them
*
* @param priv
* @return error code
*/
-int iwl_txq_ctx_reset(struct iwl_priv *priv)
+int iwl_txq_ctx_alloc(struct iwl_priv *priv)
{
- int ret = 0;
+ int ret;
int txq_id, slots_num;
unsigned long flags;
return ret;
}
+void iwl_txq_ctx_reset(struct iwl_priv *priv)
+{
+ int txq_id, slots_num;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Turn off all Tx DMA fifos */
+ priv->cfg->ops->lib->txq_set_sched(priv, 0);
+
+ /* Tell NIC where to find the "keep warm" buffer */
+ iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Alloc and init all Tx queues, including the command queue (#4) */
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
+ slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
+ TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+ iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
+ }
+}
+
/**
- * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
+ * iwl_txq_ctx_stop - Stop all Tx DMA channels
*/
void iwl_txq_ctx_stop(struct iwl_priv *priv)
{
1000);
}
spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Deallocate memory for all Tx queues */
- iwl_hw_txq_ctx_free(priv);
}
EXPORT_SYMBOL(iwl_txq_ctx_stop);
spin_lock_irqsave(&priv->hcmd_lock, flags);
+ /* If this is a huge cmd, mark the huge flag also on the meta.flags
+ * of the _original_ cmd. This is used for DMA mapping clean up.
+ */
+ if (cmd->flags & CMD_SIZE_HUGE) {
+ idx = get_cmd_index(q, q->write_ptr, 0);
+ txq->meta[idx].flags = CMD_SIZE_HUGE;
+ }
+
idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
+ struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
return;
}
- cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
- cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
- meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
+ /* If this is a huge cmd, clear the huge flag on the meta.flags
+ * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
+ * the DMA buffer for the scan (huge) command.
+ */
+ if (huge) {
+ cmd_index = get_cmd_index(&txq->q, index, 0);
+ txq->meta[cmd_index].flags = 0;
+ }
+ cmd_index = get_cmd_index(&txq->q, index, huge);
+ cmd = txq->cmd[cmd_index];
+ meta = &txq->meta[cmd_index];
pci_unmap_single(priv->pci_dev,
pci_unmap_addr(meta, mapping),
get_cmd_string(cmd->hdr.cmd));
wake_up_interruptible(&priv->wait_command_queue);
}
+ meta->flags = 0;
}
EXPORT_SYMBOL(iwl_tx_cmd_complete);
if (!s)
return -EINVAL;
+ if (s->functions) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
/* We do not want to validate the CIS cache... */
mutex_lock(&s->ops_mutex);
destroy_cis_cache(s);
count = 0;
else {
struct pcmcia_socket *s;
- unsigned int chains;
+ unsigned int chains = 1;
if (off + count > size)
count = size - off;
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
- if (pccard_validate_cis(s, &chains))
+ if (!s->functions && pccard_validate_cis(s, &chains))
return -EIO;
if (!chains)
return -ENODATA;
ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
IRQF_DISABLED, "pcmcia_insert", sock);
- if (ret)
+ if (ret) {
+ local_irq_restore(flags);
goto out1;
+ }
ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
IRQF_DISABLED, "pcmcia_eject", sock);
new_funcs = mfc.nfn;
else
new_funcs = 1;
- if (old_funcs > new_funcs) {
+ if (old_funcs != new_funcs) {
+ /* we need to re-start */
pcmcia_card_remove(s, NULL);
pcmcia_card_add(s);
- } else if (new_funcs > old_funcs) {
- s->functions = new_funcs;
- pcmcia_device_add(s, 1);
}
}
struct pcmcia_socket *s = dev->socket;
const struct firmware *fw;
int ret = -ENOMEM;
+ cistpl_longlink_mfc_t mfc;
+ int old_funcs, new_funcs = 1;
if (!filename)
return -EINVAL;
goto release;
}
+ /* we need to re-start if the number of functions changed */
+ old_funcs = s->functions;
+ if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
+ &mfc))
+ new_funcs = mfc.nfn;
+
+ if (old_funcs != new_funcs)
+ ret = -EBUSY;
/* update information */
pcmcia_device_query(dev);
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
dev_dbg(&dev->dev, "device needs a fake CIS\n");
if (!dev->socket->fake_cis)
- pcmcia_load_firmware(dev, did->cisfile);
-
- if (!dev->socket->fake_cis)
- return 0;
+ if (pcmcia_load_firmware(dev, did->cisfile))
+ return 0;
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
else
printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
-#ifdef CONFIG_PCMCIA_PROBE
-
- if (s->irq.AssignedIRQ != 0) {
- /* If the interrupt is already assigned, it must be the same */
+ /* If the interrupt is already assigned, it must be the same */
+ if (s->irq.AssignedIRQ != 0)
irq = s->irq.AssignedIRQ;
- } else {
+
+#ifdef CONFIG_PCMCIA_PROBE
+ if (!irq) {
int try;
u32 mask = s->irq_mask;
void *data = p_dev; /* something unique to this device */
return;
}
for (i = base, most = 0; i < base+num; i += 8) {
- res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+ res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res)
continue;
hole = inb(i);
bad = any = 0;
for (i = base; i < base+num; i += 8) {
- res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
- if (!res)
+ res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+ if (!res) {
+ if (!any)
+ printk(" excluding");
+ if (!bad)
+ bad = any = i;
continue;
+ }
for (j = 0; j < 8; j++)
if (inb(i+j) != most)
break;
}
if (bad) {
if ((num > 16) && (bad == base) && (i == base+num)) {
+ sub_interval(&s_data->io_db, bad, i-bad);
printk(" nothing: probe failed.\n");
return;
} else {
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{
struct socket_data *data = s->resource_data;
- unsigned long size = end - start + 1;
+ unsigned long size;
int ret = 0;
#if defined(CONFIG_X86)
start = 0x100;
#endif
+ size = end - start + 1;
+
if (end < start)
return -EINVAL;
dev_get_platdata(&pdev->dev);
int i;
+ platform_set_drvdata(pdev, NULL);
+
for (i = 0; i < pdata->num_regulators; i++)
regulator_unregister(priv->regulators[i]);
+ kfree(priv);
return 0;
}
/* Process requests that may be recovered */
if (cqr->status == DASD_CQR_NEED_ERP) {
erp_fn = base->discipline->erp_action(cqr);
- erp_fn(cqr);
+ if (IS_ERR(erp_fn(cqr)))
+ continue;
goto restart;
}
cqr->retries);
dasd_block_set_timer(device->block, (HZ << 3));
}
- return cqr;
+ return erp;
}
ccw = cqr->cpaddr;
/* add erp and initialize with default TIC */
erp = dasd_3990_erp_add_erp(cqr);
+ if (IS_ERR(erp))
+ return erp;
+
/* inspect sense, determine specific ERP if possible */
if (erp != cqr) {
if (erp == NULL) {
/* no matching erp found - set up erp */
erp = dasd_3990_erp_additional_erp(cqr);
+ if (IS_ERR(erp))
+ return erp;
} else {
/* matching erp found - set all leading erp's to DONE */
erp = dasd_3990_erp_handle_match_erp(cqr, erp);
rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
else
rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);
- if (rc) {
- free_page((unsigned long) ipl_block);
- return rc;
- }
- if (csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
+ if (rc || csum_partial(ipl_block, ipl_block->hdr.len, 0) !=
ipib_info.checksum) {
TRACE("Checksum does not match\n");
free_page((unsigned long) ipl_block);
#include "chsc.h"
static void *sei_page;
+static DEFINE_SPINLOCK(sda_lock);
/**
* chsc_error_from_response() - convert a chsc response to an error
kfree(sei_page);
}
-int __init
-chsc_enable_facility(int operation_code)
+int chsc_enable_facility(int operation_code)
{
int ret;
- struct {
+ static struct {
struct chsc_header request;
u8 reserved1:4;
u8 format:4;
u32 reserved5:4;
u32 format2:4;
u32 reserved6:24;
- } __attribute__ ((packed)) *sda_area;
+ } __attribute__ ((packed, aligned(4096))) sda_area;
- sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
- if (!sda_area)
- return -ENOMEM;
- sda_area->request.length = 0x0400;
- sda_area->request.code = 0x0031;
- sda_area->operation_code = operation_code;
+ spin_lock(&sda_lock);
+ memset(&sda_area, 0, sizeof(sda_area));
+ sda_area.request.length = 0x0400;
+ sda_area.request.code = 0x0031;
+ sda_area.operation_code = operation_code;
- ret = chsc(sda_area);
+ ret = chsc(&sda_area);
if (ret > 0) {
ret = (ret == 3) ? -ENODEV : -EBUSY;
goto out;
}
- switch (sda_area->response.code) {
+ switch (sda_area.response.code) {
case 0x0101:
ret = -EOPNOTSUPP;
break;
default:
- ret = chsc_error_from_response(sda_area->response.code);
+ ret = chsc_error_from_response(sda_area.response.code);
}
if (ret != 0)
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
- operation_code, sda_area->response.code);
+ operation_code, sda_area.response.code);
out:
- free_page((unsigned long)sda_area);
+ spin_unlock(&sda_lock);
return ret;
}
* since we don't have a way to clear the subchannel and
* cannot disable it with a request running.
*/
- cc = stsch(sch->schid, &schib);
+ cc = stsch_err(sch->schid, &schib);
if (!cc && scsw_stctl(&schib.scsw))
return -EAGAIN;
return 0;
struct schib schib;
int ccode, retry, ret = 0;
- if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
for (retry = 0; retry < 5; retry++) {
return ccode;
switch (ccode) {
case 0: /* successful */
- if (stsch(sch->schid, &schib) ||
+ if (stsch_err(sch->schid, &schib) ||
!css_sch_is_valid(&schib))
return -ENODEV;
if (cio_check_config(sch, &schib)) {
{
struct schib schib;
- if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
memcpy(&sch->schib, &schib, sizeof(schib));
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
schid.sch_no = console_irq;
- if (stsch(schid, &console_subchannel.schib) != 0 ||
+ if (stsch_err(schid, &console_subchannel.schib) != 0 ||
(console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) ||
!console_subchannel.schib.pmcw.dnv)
return -1;
cc = 0;
for (retry=0;retry<3;retry++) {
schib->pmcw.ena = 0;
- cc = msch(schid, schib);
+ cc = msch_err(schid, schib);
if (cc)
return (cc==3?-ENODEV:-EBUSY);
- if (stsch(schid, schib) || !css_sch_is_valid(schib))
+ if (stsch_err(schid, schib) || !css_sch_is_valid(schib))
return -ENODEV;
if (!schib->pmcw.ena)
return 0;
pgm_check_occured = 0;
s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
- rc = stsch(schid, addr);
+ rc = stsch_err(schid, addr);
s390_base_pgm_handler_fn = NULL;
/* The program check handler could have changed pgm_check_occured. */
/* No default clear strategy */
break;
}
- stsch(schid, &schib);
+ stsch_err(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
out:
schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
if (!schid.one)
return -ENODEV;
- if (stsch(schid, &schib))
+ if (stsch_err(schid, &schib))
return -ENODEV;
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
return -ENODEV;
/* Try to enable MSS. */
ret = chsc_enable_facility(CHSC_SDA_OC_MSS);
- switch (ret) {
- case 0: /* Success. */
- max_ssid = __MAX_SSID;
- break;
- case -ENOMEM:
- goto out;
- default:
+ if (ret)
max_ssid = 0;
- }
+ else /* Success. */
+ max_ssid = __MAX_SSID;
ret = slow_subchannel_init();
if (ret)
}
subsys_initcall_sync(channel_subsystem_init_sync);
+void channel_subsystem_reinit(void)
+{
+ chsc_enable_facility(CHSC_SDA_OC_MSS);
+}
+
#ifdef CONFIG_PROC_FS
static ssize_t cio_settle_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
sch = to_subchannel(cdev->dev.parent);
private = to_io_private(sch);
orb = &private->orb;
- cc = stsch(sch->schid, &schib);
+ cc = stsch_err(sch->schid, &schib);
printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
"device information:\n", get_clock());
blktrc.inb_usage = req->qdio_req.qdio_inb_usage;
blktrc.outb_usage = req->qdio_req.qdio_outb_usage;
- if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA) {
+ if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA &&
+ !(req->status & ZFCP_STATUS_FSFREQ_ERROR)) {
blktrc.flags |= ZFCP_BLK_LAT_VALID;
blktrc.channel_lat = lat_in->channel_lat * ticks;
blktrc.fabric_lat = lat_in->fabric_lat * ticks;
fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
- zfcp_fsf_req_trace(req, scpnt);
-
skip_fsfstatus:
+ zfcp_fsf_req_trace(req, scpnt);
zfcp_dbf_scsi_result(req->adapter->dbf, scpnt, req);
scpnt->host_scribble = NULL;
SE_DEBUG(DBG_LVL_1,
"Failed to allocate memory for"
"mgmt_invalidate_icds \n");
+ spin_unlock(&ctrl->mbox_lock);
return -1;
}
nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
u32 num_ccell;
int ofld_conns_active;
+ wait_queue_head_t eh_wait;
int max_active_conns;
struct iscsi_cid_queue cid_que;
spinlock_t lock; /* protects hba structure access */
struct mutex net_dev_lock;/* sync net device access */
+ int hba_shutdown_tmo;
/*
* PCI related info.
*/
struct bnx2i_hba *hba = handle;
/* check if cleanup happened in GOING_DOWN context */
- clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN,
&hba->adapter_state))
iscsi_host_for_each_session(hba->shost,
bnx2i_drop_session);
+
+ /* Wait for all endpoints to be torn down, Chip will be reset once
+ * control returns to network driver. So it is required to cleanup and
+ * release all connection resources before returning from this routine.
+ */
+ wait_event_interruptible_timeout(hba->eh_wait,
+ (hba->ofld_conns_active == 0),
+ hba->hba_shutdown_tmo);
+ /* This flag should be cleared last so that ep_disconnect() gracefully
+ * cleans up connection context
+ */
+ clear_bit(ADAPTER_STATE_UP, &hba->adapter_state);
}
/**
spin_lock_init(&hba->lock);
mutex_init(&hba->net_dev_lock);
+ init_waitqueue_head(&hba->eh_wait);
+ if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
+ hba->hba_shutdown_tmo = 240 * HZ;
+ else /* 5706/5708/5709 */
+ hba->hba_shutdown_tmo = 30 * HZ;
if (iscsi_host_add(shost, &hba->pcidev->dev))
goto free_dump_mem;
*/
hba = bnx2i_check_route(dst_addr);
- if (!hba) {
- rc = -ENOMEM;
+ if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) {
+ rc = -EINVAL;
goto check_busy;
}
(bnx2i_ep->state ==
EP_STATE_CONNECT_COMPL)),
msecs_to_jiffies(timeout_ms));
- if (!rc || (bnx2i_ep->state == EP_STATE_OFLD_FAILED))
+ if (bnx2i_ep->state == EP_STATE_OFLD_FAILED)
rc = -1;
if (rc > 0)
if (!hba->ofld_conns_active)
bnx2i_unreg_dev_all();
+
+ wake_up_interruptible(&hba->eh_wait);
}
static int adpt_detect(struct scsi_host_template* sht)
{
struct pci_dev *pDev = NULL;
- adpt_hba* pHba;
+ adpt_hba *pHba;
+ adpt_hba *next;
PINFO("Detecting Adaptec I2O RAID controllers...\n");
}
/* In INIT state, Activate IOPs */
- for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
// Activate does get status , init outbound, and get hrt
if (adpt_i2o_activate_hba(pHba) < 0) {
adpt_i2o_delete_hba(pHba);
PDEBUG("HBA's in OPERATIONAL state\n");
printk("dpti: If you have a lot of devices this could take a few minutes.\n");
- for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name);
if (adpt_i2o_lct_get(pHba) < 0){
adpt_i2o_delete_hba(pHba);
adpt_sysfs_class = NULL;
}
- for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
if (adpt_scsi_host_alloc(pHba, sht) < 0){
adpt_i2o_delete_hba(pHba);
continue;
}
}
pci_dev_put(pHba->pDev);
- kfree(pHba);
-
if (adpt_sysfs_class)
device_destroy(adpt_sysfs_class,
MKDEV(DPTI_I2O_MAJOR, pHba->unit));
+ kfree(pHba);
if(hba_count <= 0){
unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);
srp_cmd->buf_fmt = fmt;
}
-static void unmap_sg_list(int num_entries,
- struct device *dev,
- struct srp_direct_buf *md)
-{
- int i;
-
- for (i = 0; i < num_entries; ++i)
- dma_unmap_single(dev, md[i].va, md[i].len, DMA_BIDIRECTIONAL);
-}
-
/**
* unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
* @cmd: srp_cmd whose additional_data member will be unmapped
if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC)
return;
- else if (out_fmt == SRP_DATA_DESC_DIRECT ||
- in_fmt == SRP_DATA_DESC_DIRECT) {
- struct srp_direct_buf *data =
- (struct srp_direct_buf *) cmd->add_data;
- dma_unmap_single(dev, data->va, data->len, DMA_BIDIRECTIONAL);
- } else {
- struct srp_indirect_buf *indirect =
- (struct srp_indirect_buf *) cmd->add_data;
- int num_mapped = indirect->table_desc.len /
- sizeof(struct srp_direct_buf);
- if (num_mapped <= MAX_INDIRECT_BUFS) {
- unmap_sg_list(num_mapped, dev, &indirect->desc_list[0]);
- return;
- }
-
- unmap_sg_list(num_mapped, dev, evt_struct->ext_list);
- }
+ if (evt_struct->cmnd)
+ scsi_dma_unmap(evt_struct->cmnd);
}
static int map_sg_list(struct scsi_cmnd *cmd, int nseg,
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
write_unlock_bh(&tcp_sw_conn->sock->sk->sk_callback_lock);
- if (sock->sk->sk_sleep && waitqueue_active(sock->sk->sk_sleep)) {
+ if (sock->sk->sk_sleep) {
sock->sk->sk_err = EIO;
wake_up_interruptible(sock->sk->sk_sleep);
}
dd_data = cmdiocbq->context1;
/* normal completion and timeout crossed paths, already done */
if (!dd_data) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
return;
}
dd_data = cmdiocbq->context1;
/* normal completion and timeout crossed paths, already done */
if (!dd_data) {
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
return;
}
return 0;
done:
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (bsg_job->request->msgcode == FC_BSG_HST_CT)
kfree(sp->fcport);
kfree(sp->ctx);
if (conn_err_detail)
*conn_err_detail = mbox_sts[5];
if (tcp_source_port_num)
- *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16;
+ *tcp_source_port_num = (uint16_t) (mbox_sts[6] >> 16);
if (connection_id)
*connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
status = QLA_SUCCESS;
{
Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
- spin_unlock_irq(SCpnt->device->host->host_lock);
+ spin_lock_irq(SCpnt->device->host->host_lock);
if (wd7000_adapter_reset(host) < 0) {
spin_unlock_irq(SCpnt->device->host->host_lock);
}
spin_lock_irqsave(&port->lock, flags);
+ uart_update_timeout(port, termios->c_cflag, baud);
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
static void mcf_config_port(struct uart_port *port, int flags)
{
port->type = PORT_MCF;
+ port->fifosize = MCFUART_TXFIFOSIZE;
/* Clear mask, so no surprise interrupts. */
writeb(0, port->membase + MCFUART_UIMR);
/*
* Define the basic serial functions we support.
*/
-static struct uart_ops mcf_uart_ops = {
+static const struct uart_ops mcf_uart_ops = {
.tx_empty = mcf_tx_empty,
.get_mctrl = mcf_get_mctrl,
.set_mctrl = mcf_set_mctrl,
.verify_port = mcf_verify_port,
};
-static struct mcf_uart mcf_ports[3];
+static struct mcf_uart mcf_ports[4];
#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)
* manfid 0x0160, 0x0104
* This card appears to have a 14.7456MHz clock.
*/
+/* Generic Modem: MD55x (GPRS/EDGE) have
+ * Elan VPU16551 UART with 14.7456MHz oscillator
+ * manfid 0x015D, 0x4C45
+ */
static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
{
port->uartclk = 14745600;
.prodid = 0x0104,
.multi = -1,
.setup = quirk_setup_brainboxes_0104,
+ }, {
+ .manfid = 0x015D,
+ .prodid = 0x4C45,
+ .multi = -1,
+ .setup = quirk_setup_brainboxes_0104,
}, {
.manfid = MANFID_IBM,
.prodid = ~0,
extern void printques(int);
-#ifdef MODULE
#include <linux/module.h>
#include <linux/interrupt.h>
-
-
-MODULE_LICENSE("GPL");
-
-#endif
-
-#ifndef CONFIG_PCI
-#error "DT3155 : Kernel PCI support not enabled (DT3155 drive requires PCI)"
-#endif
-
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/poll.h>
#include "dt3155_io.h"
#include "allocator.h"
+
+MODULE_LICENSE("GPL");
+
/* Error variable. Zero means no error. */
int dt3155_errno = 0;
intf->condition = USB_INTERFACE_BINDING;
- /* Bound interfaces are initially active. They are
+ /* Probed interfaces are initially active. They are
* runtime-PM-enabled only if the driver has autosuspend support.
* They are sensitive to their children's power states.
*/
iface->condition = USB_INTERFACE_BOUND;
- /* Bound interfaces are initially active. They are
+ /* Claimed interfaces are initially inactive (suspended). They are
* runtime-PM-enabled only if the driver has autosuspend support.
* They are sensitive to their children's power states.
*/
- pm_runtime_set_active(dev);
+ pm_runtime_set_suspended(dev);
pm_suspend_ignore_children(dev, false);
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
- int i = 0;
+ int i = 0, n = 0;
struct usb_interface *intf;
if (udev->state == USB_STATE_NOTATTACHED ||
/* Suspend all the interfaces and then udev itself */
if (udev->actconfig) {
- for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ n = udev->actconfig->desc.bNumInterfaces;
+ for (i = n - 1; i >= 0; --i) {
intf = udev->actconfig->interface[i];
status = usb_suspend_interface(udev, intf, msg);
if (status != 0)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
- while (--i >= 0) {
+ while (++i < n) {
intf = udev->actconfig->interface[i];
usb_resume_interface(udev, intf, msg, 0);
}
return status;
}
+static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
+{
+ int w, i;
+ struct usb_interface *intf;
+
+ /* Remote wakeup is needed only when we actually go to sleep.
+ * For things like FREEZE and QUIESCE, if the device is already
+ * autosuspended then its current wakeup setting is okay.
+ */
+ if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
+ if (udev->state != USB_STATE_SUSPENDED)
+ udev->do_remote_wakeup = 0;
+ return;
+ }
+
+ /* If remote wakeup is permitted, see whether any interface drivers
+ * actually want it.
+ */
+ w = 0;
+ if (device_may_wakeup(&udev->dev) && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ w |= intf->needs_remote_wakeup;
+ }
+ }
+
+ /* If the device is autosuspended with the wrong wakeup setting,
+ * autoresume now so the setting can be changed.
+ */
+ if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup)
+ pm_runtime_resume(&udev->dev);
+ udev->do_remote_wakeup = w;
+}
+
/* The device lock is held by the PM core */
int usb_suspend(struct device *dev, pm_message_t msg)
{
struct usb_device *udev = to_usb_device(dev);
do_unbind_rebind(udev, DO_UNBIND);
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+ choose_wakeup(udev, msg);
return usb_suspend_both(udev, msg);
}
*/
ehci->periodic_size = DEFAULT_I_TDPS;
INIT_LIST_HEAD(&ehci->cached_itd_list);
+ INIT_LIST_HEAD(&ehci->cached_sitd_list);
if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
return retval;
* this bit; seems too long to spin routinely...
*/
retval = handshake(ehci, status_reg,
- PORT_RESET, 0, 750);
+ PORT_RESET, 0, 1000);
if (retval != 0) {
ehci_err (ehci, "port %d reset error %d\n",
wIndex + 1, retval);
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{
- free_cached_itd_list(ehci);
+ free_cached_lists(ehci);
if (ehci->async)
qh_put (ehci->async);
ehci->async = NULL;
}
snprintf(supply, sizeof(supply), "hsusb%d", i);
omap->regulator[i] = regulator_get(omap->dev, supply);
- if (IS_ERR(omap->regulator[i]))
+ if (IS_ERR(omap->regulator[i])) {
+ omap->regulator[i] = NULL;
dev_dbg(&pdev->dev,
"failed to get ehci port%d regulator\n", i);
- else
+ } else {
regulator_enable(omap->regulator[i]);
+ }
}
ret = omap_start_ehc(omap, hcd);
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
- free_cached_itd_list(ehci);
+ free_cached_lists(ehci);
ehci->next_uframe = -1;
return 0;
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
- /* OK to recycle this SITD now that its completion callback ran. */
+
done:
sitd->urb = NULL;
- sitd->stream = NULL;
- list_move(&sitd->sitd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
-
+ if (ehci->clock_frame != sitd->frame) {
+ /* OK to recycle this SITD now. */
+ sitd->stream = NULL;
+ list_move(&sitd->sitd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
+ } else {
+ /* HW might remember this SITD, so we can't recycle it yet.
+ * Move it to a safe place until a new frame starts.
+ */
+ list_move(&sitd->sitd_list, &ehci->cached_sitd_list);
+ if (stream->refcount == 2) {
+ /* If iso_stream_put() were called here, stream
+ * would be freed. Instead, just prevent reuse.
+ */
+ stream->ep->hcpriv = NULL;
+ stream->ep = NULL;
+ }
+ }
return retval;
}
/*-------------------------------------------------------------------------*/
-static void free_cached_itd_list(struct ehci_hcd *ehci)
+static void free_cached_lists(struct ehci_hcd *ehci)
{
struct ehci_itd *itd, *n;
+ struct ehci_sitd *sitd, *sn;
list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
struct ehci_iso_stream *stream = itd->stream;
list_move(&itd->itd_list, &stream->free_list);
iso_stream_put(ehci, stream);
}
+
+ list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
+ struct ehci_iso_stream *stream = sitd->stream;
+ sitd->stream = NULL;
+ list_move(&sitd->sitd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
+ }
}
/*-------------------------------------------------------------------------*/
clock_frame = -1;
}
if (ehci->clock_frame != clock_frame) {
- free_cached_itd_list(ehci);
+ free_cached_lists(ehci);
ehci->clock_frame = clock_frame;
}
clock %= mod;
clock = now;
clock_frame = clock >> 3;
if (ehci->clock_frame != clock_frame) {
- free_cached_itd_list(ehci);
+ free_cached_lists(ehci);
ehci->clock_frame = clock_frame;
}
} else {
int next_uframe; /* scan periodic, start here */
unsigned periodic_sched; /* periodic activity count */
- /* list of itds completed while clock_frame was still active */
+ /* list of itds & sitds completed while clock_frame was still active */
struct list_head cached_itd_list;
+ struct list_head cached_sitd_list;
unsigned clock_frame;
/* per root hub port */
clear_bit (action, &ehci->actions);
}
-static void free_cached_itd_list(struct ehci_hcd *ehci);
+static void free_cached_lists(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
#error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX."
#endif
-#define CFGCHIP2 DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)
+#define CFGCHIP2 DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG)
static struct clk *usb11_clk;
static struct clk *usb20_clk;
u16 textlength;
u8 shadow_power; /* for PM */
+ u8 has_interface_pm;
};
/* sysfs_streq can't replace this completely
{
int rc;
- if (!mydev->shadow_power && mydev->powered) {
+ if (mydev->powered && !mydev->has_interface_pm) {
rc = usb_autopm_get_interface(mydev->intf);
if (rc < 0)
return;
+ mydev->has_interface_pm = 1;
}
+ if (mydev->shadow_power != 1)
+ return;
+
rc = usb_control_msg(mydev->udev,
usb_sndctrlpipe(mydev->udev, 0),
0x12,
if (rc < 0)
dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
- if (mydev->shadow_power && !mydev->powered)
+ if (!mydev->powered && mydev->has_interface_pm) {
usb_autopm_put_interface(mydev->intf);
+ mydev->has_interface_pm = 0;
+ }
}
static void update_display_mode(struct usb_sevsegdev *mydev)
mydev->intf = interface;
usb_set_intfdata(interface, mydev);
+ /* PM */
+ mydev->shadow_power = 1; /* currently active */
+ mydev->has_interface_pm = 0; /* have not issued autopm_get */
+
/*set defaults */
mydev->textmode = 0x02; /* ascii mode */
mydev->mode_msb = 0x06; /* 6 characters */
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
{ USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
+ { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
{ } /* Terminating entry */
};
/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
#define SANWA_VENDOR_ID 0x11ad
#define SANWA_PRODUCT_ID 0x0001
+
+/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */
+#define ADLINK_VENDOR_ID 0x0b63
+#define ADLINK_ND6530_PRODUCT_ID 0x6530
#define CMOTECH_PRODUCT_CDU550 0x5553
#define CMOTECH_PRODUCT_CDX650 0x6512
+/* LG devices */
+#define LG_VENDOR_ID 0x1004
+#define LG_PRODUCT_VX4400_6000 0x6000 /* VX4400/VX6000/Rumor */
+
+/* Sanyo devices */
+#define SANYO_VENDOR_ID 0x0474
+#define SANYO_PRODUCT_KATANA_LX 0x0754 /* SCP-3800 (Katana LX) */
+
static struct usb_device_id id_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_ALLTEL, 0xff, 0x00, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU550, 0xff, 0xff, 0x00) },
{ USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
{ USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
+ { USB_DEVICE(0x03F0, 0x211D) }, /* HP ev2210 a.k.a MC5725 */
{ USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
/* the array dimension is the number of default entries plus */
/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
/* null entry */
-static struct usb_device_id ti_id_table_3410[10+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
};
-static struct usb_device_id ti_id_table_combined[14+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
MODULE_FIRMWARE("mts_cdma.fw");
MODULE_FIRMWARE("mts_gsm.fw");
MODULE_FIRMWARE("mts_edge.fw");
+MODULE_FIRMWARE("mts_mt9234mu.fw");
+MODULE_FIRMWARE("mts_mt9234zba.fw");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes");
const struct firmware *fw_p;
char buf[32];
+ dbg("%s\n", __func__);
/* try ID specific firmware first, then try generic firmware */
sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
dev->descriptor.idProduct);
case MTS_EDGE_PRODUCT_ID:
strcpy(buf, "mts_edge.fw");
break;
- }
+ case MTS_MT9234MU_PRODUCT_ID:
+ strcpy(buf, "mts_mt9234mu.fw");
+ break;
+ case MTS_MT9234ZBA_PRODUCT_ID:
+ strcpy(buf, "mts_mt9234zba.fw");
+ break;
+ case MTS_MT9234ZBAOLD_PRODUCT_ID:
+ strcpy(buf, "mts_mt9234zba.fw");
+ break; }
}
if (buf[0] == '\0') {
if (tdev->td_is_3410)
return -ENOENT;
}
if (fw_p->size > TI_FIRMWARE_BUF_SIZE) {
- dev_err(&dev->dev, "%s - firmware too large\n", __func__);
+ dev_err(&dev->dev, "%s - firmware too large %d \n", __func__, fw_p->size);
return -ENOENT;
}
status = ti_do_download(dev, pipe, buffer, fw_p->size);
kfree(buffer);
} else {
+ dbg("%s ENOMEM\n", __func__);
status = -ENOMEM;
}
release_firmware(fw_p);
#define MTS_CDMA_PRODUCT_ID 0xF110
#define MTS_GSM_PRODUCT_ID 0xF111
#define MTS_EDGE_PRODUCT_ID 0xF112
+#define MTS_MT9234MU_PRODUCT_ID 0xF114
+#define MTS_MT9234ZBA_PRODUCT_ID 0xF115
+#define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319
/* Commands */
#define TI_GET_VERSION 0x01
old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
keep_alives = 0;
for (cnt = 0;
- keep_alives <= WUIE_ELT_MAX && cnt < wusbhc->ports_max;
+ keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max;
cnt++) {
unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
int log_all)
{
int i;
+
+ if (!mem)
+ return 0;
+
for (i = 0; i < mem->nregions; ++i) {
struct vhost_memory_region *m = mem->regions + i;
unsigned long a = m->userspace_addr;
num = min(num, ARRAY_SIZE(vb->pfns));
for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
- struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY);
+ struct page *page = alloc_page(GFP_HIGHUSER | __GFP_NORETRY |
+ __GFP_NOMEMALLOC | __GFP_NOWARN);
if (!page) {
if (printk_ratelimit())
dev_printk(KERN_INFO, &vb->vdev->dev,
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
- depends on ARCH_OMAP16XX || ARCH_OMAP2 || ARCH_OMAP3
+ depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
help
- Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog. Say 'Y'
- here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
+ Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
+ here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
config PNX4008_WATCHDOG
tristate "PNX4008 Watchdog"
config MAX63XX_WATCHDOG
tristate "Max63xx watchdog"
- depends on ARM
+ depends on ARM && HAS_IOMEM
help
Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
#ifdef CONFIG_FSL_BOOKE
#define WDTP(x) ((((x)&0x3)<<30)|(((x)&0x3c)<<15))
-#define WDTP_MASK (WDTP(0))
+#define WDTP_MASK (WDTP(0x3f))
#else
#define WDTP(x) (TCR_WP(x))
#define WDTP_MASK (TCR_WP_MASK)
static void max63xx_wdt_disable(void)
{
+ u8 val;
+
spin_lock(&io_lock);
- __raw_writeb(3, wdt_base);
+ val = __raw_readb(wdt_base);
+ val &= ~MAX6369_WDSET;
+ val |= 3;
+ __raw_writeb(val, wdt_base);
spin_unlock(&io_lock);
{
struct afs_super_info *super;
struct vfsmount *mnt;
- struct page *page = NULL;
+ struct page *page;
size_t size;
- char *buf, *devname = NULL, *options = NULL;
+ char *buf, *devname, *options;
int ret;
_enter("{%s}", mntpt->d_name.name);
ret = -EINVAL;
size = mntpt->d_inode->i_size;
if (size > PAGE_SIZE - 1)
- goto error;
+ goto error_no_devname;
ret = -ENOMEM;
devname = (char *) get_zeroed_page(GFP_KERNEL);
if (!devname)
- goto error;
+ goto error_no_devname;
options = (char *) get_zeroed_page(GFP_KERNEL);
if (!options)
- goto error;
+ goto error_no_options;
/* read the contents of the AFS special symlink */
page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
- goto error;
+ goto error_no_page;
}
ret = -EIO;
return mnt;
error:
- if (page)
- page_cache_release(page);
- if (devname)
- free_page((unsigned long) devname);
- if (options)
- free_page((unsigned long) options);
+ page_cache_release(page);
+error_no_page:
+ free_page((unsigned long) options);
+error_no_options:
+ free_page((unsigned long) devname);
+error_no_devname:
_leave(" = %d", ret);
return ERR_PTR(ret);
}
if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
printk("BINFMT_FLAT: reloc outside program 0x%x (0 - 0x%x/0x%x)",
- (int) r,(int)(start_brk-start_code),(int)text_len);
+ (int) r,(int)(start_brk-start_data+text_len),(int)text_len);
goto failed;
}
/*
* Get ref for the oldest snapc for an inode with dirty data... that is, the
* only snap context we are allowed to write back.
- *
- * Caller holds i_lock.
*/
-static struct ceph_snap_context *__get_oldest_context(struct inode *inode,
- u64 *snap_size)
+static struct ceph_snap_context *get_oldest_context(struct inode *inode,
+ u64 *snap_size)
{
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_snap_context *snapc = NULL;
struct ceph_cap_snap *capsnap = NULL;
+ spin_lock(&inode->i_lock);
list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
dout(" cap_snap %p snapc %p has %d dirty pages\n", capsnap,
capsnap->context, capsnap->dirty_pages);
break;
}
}
- if (!snapc && ci->i_snap_realm) {
- snapc = ceph_get_snap_context(ci->i_snap_realm->cached_context);
+ if (!snapc && ci->i_head_snapc) {
+ snapc = ceph_get_snap_context(ci->i_head_snapc);
dout(" head snapc %p has %d dirty pages\n",
snapc, ci->i_wrbuffer_ref_head);
}
- return snapc;
-}
-
-static struct ceph_snap_context *get_oldest_context(struct inode *inode,
- u64 *snap_size)
-{
- struct ceph_snap_context *snapc = NULL;
-
- spin_lock(&inode->i_lock);
- snapc = __get_oldest_context(inode, snap_size);
spin_unlock(&inode->i_lock);
return snapc;
}
int len = PAGE_CACHE_SIZE;
loff_t i_size;
int err = 0;
- struct ceph_snap_context *snapc;
+ struct ceph_snap_context *snapc, *oldest;
u64 snap_size = 0;
long writeback_stat;
dout("writepage %p page %p not dirty?\n", inode, page);
goto out;
}
- if (snapc != get_oldest_context(inode, &snap_size)) {
+ oldest = get_oldest_context(inode, &snap_size);
+ if (snapc->seq > oldest->seq) {
dout("writepage %p page %p snapc %p not writeable - noop\n",
inode, page, (void *)page->private);
/* we should only noop if called by kswapd */
WARN_ON((current->flags & PF_MEMALLOC) == 0);
+ ceph_put_snap_context(oldest);
goto out;
}
+ ceph_put_snap_context(oldest);
/* is this a partial page at end of file? */
if (snap_size)
ClearPagePrivate(page);
end_page_writeback(page);
ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
- ceph_put_snap_context(snapc);
+ ceph_put_snap_context(snapc); /* page's reference */
out:
return err;
}
dout("inode %p skipping page %p\n", inode, page);
wbc->pages_skipped++;
}
+ ceph_put_snap_context((void *)page->private);
page->private = 0;
ClearPagePrivate(page);
- ceph_put_snap_context(snapc);
dout("unlocking %d %p\n", i, page);
end_page_writeback(page);
int range_whole = 0;
int should_loop = 1;
pgoff_t max_pages = 0, max_pages_ever = 0;
- struct ceph_snap_context *snapc = NULL, *last_snapc = NULL;
+ struct ceph_snap_context *snapc = NULL, *last_snapc = NULL, *pgsnapc;
struct pagevec pvec;
int done = 0;
int rc = 0;
}
/* only if matching snap context */
- if (snapc != (void *)page->private) {
- dout("page snapc %p != oldest %p\n",
- (void *)page->private, snapc);
+ pgsnapc = (void *)page->private;
+ if (pgsnapc->seq > snapc->seq) {
+ dout("page snapc %p %lld > oldest %p %lld\n",
+ pgsnapc, pgsnapc->seq, snapc, snapc->seq);
unlock_page(page);
if (!locked_pages)
continue; /* keep looking for snap */
struct ceph_snap_context *snapc)
{
struct ceph_snap_context *oldest = get_oldest_context(inode, NULL);
- return !oldest || snapc->seq <= oldest->seq;
+ int ret = !oldest || snapc->seq <= oldest->seq;
+
+ ceph_put_snap_context(oldest);
+ return ret;
}
/*
int pos_in_page = pos & ~PAGE_CACHE_MASK;
int end_in_page = pos_in_page + len;
loff_t i_size;
- struct ceph_snap_context *snapc;
int r;
+ struct ceph_snap_context *snapc, *oldest;
retry_locked:
/* writepages currently holds page lock, but if we change that later, */
BUG_ON(!ci->i_snap_realm);
down_read(&mdsc->snap_rwsem);
BUG_ON(!ci->i_snap_realm->cached_context);
- if (page->private &&
- (void *)page->private != ci->i_snap_realm->cached_context) {
+ snapc = (void *)page->private;
+ if (snapc && snapc != ci->i_head_snapc) {
/*
* this page is already dirty in another (older) snap
* context! is it writeable now?
*/
- snapc = get_oldest_context(inode, NULL);
+ oldest = get_oldest_context(inode, NULL);
up_read(&mdsc->snap_rwsem);
- if (snapc != (void *)page->private) {
+ if (snapc->seq > oldest->seq) {
+ ceph_put_snap_context(oldest);
dout(" page %p snapc %p not current or oldest\n",
- page, (void *)page->private);
+ page, snapc);
/*
* queue for writeback, and wait for snapc to
* be writeable or written
*/
- snapc = ceph_get_snap_context((void *)page->private);
+ snapc = ceph_get_snap_context(snapc);
unlock_page(page);
ceph_queue_writeback(inode);
r = wait_event_interruptible(ci->i_cap_wq,
return r;
return -EAGAIN;
}
+ ceph_put_snap_context(oldest);
/* yay, writeable, do it now (without dropping page lock) */
dout(" page %p snapc %p not current, but oldest\n",
if (capsnap->dirty_pages || capsnap->writing)
continue;
+ /*
+ * if cap writeback already occurred, we should have dropped
+ * the capsnap in ceph_put_wrbuffer_cap_refs.
+ */
+ BUG_ON(capsnap->dirty == 0);
+
/* pick mds, take s_mutex */
mds = __ceph_get_cap_mds(ci, &mseq);
if (session && session->s_mds != mds) {
}
spin_unlock(&inode->i_lock);
- dout("put_cap_refs %p had %s %s\n", inode, ceph_cap_string(had),
- last ? "last" : "");
+ dout("put_cap_refs %p had %s%s%s\n", inode, ceph_cap_string(had),
+ last ? " last" : "", put ? " put" : "");
if (last && !flushsnaps)
ceph_check_caps(ci, 0, NULL);
{
struct inode *inode = &ci->vfs_inode;
int last = 0;
- int last_snap = 0;
+ int complete_capsnap = 0;
+ int drop_capsnap = 0;
int found = 0;
struct ceph_cap_snap *capsnap = NULL;
list_for_each_entry(capsnap, &ci->i_cap_snaps, ci_item) {
if (capsnap->context == snapc) {
found = 1;
- capsnap->dirty_pages -= nr;
- last_snap = !capsnap->dirty_pages;
break;
}
}
BUG_ON(!found);
+ capsnap->dirty_pages -= nr;
+ if (capsnap->dirty_pages == 0) {
+ complete_capsnap = 1;
+ if (capsnap->dirty == 0)
+ /* cap writeback completed before we created
+ * the cap_snap; no FLUSHSNAP is needed */
+ drop_capsnap = 1;
+ }
dout("put_wrbuffer_cap_refs on %p cap_snap %p "
- " snap %lld %d/%d -> %d/%d %s%s\n",
+ " snap %lld %d/%d -> %d/%d %s%s%s\n",
inode, capsnap, capsnap->context->seq,
ci->i_wrbuffer_ref+nr, capsnap->dirty_pages + nr,
ci->i_wrbuffer_ref, capsnap->dirty_pages,
last ? " (wrbuffer last)" : "",
- last_snap ? " (capsnap last)" : "");
+ complete_capsnap ? " (complete capsnap)" : "",
+ drop_capsnap ? " (drop capsnap)" : "");
+ if (drop_capsnap) {
+ ceph_put_snap_context(capsnap->context);
+ list_del(&capsnap->ci_item);
+ list_del(&capsnap->flushing_item);
+ ceph_put_cap_snap(capsnap);
+ }
}
spin_unlock(&inode->i_lock);
if (last) {
ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
iput(inode);
- } else if (last_snap) {
+ } else if (complete_capsnap) {
ceph_flush_snaps(ci);
wake_up(&ci->i_cap_wq);
}
+ if (drop_capsnap)
+ iput(inode);
}
/*
break;
}
WARN_ON(capsnap->dirty_pages || capsnap->writing);
- dout(" removing cap_snap %p follows %lld\n",
- capsnap, follows);
+ dout(" removing %p cap_snap %p follows %lld\n",
+ inode, capsnap, follows);
ceph_put_snap_context(capsnap->context);
list_del(&capsnap->ci_item);
list_del(&capsnap->flushing_item);
spin_lock(&inode->i_lock);
spin_lock(&dcache_lock);
+ last = dentry;
+
if (err < 0)
goto out_unlock;
- last = dentry;
-
p = p->prev;
filp->f_pos++;
req->r_readdir_offset = fi->next_offset;
req->r_args.readdir.frag = cpu_to_le32(frag);
req->r_args.readdir.max_entries = cpu_to_le32(max_entries);
- req->r_num_caps = max_entries;
+ req->r_num_caps = max_entries + 1;
err = ceph_mdsc_do_request(mdsc, NULL, req);
if (err < 0) {
ceph_mdsc_put_request(req);
struct inode *inode = ceph_get_snapdir(parent);
dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
dentry, dentry->d_name.len, dentry->d_name.name, inode);
+ BUG_ON(!d_unhashed(dentry));
d_add(dentry, inode);
err = 0;
}
struct inode *in = NULL;
struct ceph_mds_reply_inode *ininfo;
struct ceph_vino vino;
+ struct ceph_client *client = ceph_sb_to_client(sb);
int i = 0;
int err = 0;
return err;
}
- if (rinfo->head->is_dentry && !req->r_aborted) {
+ /*
+ * ignore null lease/binding on snapdir ENOENT, or else we
+ * will have trouble splicing in the virtual snapdir later
+ */
+ if (rinfo->head->is_dentry && !req->r_aborted &&
+ (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name,
+ client->mount_args->snapdir_name,
+ req->r_dentry->d_name.len))) {
/*
* lookup link rename : null -> possibly existing inode
* mknod symlink mkdir : null -> new inode
static char tag_ack = CEPH_MSGR_TAG_ACK;
static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE;
+#ifdef CONFIG_LOCKDEP
+static struct lock_class_key socket_class;
+#endif
+
static void queue_con(struct ceph_connection *con);
static void con_work(struct work_struct *);
con->sock = sock;
sock->sk->sk_allocation = GFP_NOFS;
+#ifdef CONFIG_LOCKDEP
+ lockdep_set_class(&sock->sk->sk_lock, &socket_class);
+#endif
+
set_sock_callbacks(sock, con);
dout("connect %s\n", pr_addr(&con->peer_addr.in_addr));
con->out_msg = NULL;
}
con->in_seq = 0;
+ con->in_seq_acked = 0;
}
/*
return ERR_PTR(err);
}
-
-/*
- * osd map
- */
-void ceph_osdmap_destroy(struct ceph_osdmap *map)
-{
- dout("osdmap_destroy %p\n", map);
- if (map->crush)
- crush_destroy(map->crush);
- while (!RB_EMPTY_ROOT(&map->pg_temp)) {
- struct ceph_pg_mapping *pg =
- rb_entry(rb_first(&map->pg_temp),
- struct ceph_pg_mapping, node);
- rb_erase(&pg->node, &map->pg_temp);
- kfree(pg);
- }
- while (!RB_EMPTY_ROOT(&map->pg_pools)) {
- struct ceph_pg_pool_info *pi =
- rb_entry(rb_first(&map->pg_pools),
- struct ceph_pg_pool_info, node);
- rb_erase(&pi->node, &map->pg_pools);
- kfree(pi);
- }
- kfree(map->osd_state);
- kfree(map->osd_weight);
- kfree(map->osd_addr);
- kfree(map);
-}
-
-/*
- * adjust max osd value. reallocate arrays.
- */
-static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
-{
- u8 *state;
- struct ceph_entity_addr *addr;
- u32 *weight;
-
- state = kcalloc(max, sizeof(*state), GFP_NOFS);
- addr = kcalloc(max, sizeof(*addr), GFP_NOFS);
- weight = kcalloc(max, sizeof(*weight), GFP_NOFS);
- if (state == NULL || addr == NULL || weight == NULL) {
- kfree(state);
- kfree(addr);
- kfree(weight);
- return -ENOMEM;
- }
-
- /* copy old? */
- if (map->osd_state) {
- memcpy(state, map->osd_state, map->max_osd*sizeof(*state));
- memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr));
- memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight));
- kfree(map->osd_state);
- kfree(map->osd_addr);
- kfree(map->osd_weight);
- }
-
- map->osd_state = state;
- map->osd_weight = weight;
- map->osd_addr = addr;
- map->max_osd = max;
- return 0;
-}
-
/*
* rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid
* to a set of osds)
return NULL;
}
+static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi)
+{
+ rb_erase(&pi->node, root);
+ kfree(pi->name);
+ kfree(pi);
+}
+
void __decode_pool(void **p, struct ceph_pg_pool_info *pi)
{
ceph_decode_copy(p, &pi->v, sizeof(pi->v));
*p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2;
}
+static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map)
+{
+ struct ceph_pg_pool_info *pi;
+ u32 num, len, pool;
+
+ ceph_decode_32_safe(p, end, num, bad);
+ dout(" %d pool names\n", num);
+ while (num--) {
+ ceph_decode_32_safe(p, end, pool, bad);
+ ceph_decode_32_safe(p, end, len, bad);
+ dout(" pool %d len %d\n", pool, len);
+ pi = __lookup_pg_pool(&map->pg_pools, pool);
+ if (pi) {
+ kfree(pi->name);
+ pi->name = kmalloc(len + 1, GFP_NOFS);
+ if (pi->name) {
+ memcpy(pi->name, *p, len);
+ pi->name[len] = '\0';
+ dout(" name is %s\n", pi->name);
+ }
+ }
+ *p += len;
+ }
+ return 0;
+
+bad:
+ return -EINVAL;
+}
+
+/*
+ * osd map
+ */
+void ceph_osdmap_destroy(struct ceph_osdmap *map)
+{
+ dout("osdmap_destroy %p\n", map);
+ if (map->crush)
+ crush_destroy(map->crush);
+ while (!RB_EMPTY_ROOT(&map->pg_temp)) {
+ struct ceph_pg_mapping *pg =
+ rb_entry(rb_first(&map->pg_temp),
+ struct ceph_pg_mapping, node);
+ rb_erase(&pg->node, &map->pg_temp);
+ kfree(pg);
+ }
+ while (!RB_EMPTY_ROOT(&map->pg_pools)) {
+ struct ceph_pg_pool_info *pi =
+ rb_entry(rb_first(&map->pg_pools),
+ struct ceph_pg_pool_info, node);
+ __remove_pg_pool(&map->pg_pools, pi);
+ }
+ kfree(map->osd_state);
+ kfree(map->osd_weight);
+ kfree(map->osd_addr);
+ kfree(map);
+}
+
+/*
+ * adjust max osd value. reallocate arrays.
+ */
+static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
+{
+ u8 *state;
+ struct ceph_entity_addr *addr;
+ u32 *weight;
+
+ state = kcalloc(max, sizeof(*state), GFP_NOFS);
+ addr = kcalloc(max, sizeof(*addr), GFP_NOFS);
+ weight = kcalloc(max, sizeof(*weight), GFP_NOFS);
+ if (state == NULL || addr == NULL || weight == NULL) {
+ kfree(state);
+ kfree(addr);
+ kfree(weight);
+ return -ENOMEM;
+ }
+
+ /* copy old? */
+ if (map->osd_state) {
+ memcpy(state, map->osd_state, map->max_osd*sizeof(*state));
+ memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr));
+ memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight));
+ kfree(map->osd_state);
+ kfree(map->osd_addr);
+ kfree(map->osd_weight);
+ }
+
+ map->osd_state = state;
+ map->osd_weight = weight;
+ map->osd_addr = addr;
+ map->max_osd = max;
+ return 0;
+}
+
/*
* decode a full map.
*/
ceph_decode_32_safe(p, end, max, bad);
while (max--) {
ceph_decode_need(p, end, 4 + 1 + sizeof(pi->v), bad);
- pi = kmalloc(sizeof(*pi), GFP_NOFS);
+ pi = kzalloc(sizeof(*pi), GFP_NOFS);
if (!pi)
goto bad;
pi->id = ceph_decode_32(p);
__decode_pool(p, pi);
__insert_pg_pool(&map->pg_pools, pi);
}
+
+ if (version >= 5 && __decode_pool_names(p, end, map) < 0)
+ goto bad;
+
ceph_decode_32_safe(p, end, map->pool_max, bad);
ceph_decode_32_safe(p, end, map->flags, bad);
}
pi = __lookup_pg_pool(&map->pg_pools, pool);
if (!pi) {
- pi = kmalloc(sizeof(*pi), GFP_NOFS);
+ pi = kzalloc(sizeof(*pi), GFP_NOFS);
if (!pi) {
err = -ENOMEM;
goto bad;
}
__decode_pool(p, pi);
}
+ if (version >= 5 && __decode_pool_names(p, end, map) < 0)
+ goto bad;
/* old_pool */
ceph_decode_32_safe(p, end, len, bad);
ceph_decode_32_safe(p, end, pool, bad);
pi = __lookup_pg_pool(&map->pg_pools, pool);
- if (pi) {
- rb_erase(&pi->node, &map->pg_pools);
- kfree(pi);
- }
+ if (pi)
+ __remove_pg_pool(&map->pg_pools, pi);
}
/* new_up */
int id;
struct ceph_pg_pool v;
int pg_num_mask, pgp_num_mask, lpg_num_mask, lpgp_num_mask;
+ char *name;
};
struct ceph_pg_mapping {
/*
* osdmap encoding versions
*/
-#define CEPH_OSDMAP_INC_VERSION 4
-#define CEPH_OSDMAP_VERSION 4
+#define CEPH_OSDMAP_INC_VERSION 5
+#define CEPH_OSDMAP_INC_VERSION_EXT 5
+#define CEPH_OSDMAP_VERSION 5
+#define CEPH_OSDMAP_VERSION_EXT 5
/*
* fs id
* Caller must hold snap_rwsem for read (i.e., the realm topology won't
* change).
*/
-void ceph_queue_cap_snap(struct ceph_inode_info *ci,
- struct ceph_snap_context *snapc)
+void ceph_queue_cap_snap(struct ceph_inode_info *ci)
{
struct inode *inode = &ci->vfs_inode;
struct ceph_cap_snap *capsnap;
as no new writes are allowed to start when pending, so any
writes in progress now were started before the previous
cap_snap. lucky us. */
- dout("queue_cap_snap %p snapc %p seq %llu used %d"
- " already pending\n", inode, snapc, snapc->seq, used);
+ dout("queue_cap_snap %p already pending\n", inode);
kfree(capsnap);
} else if (ci->i_wrbuffer_ref_head || (used & CEPH_CAP_FILE_WR)) {
+ struct ceph_snap_context *snapc = ci->i_head_snapc;
+
igrab(inode);
atomic_set(&capsnap->nref, 1);
INIT_LIST_HEAD(&capsnap->flushing_item);
capsnap->follows = snapc->seq - 1;
- capsnap->context = ceph_get_snap_context(snapc);
capsnap->issued = __ceph_caps_issued(ci, NULL);
capsnap->dirty = __ceph_caps_dirty(ci);
snapshot. */
capsnap->dirty_pages = ci->i_wrbuffer_ref_head;
ci->i_wrbuffer_ref_head = 0;
- ceph_put_snap_context(ci->i_head_snapc);
+ capsnap->context = snapc;
ci->i_head_snapc = NULL;
list_add_tail(&capsnap->ci_item, &ci->i_cap_snaps);
capsnap->ctime = inode->i_ctime;
capsnap->time_warp_seq = ci->i_time_warp_seq;
if (capsnap->dirty_pages) {
- dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu "
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu "
"still has %d dirty pages\n", inode, capsnap,
capsnap->context, capsnap->context->seq,
- capsnap->size, capsnap->dirty_pages);
+ ceph_cap_string(capsnap->dirty), capsnap->size,
+ capsnap->dirty_pages);
return 0;
}
- dout("finish_cap_snap %p cap_snap %p snapc %p %llu s=%llu clean\n",
+ dout("finish_cap_snap %p cap_snap %p snapc %p %llu %s s=%llu\n",
inode, capsnap, capsnap->context,
- capsnap->context->seq, capsnap->size);
+ capsnap->context->seq, ceph_cap_string(capsnap->dirty),
+ capsnap->size);
spin_lock(&mdsc->snap_flush_lock);
list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
if (lastinode)
iput(lastinode);
lastinode = inode;
- ceph_queue_cap_snap(ci, realm->cached_context);
+ ceph_queue_cap_snap(ci);
spin_lock(&realm->inodes_with_caps_lock);
}
spin_unlock(&realm->inodes_with_caps_lock);
spin_unlock(&realm->inodes_with_caps_lock);
spin_unlock(&inode->i_lock);
- ceph_queue_cap_snap(ci,
- ci->i_snap_realm->cached_context);
+ ceph_queue_cap_snap(ci);
iput(inode);
continue;
extern void ceph_handle_snap(struct ceph_mds_client *mdsc,
struct ceph_mds_session *session,
struct ceph_msg *msg);
-extern void ceph_queue_cap_snap(struct ceph_inode_info *ci,
- struct ceph_snap_context *snapc);
+extern void ceph_queue_cap_snap(struct ceph_inode_info *ci);
extern int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
struct ceph_cap_snap *capsnap);
extern void ceph_cleanup_empty_realms(struct ceph_mds_client *mdsc);
static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,
struct ecryptfs_crypt_stat *crypt_stat)
{
- (*offset) = (crypt_stat->num_header_bytes_at_front
- + (crypt_stat->extent_size * extent_num));
+ (*offset) = ecryptfs_lower_header_size(crypt_stat)
+ + (crypt_stat->extent_size * extent_num);
}
/**
set_extent_mask_and_shift(crypt_stat);
crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- crypt_stat->num_header_bytes_at_front = 0;
+ crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
else {
if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)
- crypt_stat->num_header_bytes_at_front =
+ crypt_stat->metadata_size =
ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
else
- crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE;
+ crypt_stat->metadata_size = PAGE_CACHE_SIZE;
}
}
(*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
}
-static void
-write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
- size_t *written)
+void ecryptfs_write_crypt_stat_flags(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written)
{
u32 flags = 0;
int i;
header_extent_size = (u32)crypt_stat->extent_size;
num_header_extents_at_front =
- (u16)(crypt_stat->num_header_bytes_at_front
- / crypt_stat->extent_size);
+ (u16)(crypt_stat->metadata_size / crypt_stat->extent_size);
put_unaligned_be32(header_extent_size, virt);
virt += 4;
put_unaligned_be16(num_header_extents_at_front, virt);
offset = ECRYPTFS_FILE_SIZE_BYTES;
write_ecryptfs_marker((page_virt + offset), &written);
offset += written;
- write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
+ ecryptfs_write_crypt_stat_flags((page_virt + offset), crypt_stat,
+ &written);
offset += written;
ecryptfs_write_header_metadata((page_virt + offset), crypt_stat,
&written);
rc = -EINVAL;
goto out;
}
- virt_len = crypt_stat->num_header_bytes_at_front;
+ virt_len = crypt_stat->metadata_size;
order = get_order(virt_len);
/* Released in this function */
virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order);
header_extent_size = get_unaligned_be32(virt);
virt += sizeof(__be32);
num_header_extents_at_front = get_unaligned_be16(virt);
- crypt_stat->num_header_bytes_at_front =
- (((size_t)num_header_extents_at_front
- * (size_t)header_extent_size));
+ crypt_stat->metadata_size = (((size_t)num_header_extents_at_front
+ * (size_t)header_extent_size));
(*bytes_read) = (sizeof(__be32) + sizeof(__be16));
if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)
- && (crypt_stat->num_header_bytes_at_front
+ && (crypt_stat->metadata_size
< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {
rc = -EINVAL;
printk(KERN_WARNING "Invalid header size: [%zd]\n",
- crypt_stat->num_header_bytes_at_front);
+ crypt_stat->metadata_size);
}
return rc;
}
*/
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
{
- crypt_stat->num_header_bytes_at_front =
- ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
+ crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
}
/**
ecryptfs_dentry,
ECRYPTFS_VALIDATE_HEADER_SIZE);
if (rc) {
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);
if (rc) {
printk(KERN_DEBUG "Valid eCryptfs headers not found in "
u32 flags;
unsigned int file_version;
size_t iv_bytes;
- size_t num_header_bytes_at_front;
+ size_t metadata_size;
size_t extent_size; /* Data extent size; default is 4096 */
size_t key_size;
size_t extent_shift;
extern struct mutex ecryptfs_daemon_hash_mux;
+static inline size_t
+ecryptfs_lower_header_size(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
+ return 0;
+ return crypt_stat->metadata_size;
+}
+
static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file)
{
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry);
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry);
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
+void ecryptfs_write_crypt_stat_flags(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written);
int ecryptfs_read_and_validate_header_region(char *data,
struct inode *ecryptfs_inode);
int ecryptfs_read_and_validate_xattr_region(char *page_virt,
rc = ecryptfs_read_and_validate_header_region(page_virt,
ecryptfs_dentry->d_inode);
if (rc) {
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
rc = ecryptfs_read_and_validate_xattr_region(page_virt,
ecryptfs_dentry);
if (rc) {
ecryptfs_dentry->d_sb)->mount_crypt_stat;
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
- file_size = (crypt_stat->num_header_bytes_at_front
+ file_size = (crypt_stat->metadata_size
+ i_size_read(lower_dentry->d_inode));
else
file_size = i_size_read(lower_dentry->d_inode);
mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
if (IS_ERR(lower_dentry)) {
rc = PTR_ERR(lower_dentry);
- printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
- "lower_dentry = [%s]\n", __func__, rc,
- ecryptfs_dentry->d_name.name);
+ ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
+ "[%d] on lower_dentry = [%s]\n", __func__, rc,
+ encrypted_and_encoded_name);
goto out_d_drop;
}
if (lower_dentry->d_inode)
mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
if (IS_ERR(lower_dentry)) {
rc = PTR_ERR(lower_dentry);
- printk(KERN_ERR "%s: lookup_one_len() returned [%d] on "
- "lower_dentry = [%s]\n", __func__, rc,
- encrypted_and_encoded_name);
+ ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
+ "[%d] on lower_dentry = [%s]\n", __func__, rc,
+ encrypted_and_encoded_name);
goto out_d_drop;
}
lookup_and_interpose:
rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
if (rc)
goto out_lock;
- fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
- fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
+ fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
old_dentry->d_inode->i_nlink =
ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
i_size_write(new_dentry->d_inode, file_size_save);
return rc;
}
-static int
-ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
+ size_t *bufsiz)
{
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
char *lower_buf;
- size_t lower_bufsiz;
- struct dentry *lower_dentry;
- struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
- char *plaintext_name;
- size_t plaintext_name_size;
+ size_t lower_bufsiz = PATH_MAX;
mm_segment_t old_fs;
int rc;
- lower_dentry = ecryptfs_dentry_to_lower(dentry);
- if (!lower_dentry->d_inode->i_op->readlink) {
- rc = -EINVAL;
- goto out;
- }
- mount_crypt_stat = &ecryptfs_superblock_to_private(
- dentry->d_sb)->mount_crypt_stat;
- /*
- * If the lower filename is encrypted, it will result in a significantly
- * longer name. If needed, truncate the name after decode and decrypt.
- */
- if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
- lower_bufsiz = PATH_MAX;
- else
- lower_bufsiz = bufsiz;
- /* Released in this function */
lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);
- if (lower_buf == NULL) {
- printk(KERN_ERR "%s: Out of memory whilst attempting to "
- "kmalloc [%zd] bytes\n", __func__, lower_bufsiz);
+ if (!lower_buf) {
rc = -ENOMEM;
goto out;
}
(char __user *)lower_buf,
lower_bufsiz);
set_fs(old_fs);
- if (rc >= 0) {
- rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name,
- &plaintext_name_size,
- dentry, lower_buf,
- rc);
- if (rc) {
- printk(KERN_ERR "%s: Error attempting to decode and "
- "decrypt filename; rc = [%d]\n", __func__,
- rc);
- goto out_free_lower_buf;
- }
- /* Check for bufsiz <= 0 done in sys_readlinkat() */
- rc = copy_to_user(buf, plaintext_name,
- min((size_t) bufsiz, plaintext_name_size));
- if (rc)
- rc = -EFAULT;
- else
- rc = plaintext_name_size;
- kfree(plaintext_name);
- fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode);
- }
-out_free_lower_buf:
+ if (rc < 0)
+ goto out;
+ lower_bufsiz = rc;
+ rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry,
+ lower_buf, lower_bufsiz);
+out:
kfree(lower_buf);
+ return rc;
+}
+
+static int
+ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+{
+ char *kbuf;
+ size_t kbufsiz, copied;
+ int rc;
+
+ rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz);
+ if (rc)
+ goto out;
+ copied = min_t(size_t, bufsiz, kbufsiz);
+ rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied;
+ kfree(kbuf);
+ fsstack_copy_attr_atime(dentry->d_inode,
+ ecryptfs_dentry_to_lower(dentry)->d_inode);
out:
return rc;
}
{
loff_t lower_size;
- lower_size = crypt_stat->num_header_bytes_at_front;
+ lower_size = ecryptfs_lower_header_size(crypt_stat);
if (upper_size != 0) {
loff_t num_extents;
return rc;
}
+int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ int rc = 0;
+
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
+ dentry->d_sb)->mount_crypt_stat;
+ generic_fillattr(dentry->d_inode, stat);
+ if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
+ char *target;
+ size_t targetsiz;
+
+ rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz);
+ if (!rc) {
+ kfree(target);
+ stat->size = targetsiz;
+ }
+ }
+ return rc;
+}
+
int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!lower_dentry->d_inode->i_op->setxattr) {
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
goto out;
}
mutex_lock(&lower_dentry->d_inode->i_mutex);
int rc = 0;
if (!lower_dentry->d_inode->i_op->getxattr) {
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
goto out;
}
mutex_lock(&lower_dentry->d_inode->i_mutex);
lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!lower_dentry->d_inode->i_op->listxattr) {
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
goto out;
}
mutex_lock(&lower_dentry->d_inode->i_mutex);
lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!lower_dentry->d_inode->i_op->removexattr) {
- rc = -ENOSYS;
+ rc = -EOPNOTSUPP;
goto out;
}
mutex_lock(&lower_dentry->d_inode->i_mutex);
.put_link = ecryptfs_put_link,
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
+ .getattr = ecryptfs_getattr_link,
.setxattr = ecryptfs_setxattr,
.getxattr = ecryptfs_getxattr,
.listxattr = ecryptfs_listxattr,
return rc;
}
+static void strip_xattr_flag(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) {
+ size_t written;
+
+ crypt_stat->flags &= ~ECRYPTFS_METADATA_IN_XATTR;
+ ecryptfs_write_crypt_stat_flags(page_virt, crypt_stat,
+ &written);
+ crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
+ }
+}
+
/**
* Header Extent:
* Octets 0-7: Unencrypted file size (big-endian)
* (big-endian)
* Octet 26: Begin RFC 2440 authentication token packet set
*/
-static void set_header_info(char *page_virt,
- struct ecryptfs_crypt_stat *crypt_stat)
-{
- size_t written;
- size_t save_num_header_bytes_at_front =
- crypt_stat->num_header_bytes_at_front;
-
- crypt_stat->num_header_bytes_at_front =
- ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
- ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written);
- crypt_stat->num_header_bytes_at_front =
- save_num_header_bytes_at_front;
-}
/**
* ecryptfs_copy_up_encrypted_with_header
* num_extents_per_page)
+ extent_num_in_page);
size_t num_header_extents_at_front =
- (crypt_stat->num_header_bytes_at_front
- / crypt_stat->extent_size);
+ (crypt_stat->metadata_size / crypt_stat->extent_size);
if (view_extent_num < num_header_extents_at_front) {
/* This is a header extent */
memset(page_virt, 0, PAGE_CACHE_SIZE);
/* TODO: Support more than one header extent */
if (view_extent_num == 0) {
+ size_t written;
+
rc = ecryptfs_read_xattr_region(
page_virt, page->mapping->host);
- set_header_info(page_virt, crypt_stat);
+ strip_xattr_flag(page_virt + 16, crypt_stat);
+ ecryptfs_write_header_metadata(page_virt + 20,
+ crypt_stat,
+ &written);
}
kunmap_atomic(page_virt, KM_USER0);
flush_dcache_page(page);
/* This is an encrypted data extent */
loff_t lower_offset =
((view_extent_num * crypt_stat->extent_size)
- - crypt_stat->num_header_bytes_at_front);
+ - crypt_stat->metadata_size);
rc = ecryptfs_read_lower_page_segment(
page, (lower_offset >> PAGE_CACHE_SHIFT),
if (lower_dentry->d_inode) {
fput(inode_info->lower_file);
inode_info->lower_file = NULL;
- d_drop(lower_dentry);
}
}
ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat);
#ifdef CONFIG_BLOCK
-#define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
-#define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
+static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
+{
+ return (offset >> inode->i_blkbits);
+}
+
+static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
+{
+ return (blk << inode->i_blkbits);
+}
/**
* __generic_block_fiemap - FIEMAP for block based inodes (no locking)
- * @inode - the inode to map
- * @arg - the pointer to userspace where we copy everything to
- * @get_block - the fs's get_block function
+ * @inode: the inode to map
+ * @fieinfo: the fiemap info struct that will be passed back to userspace
+ * @start: where to start mapping in the inode
+ * @len: how much space to map
+ * @get_block: the fs's get_block function
*
* This does FIEMAP for block based inodes. Basically it will just loop
* through get_block until we hit the number of extents we want to map, or we
*/
int __generic_block_fiemap(struct inode *inode,
- struct fiemap_extent_info *fieinfo, u64 start,
- u64 len, get_block_t *get_block)
+ struct fiemap_extent_info *fieinfo, loff_t start,
+ loff_t len, get_block_t *get_block)
{
- struct buffer_head tmp;
- unsigned long long start_blk;
- long long length = 0, map_len = 0;
+ struct buffer_head map_bh;
+ sector_t start_blk, last_blk;
+ loff_t isize = i_size_read(inode);
u64 logical = 0, phys = 0, size = 0;
u32 flags = FIEMAP_EXTENT_MERGED;
- int ret = 0, past_eof = 0, whole_file = 0;
+ bool past_eof = false, whole_file = false;
+ int ret = 0;
- if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
+ ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
+ if (ret)
return ret;
- start_blk = logical_to_blk(inode, start);
-
- length = (long long)min_t(u64, len, i_size_read(inode));
- if (length < len)
- whole_file = 1;
+ /*
+ * Either the i_mutex or other appropriate locking needs to be held
+ * since we expect isize to not change at all through the duration of
+ * this call.
+ */
+ if (len >= isize) {
+ whole_file = true;
+ len = isize;
+ }
- map_len = length;
+ start_blk = logical_to_blk(inode, start);
+ last_blk = logical_to_blk(inode, start + len - 1);
do {
/*
* we set b_size to the total size we want so it will map as
* many contiguous blocks as possible at once
*/
- memset(&tmp, 0, sizeof(struct buffer_head));
- tmp.b_size = map_len;
+ memset(&map_bh, 0, sizeof(struct buffer_head));
+ map_bh.b_size = len;
- ret = get_block(inode, start_blk, &tmp, 0);
+ ret = get_block(inode, start_blk, &map_bh, 0);
if (ret)
break;
/* HOLE */
- if (!buffer_mapped(&tmp)) {
- length -= blk_to_logical(inode, 1);
+ if (!buffer_mapped(&map_bh)) {
start_blk++;
/*
- * we want to handle the case where there is an
+ * We want to handle the case where there is an
* allocated block at the front of the file, and then
* nothing but holes up to the end of the file properly,
* to make sure that extent at the front gets properly
* marked with FIEMAP_EXTENT_LAST
*/
if (!past_eof &&
- blk_to_logical(inode, start_blk) >=
- blk_to_logical(inode, 0)+i_size_read(inode))
+ blk_to_logical(inode, start_blk) >= isize)
past_eof = 1;
/*
- * first hole after going past the EOF, this is our
+ * First hole after going past the EOF, this is our
* last extent
*/
if (past_eof && size) {
ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size,
flags);
- break;
+ } else if (size) {
+ ret = fiemap_fill_next_extent(fieinfo, logical,
+ phys, size, flags);
+ size = 0;
}
/* if we have holes up to/past EOF then we're done */
- if (length <= 0 || past_eof)
+ if (start_blk > last_blk || past_eof || ret)
break;
} else {
/*
- * we have gone over the length of what we wanted to
+ * We have gone over the length of what we wanted to
* map, and it wasn't the entire file, so add the extent
* we got last time and exit.
*
* are good to go, just add the extent to the fieinfo
* and break
*/
- if (length <= 0 && !whole_file) {
+ if (start_blk > last_blk && !whole_file) {
ret = fiemap_fill_next_extent(fieinfo, logical,
phys, size,
flags);
}
logical = blk_to_logical(inode, start_blk);
- phys = blk_to_logical(inode, tmp.b_blocknr);
- size = tmp.b_size;
+ phys = blk_to_logical(inode, map_bh.b_blocknr);
+ size = map_bh.b_size;
flags = FIEMAP_EXTENT_MERGED;
- length -= tmp.b_size;
start_blk += logical_to_blk(inode, size);
/*
* soon as we find a hole that the last extent we found
* is marked with FIEMAP_EXTENT_LAST
*/
- if (!past_eof &&
- logical+size >=
- blk_to_logical(inode, 0)+i_size_read(inode))
- past_eof = 1;
+ if (!past_eof && logical + size >= isize)
+ past_eof = true;
}
cond_resched();
} while (1);
- /* if ret is 1 then we just hit the end of the extent array */
+ /* If ret is 1 then we just hit the end of the extent array */
if (ret == 1)
ret = 0;
inode->i_op = &page_symlink_inode_operations;
inode->i_mapping->a_ops = &jfs_aops;
} else {
- inode->i_op = &jfs_symlink_inode_operations;
+ inode->i_op = &jfs_fast_symlink_inode_operations;
/*
* The inline data should be null-terminated, but
* don't let on-disk corruption crash the kernel
bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);
bmp->db_agpref = le32_to_cpu(dbmp_le->dn_agpref);
bmp->db_aglevel = le32_to_cpu(dbmp_le->dn_aglevel);
- bmp->db_agheigth = le32_to_cpu(dbmp_le->dn_agheigth);
+ bmp->db_agheight = le32_to_cpu(dbmp_le->dn_agheight);
bmp->db_agwidth = le32_to_cpu(dbmp_le->dn_agwidth);
bmp->db_agstart = le32_to_cpu(dbmp_le->dn_agstart);
bmp->db_agl2size = le32_to_cpu(dbmp_le->dn_agl2size);
dbmp_le->dn_maxag = cpu_to_le32(bmp->db_maxag);
dbmp_le->dn_agpref = cpu_to_le32(bmp->db_agpref);
dbmp_le->dn_aglevel = cpu_to_le32(bmp->db_aglevel);
- dbmp_le->dn_agheigth = cpu_to_le32(bmp->db_agheigth);
+ dbmp_le->dn_agheight = cpu_to_le32(bmp->db_agheight);
dbmp_le->dn_agwidth = cpu_to_le32(bmp->db_agwidth);
dbmp_le->dn_agstart = cpu_to_le32(bmp->db_agstart);
dbmp_le->dn_agl2size = cpu_to_le32(bmp->db_agl2size);
* tree index of this allocation group within the control page.
*/
agperlev =
- (1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
+ (1 << (L2LPERCTL - (bmp->db_agheight << 1))) / bmp->db_agwidth;
ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
/* dmap control page trees fan-out by 4 and a single allocation
* the subtree to find the leftmost leaf that describes this
* free space.
*/
- for (k = bmp->db_agheigth; k > 0; k--) {
+ for (k = bmp->db_agheight; k > 0; k--) {
for (n = 0, m = (ti << 2) + 1; n < 4; n++) {
if (l2nb <= dcp->stree[m + n]) {
ti = m + n;
}
/*
- * compute db_aglevel, db_agheigth, db_width, db_agstart:
+ * compute db_aglevel, db_agheight, db_width, db_agstart:
* an ag is covered in aglevel dmapctl summary tree,
* at agheight level height (from leaf) with agwidth number of nodes
* each, which starts at agstart index node of the smmary tree node
bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
l2nl =
bmp->db_agl2size - (L2BPERDMAP + bmp->db_aglevel * L2LPERCTL);
- bmp->db_agheigth = l2nl >> 1;
- bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheigth << 1));
- for (i = 5 - bmp->db_agheigth, bmp->db_agstart = 0, n = 1; i > 0;
+ bmp->db_agheight = l2nl >> 1;
+ bmp->db_agwidth = 1 << (l2nl - (bmp->db_agheight << 1));
+ for (i = 5 - bmp->db_agheight, bmp->db_agstart = 0, n = 1; i > 0;
i--) {
bmp->db_agstart += n;
n <<= 2;
__le32 dn_maxag; /* 4: max active alloc group number */
__le32 dn_agpref; /* 4: preferred alloc group (hint) */
__le32 dn_aglevel; /* 4: dmapctl level holding the AG */
- __le32 dn_agheigth; /* 4: height in dmapctl of the AG */
+ __le32 dn_agheight; /* 4: height in dmapctl of the AG */
__le32 dn_agwidth; /* 4: width in dmapctl of the AG */
__le32 dn_agstart; /* 4: start tree index at AG height */
__le32 dn_agl2size; /* 4: l2 num of blks per alloc group */
int dn_maxag; /* max active alloc group number */
int dn_agpref; /* preferred alloc group (hint) */
int dn_aglevel; /* dmapctl level holding the AG */
- int dn_agheigth; /* height in dmapctl of the AG */
+ int dn_agheight; /* height in dmapctl of the AG */
int dn_agwidth; /* width in dmapctl of the AG */
int dn_agstart; /* start tree index at AG height */
int dn_agl2size; /* l2 num of blks per alloc group */
#define db_agsize db_bmap.dn_agsize
#define db_agl2size db_bmap.dn_agl2size
#define db_agwidth db_bmap.dn_agwidth
-#define db_agheigth db_bmap.dn_agheigth
+#define db_agheight db_bmap.dn_agheight
#define db_agstart db_bmap.dn_agstart
#define db_numag db_bmap.dn_numag
#define db_maxlevel db_bmap.dn_maxlevel
extern const struct inode_operations jfs_file_inode_operations;
extern const struct file_operations jfs_file_operations;
extern const struct inode_operations jfs_symlink_inode_operations;
+extern const struct inode_operations jfs_fast_symlink_inode_operations;
extern const struct dentry_operations jfs_ci_dentry_operations;
#endif /* _H_JFS_INODE */
*/
if (ssize <= IDATASIZE) {
- ip->i_op = &jfs_symlink_inode_operations;
+ ip->i_op = &jfs_fast_symlink_inode_operations;
i_fastsymlink = JFS_IP(ip)->i_inline;
memcpy(i_fastsymlink, name, ssize);
else {
jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
- ip->i_op = &page_symlink_inode_operations;
+ ip->i_op = &jfs_symlink_inode_operations;
ip->i_mapping->a_ops = &jfs_aops;
/*
struct inode *iplist[1];
struct jfs_superblock *j_sb, *j_sb2;
uint old_agsize;
+ int agsizechanged = 0;
struct buffer_head *bh, *bh2;
/* If the volume hasn't grown, get out now */
*/
if ((rc = dbExtendFS(ipbmap, XAddress, nblocks)))
goto error_out;
+
+ agsizechanged |= (bmp->db_agsize != old_agsize);
+
/*
* the map now has extended to cover additional nblocks:
* dn_mapsize = oldMapsize + nblocks;
* will correctly identify the new ag);
*/
/* if new AG size the same as old AG size, done! */
- if (bmp->db_agsize != old_agsize) {
+ if (agsizechanged) {
if ((rc = diExtendFS(ipimap, ipbmap)))
goto error_out;
return NULL;
}
-const struct inode_operations jfs_symlink_inode_operations = {
+const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = jfs_follow_link,
+ .setattr = jfs_setattr,
+ .setxattr = jfs_setxattr,
+ .getxattr = jfs_getxattr,
+ .listxattr = jfs_listxattr,
+ .removexattr = jfs_removexattr,
+};
+
+const struct inode_operations jfs_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
+ .setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
.listxattr = jfs_listxattr,
struct logfs_block *block;
int round, progress, last_progress = 0;
+ /*
+ * Doing too many changes to the segfile at once would result
+ * in a large number of aliases. Write the journal before
+ * things get out of hand.
+ */
+ if (super->s_shadow_tree.no_shadowed_segments >= MAX_OBJ_ALIASES)
+ logfs_write_anchor(sb);
+
if (no_free_segments(sb) >= target &&
super->s_no_object_aliases < MAX_OBJ_ALIASES)
return;
static int journal_erase_segment(struct logfs_area *area)
{
struct super_block *sb = area->a_sb;
- struct logfs_segment_header sh;
+ union {
+ struct logfs_segment_header sh;
+ unsigned char c[ALIGN(sizeof(struct logfs_segment_header), 16)];
+ } u;
u64 ofs;
int err;
if (err)
return err;
- sh.pad = 0;
- sh.type = SEG_JOURNAL;
- sh.level = 0;
- sh.segno = cpu_to_be32(area->a_segno);
- sh.ec = cpu_to_be32(area->a_erase_count);
- sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
- sh.crc = logfs_crc32(&sh, sizeof(sh), 4);
+ memset(&u, 0, sizeof(u));
+ u.sh.pad = 0;
+ u.sh.type = SEG_JOURNAL;
+ u.sh.level = 0;
+ u.sh.segno = cpu_to_be32(area->a_segno);
+ u.sh.ec = cpu_to_be32(area->a_erase_count);
+ u.sh.gec = cpu_to_be64(logfs_super(sb)->s_gec);
+ u.sh.crc = logfs_crc32(&u.sh, sizeof(u.sh), 4);
/* This causes a bug in segment.c. Not yet. */
//logfs_set_segment_erased(sb, area->a_segno, area->a_erase_count, 0);
ofs = dev_ofs(sb, area->a_segno, 0);
- area->a_used_bytes = ALIGN(sizeof(sh), 16);
- logfs_buf_write(area, ofs, &sh, sizeof(sh));
+ area->a_used_bytes = sizeof(u);
+ logfs_buf_write(area, ofs, &u, sizeof(u));
return 0;
}
btree_grim_visitor64(&tree->new, (unsigned long)sb, account_shadow);
btree_grim_visitor64(&tree->old, (unsigned long)sb, account_shadow);
+ btree_grim_visitor32(&tree->segment_map, 0, NULL);
+ tree->no_shadowed_segments = 0;
if (li->li_block) {
/*
if (len == 0)
return logfs_write_header(super, header, 0, type);
+ BUG_ON(len > sb->s_blocksize);
compr_len = logfs_compress(buf, data, len, sb->s_blocksize);
if (compr_len < 0 || type == JE_ANCHOR) {
- BUG_ON(len > sb->s_blocksize);
memcpy(data, buf, len);
compr_len = len;
compr = COMPR_NONE;
if (ofs < 0)
return ofs;
logfs_buf_write(area, ofs, super->s_compressed_je, len);
+ BUG_ON(super->s_no_je >= MAX_JOURNAL_ENTRIES);
super->s_je_array[super->s_no_je++] = cpu_to_be64(ofs);
return 0;
}
* struct shadow_tree
* @new: shadows where old_ofs==0, indexed by new_ofs
* @old: shadows where old_ofs!=0, indexed by old_ofs
+ * @segment_map: bitfield of segments containing shadows
+ * @no_shadowed_segment: number of segments containing shadows
*/
struct shadow_tree {
struct btree_head64 new;
struct btree_head64 old;
+ struct btree_head32 segment_map;
+ int no_shadowed_segments;
};
struct object_alias_item {
level_t level, int child_no, __be64 val);
struct logfs_block_ops {
void (*write_block)(struct logfs_block *block);
- gc_level_t (*block_level)(struct logfs_block *block);
void (*free_block)(struct super_block *sb, struct logfs_block*block);
int (*write_alias)(struct super_block *sb,
struct logfs_block *block,
write_alias_t *write_one_alias);
};
+#define MAX_JOURNAL_ENTRIES 256
+
struct logfs_super {
struct mtd_info *s_mtd; /* underlying device */
struct block_device *s_bdev; /* underlying device */
u32 s_journal_ec[LOGFS_JOURNAL_SEGS]; /* journal erasecounts */
u64 s_last_version;
struct logfs_area *s_journal_area; /* open journal segment */
- __be64 s_je_array[64];
+ __be64 s_je_array[MAX_JOURNAL_ENTRIES];
int s_no_je;
int s_sum_index; /* for the 12 summaries */
return logfs_super(sb)->s_area[(__force u8)gc_level];
}
+static inline void logfs_mempool_destroy(mempool_t *pool)
+{
+ if (pool)
+ mempool_destroy(pool);
+}
+
#endif
}
}
-static gc_level_t inode_block_level(struct logfs_block *block)
-{
- BUG_ON(block->inode->i_ino == LOGFS_INO_MASTER);
- return GC_LEVEL(LOGFS_MAX_LEVELS);
-}
-
-static gc_level_t indirect_block_level(struct logfs_block *block)
-{
- struct page *page;
- struct inode *inode;
- u64 bix;
- level_t level;
-
- page = block->page;
- inode = page->mapping->host;
- logfs_unpack_index(page->index, &bix, &level);
- return expand_level(inode->i_ino, level);
-}
-
/*
* This silences a false, yet annoying gcc warning. I hate it when my editor
* jumps into bitops.h each time I recompile this file.
static struct logfs_block_ops inode_block_ops = {
.write_block = inode_write_block,
- .block_level = inode_block_level,
.free_block = inode_free_block,
.write_alias = inode_write_alias,
};
struct logfs_block_ops indirect_block_ops = {
.write_block = indirect_write_block,
- .block_level = indirect_block_level,
.free_block = indirect_free_block,
.write_alias = indirect_write_alias,
};
mempool_free(shadow, super->s_shadow_pool);
}
+static void mark_segment(struct shadow_tree *tree, u32 segno)
+{
+ int err;
+
+ if (!btree_lookup32(&tree->segment_map, segno)) {
+ err = btree_insert32(&tree->segment_map, segno, (void *)1,
+ GFP_NOFS);
+ BUG_ON(err);
+ tree->no_shadowed_segments++;
+ }
+}
+
/**
* fill_shadow_tree - Propagate shadow tree changes due to a write
* @inode: Inode owning the page
super->s_dirty_used_bytes += shadow->new_len;
super->s_dirty_free_bytes += shadow->old_len;
+ mark_segment(tree, shadow->old_ofs >> super->s_segshift);
+ mark_segment(tree, shadow->new_ofs >> super->s_segshift);
}
}
return logfs_truncate_direct(inode, size);
}
-int logfs_truncate(struct inode *inode, u64 size)
+/*
+ * Truncate, by changing the segment file, can consume a fair amount
+ * of resources. So back off from time to time and do some GC.
+ * 8 or 2048 blocks should be well within safety limits even if
+ * every single block resided in a different segment.
+ */
+#define TRUNCATE_STEP (8 * 1024 * 1024)
+int logfs_truncate(struct inode *inode, u64 target)
{
struct super_block *sb = inode->i_sb;
- int err;
+ u64 size = i_size_read(inode);
+ int err = 0;
- logfs_get_wblocks(sb, NULL, 1);
- err = __logfs_truncate(inode, size);
- if (!err)
- err = __logfs_write_inode(inode, 0);
- logfs_put_wblocks(sb, NULL, 1);
+ size = ALIGN(size, TRUNCATE_STEP);
+ while (size > target) {
+ if (size > TRUNCATE_STEP)
+ size -= TRUNCATE_STEP;
+ else
+ size = 0;
+ if (size < target)
+ size = target;
+
+ logfs_get_wblocks(sb, NULL, 1);
+ err = __logfs_truncate(inode, target);
+ if (!err)
+ err = __logfs_write_inode(inode, 0);
+ logfs_put_wblocks(sb, NULL, 1);
+ }
if (!err)
- err = vmtruncate(inode, size);
+ err = vmtruncate(inode, target);
/* I don't trust error recovery yet. */
WARN_ON(err);
struct logfs_super *super = logfs_super(sb);
destroy_meta_inode(super->s_segfile_inode);
- if (super->s_block_pool)
- mempool_destroy(super->s_block_pool);
- if (super->s_shadow_pool)
- mempool_destroy(super->s_shadow_pool);
+ logfs_mempool_destroy(super->s_block_pool);
+ logfs_mempool_destroy(super->s_shadow_pool);
}
return 0;
}
-static gc_level_t btree_block_level(struct logfs_block *block)
-{
- return expand_level(block->ino, block->level);
-}
-
static struct logfs_block_ops btree_block_ops = {
.write_block = btree_write_block,
- .block_level = btree_block_level,
.free_block = __free_block,
.write_alias = btree_write_alias,
};
for (i--; i >= 0; i--)
free_area(super->s_area[i]);
free_area(super->s_journal_area);
- mempool_destroy(super->s_alias_pool);
+ logfs_mempool_destroy(super->s_alias_pool);
return -ENOMEM;
}
#include "logfs.h"
#include <linux/bio.h>
#include <linux/slab.h>
+#include <linux/blkdev.h>
#include <linux/mtd/mtd.h>
#include <linux/statfs.h>
#include <linux/buffer_head.h>
sb->s_fs_info = super;
sb->s_mtd = super->s_mtd;
sb->s_bdev = super->s_bdev;
+ if (sb->s_bdev)
+ sb->s_bdi = &bdev_get_queue(sb->s_bdev)->backing_dev_info;
+ if (sb->s_mtd)
+ sb->s_bdi = sb->s_mtd->backing_dev_info;
return 0;
}
btree_init_mempool64(&super->s_shadow_tree.new, super->s_btree_pool);
btree_init_mempool64(&super->s_shadow_tree.old, super->s_btree_pool);
+ btree_init_mempool32(&super->s_shadow_tree.segment_map,
+ super->s_btree_pool);
ret = logfs_init_mapping(sb);
if (ret)
if (super->s_erase_page)
__free_page(super->s_erase_page);
super->s_devops->put_device(sb);
- mempool_destroy(super->s_btree_pool);
- mempool_destroy(super->s_alias_pool);
+ logfs_mempool_destroy(super->s_btree_pool);
+ logfs_mempool_destroy(super->s_alias_pool);
kfree(super);
log_super("LogFS: Finished unmounting\n");
}
/* Initialise the client representation from the mount data */
server->flags = data->flags;
- server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR;
+ server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR|
+ NFS_CAP_POSIX_LOCK;
server->options = data->options;
/* Get a client record */
res = NULL;
goto out;
/* This turned out not to be a regular file */
+ case -EISDIR:
case -ENOTDIR:
goto no_open;
case -ELOOP:
if (!(nd->intent.open.flags & O_NOFOLLOW))
goto no_open;
- /* case -EISDIR: */
/* case -EINVAL: */
default:
goto out;
list_for_each_entry(pos, &nfsi->open_files, list) {
if (cred != NULL && pos->cred != cred)
continue;
- if ((pos->mode & mode) == mode) {
- ctx = get_nfs_open_context(pos);
- break;
- }
+ if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode)
+ continue;
+ ctx = get_nfs_open_context(pos);
+ break;
}
spin_unlock(&inode->i_lock);
return ctx;
nfs_post_op_update_inode(dir, o_res->dir_attr);
} else
nfs_refresh_inode(dir, o_res->dir_attr);
+ if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
+ server->caps &= ~NFS_CAP_POSIX_LOCK;
if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
status = _nfs4_proc_open_confirm(data);
if (status != 0)
status = PTR_ERR(state);
if (IS_ERR(state))
goto err_opendata_put;
- if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0)
+ if (server->caps & NFS_CAP_POSIX_LOCK)
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
nfs4_opendata_put(opendata);
nfs4_put_state_owner(sp);
struct inode *inode = page->mapping->host;
struct nfs_server *nfss = NFS_SERVER(inode);
+ page_cache_get(page);
if (atomic_long_inc_return(&nfss->writeback) >
NFS_CONGESTION_ON_THRESH) {
set_bdi_congested(&nfss->backing_dev_info,
struct nfs_server *nfss = NFS_SERVER(inode);
end_page_writeback(page);
+ page_cache_release(page);
if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH)
clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC);
}
nfs_mark_request_dirty(struct nfs_page *req)
{
__set_page_dirty_nobuffers(req->wb_page);
+ __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
req = nfs_setup_write_request(ctx, page, offset, count);
if (IS_ERR(req))
return PTR_ERR(req);
+ nfs_mark_request_dirty(req);
/* Update file length */
nfs_grow_file(page, offset, count);
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
+ nfs_mark_request_dirty(req);
nfs_clear_page_tag_locked(req);
return 0;
}
status = nfs_writepage_setup(ctx, page, offset, count);
if (status < 0)
nfs_set_pageerror(page);
- else
- __set_page_dirty_nobuffers(page);
dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n",
status, (long long)i_size_read(inode));
static void nfs_writepage_release(struct nfs_page *req)
{
+ struct page *page = req->wb_page;
- if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
- nfs_end_page_writeback(req->wb_page);
+ if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req))
nfs_inode_remove_request(req);
- } else
- nfs_end_page_writeback(req->wb_page);
nfs_clear_page_tag_locked(req);
+ nfs_end_page_writeback(page);
}
static int flush_task_priority(int how)
int how)
{
struct inode *inode = req->wb_context->path.dentry->d_inode;
- int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
int priority = flush_task_priority(how);
struct rpc_task *task;
struct rpc_message msg = {
.callback_ops = call_ops,
.callback_data = data,
.workqueue = nfsiod_workqueue,
- .flags = flags,
+ .flags = RPC_TASK_ASYNC,
.priority = priority,
};
+ int ret = 0;
/* Set up the RPC argument and reply structs
* NB: take care not to mess about with data->commit et al. */
(unsigned long long)data->args.offset);
task = rpc_run_task(&task_setup_data);
- if (IS_ERR(task))
- return PTR_ERR(task);
+ if (IS_ERR(task)) {
+ ret = PTR_ERR(task);
+ goto out;
+ }
+ if (how & FLUSH_SYNC) {
+ ret = rpc_wait_for_completion_task(task);
+ if (ret == 0)
+ ret = task->tk_status;
+ }
rpc_put_task(task);
- return 0;
+out:
+ return ret;
}
/* If a nfs_flush_* function fails, it should remove reqs from @head and
*/
static void nfs_redirty_request(struct nfs_page *req)
{
+ struct page *page = req->wb_page;
+
nfs_mark_request_dirty(req);
- nfs_end_page_writeback(req->wb_page);
nfs_clear_page_tag_locked(req);
+ nfs_end_page_writeback(page);
}
/*
if (nfs_write_need_commit(data)) {
memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
nfs_mark_request_commit(req);
- nfs_end_page_writeback(page);
dprintk(" marked for commit\n");
goto next;
}
dprintk(" OK\n");
remove_request:
- nfs_end_page_writeback(page);
nfs_inode_remove_request(req);
next:
nfs_clear_page_tag_locked(req);
+ nfs_end_page_writeback(page);
}
nfs_writedata_release(calldata);
}
{
struct nfs_page *first = nfs_list_entry(head->next);
struct inode *inode = first->wb_context->path.dentry->d_inode;
- int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
int priority = flush_task_priority(how);
struct rpc_task *task;
struct rpc_message msg = {
.callback_ops = &nfs_commit_ops,
.callback_data = data,
.workqueue = nfsiod_workqueue,
- .flags = flags,
+ .flags = RPC_TASK_ASYNC,
.priority = priority,
};
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return PTR_ERR(task);
+ if (how & FLUSH_SYNC)
+ rpc_wait_for_completion_task(task);
rpc_put_task(task);
return 0;
}
Note that this behavior is currently deprecated and may go away in
future. Please use notification via netlink socket instead.
+config QUOTA_DEBUG
+ bool "Additional quota sanity checks"
+ depends on QUOTA
+ default n
+ help
+ If you say Y here, quota subsystem will perform some additional
+ sanity checks of quota internal structures. If unsure, say N.
+
# Generic support for tree structured quota files. Selected when needed.
config QUOTA_TREE
tristate
#include <asm/uaccess.h>
-#define __DQUOT_PARANOIA
-
/*
* There are three quota SMP locks. dq_list_lock protects all lists with quotas
* and quota formats, dqstats structure containing statistics about the lists
if (!dquot)
return;
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
if (!atomic_read(&dquot->dq_count)) {
printk("VFS: dqput: trying to free free dquot\n");
printk("VFS: device %s, dquot of %s %d\n",
goto we_slept;
}
atomic_dec(&dquot->dq_count);
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
/* sanity check */
BUG_ON(!list_empty(&dquot->dq_free));
#endif
dquot = NULL;
goto out;
}
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */
#endif
out:
static void add_dquot_ref(struct super_block *sb, int type)
{
struct inode *inode, *old_inode = NULL;
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
int reserved = 0;
#endif
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW))
continue;
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
if (unlikely(inode_get_rsv_space(inode) > 0))
reserved = 1;
#endif
spin_unlock(&inode_lock);
iput(old_inode);
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
if (reserved) {
printk(KERN_WARNING "VFS (%s): Writes happened before quota"
" was turned on thus quota information is probably "
inode->i_dquot[type] = NULL;
if (dquot) {
if (dqput_blocks(dquot)) {
-#ifdef __DQUOT_PARANOIA
+#ifdef CONFIG_QUOTA_DEBUG
if (atomic_read(&dquot->dq_count) != 1)
printk(KERN_WARNING "VFS: Adding dquot with dq_count %d to dispose list.\n", atomic_read(&dquot->dq_count));
#endif
* call into reclaim to find it in a clean state instead of waiting for
* it now. We also don't return errors here - if the error is transient
* then the next reclaim pass will flush the inode, and if the error
- * is permanent then the next sync reclaim will relcaim the inode and
+ * is permanent then the next sync reclaim will reclaim the inode and
* pass on the error.
*/
- if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+ if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
xfs_fs_cmn_err(CE_WARN, ip->i_mount,
"inode 0x%llx background reclaim flush failed with %d",
(long long)ip->i_ino, error);
/*
* Determine if we have a transaction that has gone to disk
- * that needs to be covered. Log activity needs to be idle (no AIL and
- * nothing in the iclogs). And, we need to be in the right state indicating
- * something has gone out.
+ * that needs to be covered. To begin the transition to the idle state
+ * firstly the log needs to be idle (no AIL and nothing in the iclogs).
+ * If we are then in a state where covering is needed, the caller is informed
+ * that dummy transactions are required to move the log into the idle state.
+ *
+ * Because this is called as part of the sync process, we should also indicate
+ * that dummy transactions should be issued in anything but the covered or
+ * idle states. This ensures that the log tail is accurately reflected in
+ * the log at the end of the sync, hence if a crash occurrs avoids replay
+ * of transactions where the metadata is already on disk.
*/
int
xfs_log_need_covered(xfs_mount_t *mp)
return 0;
spin_lock(&log->l_icloglock);
- if (((log->l_covered_state == XLOG_STATE_COVER_NEED) ||
- (log->l_covered_state == XLOG_STATE_COVER_NEED2))
- && !xfs_trans_ail_tail(log->l_ailp)
- && xlog_iclogs_empty(log)) {
- if (log->l_covered_state == XLOG_STATE_COVER_NEED)
- log->l_covered_state = XLOG_STATE_COVER_DONE;
- else {
- ASSERT(log->l_covered_state == XLOG_STATE_COVER_NEED2);
- log->l_covered_state = XLOG_STATE_COVER_DONE2;
+ switch (log->l_covered_state) {
+ case XLOG_STATE_COVER_DONE:
+ case XLOG_STATE_COVER_DONE2:
+ case XLOG_STATE_COVER_IDLE:
+ break;
+ case XLOG_STATE_COVER_NEED:
+ case XLOG_STATE_COVER_NEED2:
+ if (!xfs_trans_ail_tail(log->l_ailp) &&
+ xlog_iclogs_empty(log)) {
+ if (log->l_covered_state == XLOG_STATE_COVER_NEED)
+ log->l_covered_state = XLOG_STATE_COVER_DONE;
+ else
+ log->l_covered_state = XLOG_STATE_COVER_DONE2;
}
+ /* FALLTHRU */
+ default:
needed = 1;
+ break;
}
spin_unlock(&log->l_icloglock);
return needed;
{0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
/*
* Char device interface.
*
- * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.net>
- *
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*/
#ifndef _LINUX_FIREWIRE_CDEV_H
* @type: %FW_CDEV_ISO_CONTEXT_TRANSMIT or %FW_CDEV_ISO_CONTEXT_RECEIVE
* @header_size: Header size to strip for receive contexts
* @channel: Channel to bind to
- * @speed: Speed to transmit at
+ * @speed: Speed for transmit contexts
* @closure: To be returned in &fw_cdev_event_iso_interrupt
* @handle: Handle to context, written back by kernel
*
* If a context was successfully created, the kernel writes back a handle to the
* context, which must be passed in for subsequent operations on that context.
*
+ * For receive contexts, @header_size must be at least 4 and must be a multiple
+ * of 4.
+ *
* Note that the effect of a @header_size > 4 depends on
* &fw_cdev_get_info.version, as documented at &fw_cdev_event_iso_interrupt.
*/
*
* &struct fw_cdev_iso_packet is used to describe isochronous packet queues.
*
- * Use the FW_CDEV_ISO_ macros to fill in @control. The sy and tag fields are
- * specified by IEEE 1394a and IEC 61883.
- *
- * FIXME - finish this documentation
+ * Use the FW_CDEV_ISO_ macros to fill in @control.
+ *
+ * For transmit packets, the header length must be a multiple of 4 and specifies
+ * the numbers of bytes in @header that will be prepended to the packet's
+ * payload; these bytes are copied into the kernel and will not be accessed
+ * after the ioctl has returned. The sy and tag fields are copied to the iso
+ * packet header (these fields are specified by IEEE 1394a and IEC 61883-1).
+ * The skip flag specifies that no packet is to be sent in a frame; when using
+ * this, all other fields except the interrupt flag must be zero.
+ *
+ * For receive packets, the header length must be a multiple of the context's
+ * header size; if the header length is larger than the context's header size,
+ * multiple packets are queued for this entry. The sy and tag fields are
+ * ignored. If the sync flag is set, the context drops all packets until
+ * a packet with a matching sy field is received (the sync value to wait for is
+ * specified in the &fw_cdev_start_iso structure). The payload length defines
+ * how many payload bytes can be received for one packet (in addition to payload
+ * quadlets that have been defined as headers and are stripped and returned in
+ * the &fw_cdev_event_iso_interrupt structure). If more bytes are received, the
+ * additional bytes are dropped. If less bytes are received, the remaining
+ * bytes in this part of the payload buffer will not be written to, not even by
+ * the next packet, i.e., packets received in consecutive frames will not
+ * necessarily be consecutive in memory. If an entry has queued multiple
+ * packets, the payload length is divided equally among them.
+ *
+ * When a packet with the interrupt flag set has been completed, the
+ * &fw_cdev_event_iso_interrupt event will be sent. An entry that has queued
+ * multiple receive packets is completed when its last packet is completed.
*/
struct fw_cdev_iso_packet {
__u32 control;
* Queue a number of isochronous packets for reception or transmission.
* This ioctl takes a pointer to an array of &fw_cdev_iso_packet structs,
* which describe how to transmit from or receive into a contiguous region
- * of a mmap()'ed payload buffer. As part of the packet descriptors,
+ * of a mmap()'ed payload buffer. As part of transmit packet descriptors,
* a series of headers can be supplied, which will be prepended to the
* payload during DMA.
*
* instead of allocated.
* An %FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED event concludes this operation.
*
- * To summarize, %FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE allocates iso resources
- * for the lifetime of the fd or handle.
+ * To summarize, %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE allocates iso resources
+ * for the lifetime of the fd or @handle.
* In contrast, %FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE allocates iso resources
* for the duration of a bus generation.
*
+/*
+ * IEEE 1394 constants.
+ *
+ * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
#ifndef _LINUX_FIREWIRE_CONSTANTS_H
#define _LINUX_FIREWIRE_CONSTANTS_H
#define EXTCODE_WRAP_ADD 0x6
#define EXTCODE_VENDOR_DEPENDENT 0x7
-/* Juju specific tcodes */
+/* Linux firewire-core (Juju) specific tcodes */
#define TCODE_LOCK_MASK_SWAP (0x10 | EXTCODE_MASK_SWAP)
#define TCODE_LOCK_COMPARE_SWAP (0x10 | EXTCODE_COMPARE_SWAP)
#define TCODE_LOCK_FETCH_ADD (0x10 | EXTCODE_FETCH_ADD)
#define RCODE_TYPE_ERROR 0x6
#define RCODE_ADDRESS_ERROR 0x7
-/* Juju specific rcodes */
+/* Linux firewire-core (Juju) specific rcodes */
#define RCODE_SEND_ERROR 0x10
#define RCODE_CANCELLED 0x11
#define RCODE_BUSY 0x12
extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
unsigned long arg);
extern int __generic_block_fiemap(struct inode *inode,
- struct fiemap_extent_info *fieinfo, u64 start,
- u64 len, get_block_t *get_block);
+ struct fiemap_extent_info *fieinfo,
+ loff_t start, loff_t len,
+ get_block_t *get_block);
extern int generic_block_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo, u64 start,
u64 len, get_block_t *get_block);
* @active_low: gpio polarity
* @wakeup: controls whether the device should be set up as wakeup
* source
+ * @no_autorepeat: disable key autorepeat
*
* This structure represents platform-specific data that use used by
* matrix_keypad driver to perform proper initialization.
bool active_low;
bool wakeup;
+ bool no_autorepeat;
};
/**
*/
struct kvm_io_bus {
int dev_count;
-#define NR_IOBUS_DEVS 6
+#define NR_IOBUS_DEVS 200
struct kvm_io_device *devs[NR_IOBUS_DEVS];
};
int user_alloc;
};
+static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memslot)
+{
+ return ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+}
+
struct kvm_kernel_irq_routing_entry {
u32 gsi;
u32 type;
#define NFS_CAP_ATIME (1U << 11)
#define NFS_CAP_CTIME (1U << 12)
#define NFS_CAP_MTIME (1U << 13)
+#define NFS_CAP_POSIX_LOCK (1U << 14)
/* maximum number of slots to use */
# define rcu_read_release_sched() \
lock_release(&rcu_sched_lock_map, 1, _THIS_IP_)
-static inline int debug_lockdep_rcu_enabled(void)
-{
- return likely(rcu_scheduler_active && debug_locks);
-}
+extern int debug_lockdep_rcu_enabled(void);
/**
* rcu_read_lock_held - might we be in RCU read-side critical section?
/**
* rcu_dereference_check - rcu_dereference with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * Do an rcu_dereference(), but check that the conditions under which the
+ * dereference will take place are correct. Typically the conditions indicate
+ * the various locking conditions that should be held at that point. The check
+ * should return true if the conditions are satisfied.
+ *
+ * For example:
+ *
+ * bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
+ * lockdep_is_held(&foo->lock));
*
- * Do an rcu_dereference(), but check that the context is correct.
- * For example, rcu_dereference_check(gp, rcu_read_lock_held()) to
- * ensure that the rcu_dereference_check() executes within an RCU
- * read-side critical section. It is also possible to check for
- * locks being held, for example, by using lockdep_is_held().
+ * could be used to indicate to lockdep that foo->bar may only be dereferenced
+ * if either the RCU read lock is held, or that the lock required to replace
+ * the bar struct at foo->bar is held.
+ *
+ * Note that the list of conditions may also include indications of when a lock
+ * need not be held, for example during initialisation or destruction of the
+ * target struct:
+ *
+ * bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
+ * lockdep_is_held(&foo->lock) ||
+ * atomic_read(&foo->usage) == 0);
*/
#define rcu_dereference_check(p, c) \
({ \
rcu_dereference_raw(p); \
})
+/**
+ * rcu_dereference_protected - fetch RCU pointer when updates prevented
+ *
+ * Return the value of the specified RCU-protected pointer, but omit
+ * both the smp_read_barrier_depends() and the ACCESS_ONCE(). This
+ * is useful in cases where update-side locks prevent the value of the
+ * pointer from changing. Please note that this primitive does -not-
+ * prevent the compiler from repeating this reference or combining it
+ * with other references, so it should not be used without protection
+ * of appropriate locks.
+ */
+#define rcu_dereference_protected(p, c) \
+ ({ \
+ if (debug_lockdep_rcu_enabled() && !(c)) \
+ lockdep_rcu_dereference(__FILE__, __LINE__); \
+ (p); \
+ })
+
#else /* #ifdef CONFIG_PROVE_RCU */
#define rcu_dereference_check(p, c) rcu_dereference_raw(p)
+#define rcu_dereference_protected(p, c) (p)
#endif /* #else #ifdef CONFIG_PROVE_RCU */
+/**
+ * rcu_access_pointer - fetch RCU pointer with no dereferencing
+ *
+ * Return the value of the specified RCU-protected pointer, but omit the
+ * smp_read_barrier_depends() and keep the ACCESS_ONCE(). This is useful
+ * when the value of this pointer is accessed, but the pointer is not
+ * dereferenced, for example, when testing an RCU-protected pointer against
+ * NULL. This may also be used in cases where update-side locks prevent
+ * the value of the pointer from changing, but rcu_dereference_protected()
+ * is a lighter-weight primitive for this use case.
+ */
+#define rcu_access_pointer(p) ACCESS_ONCE(p)
+
/**
* rcu_read_lock - mark the beginning of an RCU read-side critical section.
*
{
/* Nothing except the stubbed out regulator API should be
* looking at the value except to check if it is an error
- * value so the actual return value doesn't matter.
+ * value. Drivers are free to handle NULL specifically by
+ * skipping all regulator API calls, but they don't have to.
+ * Drivers which don't, should make sure they properly handle
+ * corner cases of the API, such as regulator_get_voltage()
+ * returning 0.
*/
- return (struct regulator *)id;
+ return NULL;
}
static inline void regulator_put(struct regulator *regulator)
{
extern int sysctl_x25_ack_holdback_timeout;
extern int sysctl_x25_forward;
+extern int x25_parse_address_block(struct sk_buff *skb,
+ struct x25_address *called_addr,
+ struct x25_address *calling_addr);
+
extern int x25_addr_ntoa(unsigned char *, struct x25_address *,
struct x25_address *);
extern int x25_addr_aton(unsigned char *, struct x25_address *,
error:
put_cred(new);
+ return NULL;
+
free_tgcred:
#ifdef CONFIG_KEYS
kfree(tgcred);
{
if (cred->magic != CRED_MAGIC)
return true;
- if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
- return true;
#ifdef CONFIG_SECURITY_SELINUX
if (selinux_is_enabled()) {
if ((unsigned long) cred->security < PAGE_SIZE)
* User space encodes device types as two-byte values,
* so we need to recode them
*/
- swdev = old_decode_dev(swap_area.dev);
+ swdev = new_decode_dev(swap_area.dev);
if (swdev) {
offset = swap_area.offset;
data->swap = swap_type_of(swdev, offset, NULL);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
+int debug_lockdep_rcu_enabled(void)
+{
+ return rcu_scheduler_active && debug_locks &&
+ current->lockdep_recursion == 0;
+}
+EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
+
/**
* rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section?
*
config DEBUG_KMEMLEAK
bool "Kernel memory leak detector"
depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
- (X86 || ARM || PPC || S390 || SUPERH || MICROBLAZE)
+ (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE)
select DEBUG_FS if SYSFS
select STACKTRACE if STACKTRACE_SUPPORT
* Now parse out the first token and use it as the name for the
* driver to filter for.
*/
- for (i = 0; i < NAME_MAX_LEN; ++i) {
+ for (i = 0; i < NAME_MAX_LEN - 1; ++i) {
current_driver_name[i] = buf[i];
if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
break;
};
struct printf_spec {
- u16 type;
- s16 field_width; /* width of output field */
+ u8 type; /* format_type enum */
u8 flags; /* flags to number() */
- u8 base;
- s8 precision; /* # of digits/chars */
- u8 qualifier;
+ u8 base; /* number base, 8, 10 or 16 only */
+ u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */
+ s16 field_width; /* width of output field */
+ s16 precision; /* # of digits/chars */
};
static char *number(char *buf, char *end, unsigned long long num,
* @page: the page to add the mapping to
* @vma: the vm area in which the mapping is added
* @address: the user virtual address mapped
+ * @exclusive: the page is exclusively owned by the current process
*/
static void __page_set_anon_rmap(struct page *page,
- struct vm_area_struct *vma, unsigned long address)
+ struct vm_area_struct *vma, unsigned long address, int exclusive)
{
- struct anon_vma_chain *avc;
- struct anon_vma *anon_vma;
+ struct anon_vma *anon_vma = vma->anon_vma;
- BUG_ON(!vma->anon_vma);
+ BUG_ON(!anon_vma);
/*
- * We must use the _oldest_ possible anon_vma for the page mapping!
+ * If the page isn't exclusively mapped into this vma,
+ * we must use the _oldest_ possible anon_vma for the
+ * page mapping!
*
- * So take the last AVC chain entry in the vma, which is the deepest
- * ancestor, and use the anon_vma from that.
+ * So take the last AVC chain entry in the vma, which is
+ * the deepest ancestor, and use the anon_vma from that.
*/
- avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
- anon_vma = avc->anon_vma;
+ if (!exclusive) {
+ struct anon_vma_chain *avc;
+ avc = list_entry(vma->anon_vma_chain.prev, struct anon_vma_chain, same_vma);
+ anon_vma = avc->anon_vma;
+ }
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
page->mapping = (struct address_space *) anon_vma;
VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
if (first)
- __page_set_anon_rmap(page, vma, address);
+ __page_set_anon_rmap(page, vma, address, 0);
else
__page_check_anon_rmap(page, vma, address);
}
SetPageSwapBacked(page);
atomic_set(&page->_mapcount, 0); /* increment count (starts at -1) */
__inc_zone_page_state(page, NR_ANON_PAGES);
- __page_set_anon_rmap(page, vma, address);
+ __page_set_anon_rmap(page, vma, address, 1);
if (page_evictable(page, vma))
lru_cache_add_lru(page, LRU_ACTIVE_ANON);
else
if (!pskb_may_pull(skb, len))
return -EINVAL;
- grec = (void *)(skb->data + len);
+ grec = (void *)(skb->data + len - sizeof(*grec));
group = grec->grec_mca;
type = grec->grec_type;
return -EFAULT;
}
} else if (count == 1) {
- if (copy_from_user(&sfilter, optval, optlen))
+ if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
}
if (dev->real_num_tx_queues > 1)
queue_index = skb_tx_hash(dev, skb);
- if (sk && sk->sk_dst_cache)
- sk_tx_queue_set(sk, queue_index);
+ if (sk) {
+ struct dst_entry *dst = rcu_dereference(sk->sk_dst_cache);
+
+ if (dst && skb_dst(skb) == dst)
+ sk_tx_queue_set(sk, queue_index);
+ }
}
}
{
struct node *ret = tnode_get_child(tn, i);
- return rcu_dereference(ret);
+ return rcu_dereference_check(ret,
+ rcu_read_lock_held() ||
+ lockdep_rtnl_is_held());
}
static inline int tnode_child_length(const struct tnode *tn)
newskb->pkt_type = PACKET_LOOPBACK;
newskb->ip_summed = CHECKSUM_UNNECESSARY;
WARN_ON(!skb_dst(newskb));
- netif_rx(newskb);
+ netif_rx_ni(newskb);
return 0;
}
if (hslot->count < hslot2->count)
goto begin;
- result = udp4_lib_lookup2(net, INADDR_ANY, sport,
- daddr, hnum, dif,
+ result = udp4_lib_lookup2(net, saddr, sport,
+ INADDR_ANY, hnum, dif,
hslot2, slot2);
}
rcu_read_unlock();
newskb->ip_summed = CHECKSUM_UNNECESSARY;
WARN_ON(!skb_dst(newskb));
- netif_rx(newskb);
+ netif_rx_ni(newskb);
return 0;
}
if (hslot->count < hslot2->count)
goto begin;
- result = udp6_lib_lookup2(net, &in6addr_any, sport,
- daddr, hnum, dif,
+ result = udp6_lib_lookup2(net, saddr, sport,
+ &in6addr_any, hnum, dif,
hslot2, slot2);
}
rcu_read_unlock();
switch (sdata->vif.type) {
case NL80211_IFTYPE_AP:
sdata->vif.bss_conf.enable_beacon =
- !!rcu_dereference(sdata->u.ap.beacon);
+ !!sdata->u.ap.beacon;
break;
case NL80211_IFTYPE_ADHOC:
sdata->vif.bss_conf.enable_beacon =
- !!rcu_dereference(sdata->u.ibss.presp);
+ !!sdata->u.ibss.presp;
break;
case NL80211_IFTYPE_MESH_POINT:
sdata->vif.bss_conf.enable_beacon = true;
switch (fc & IEEE80211_FCTL_STYPE) {
case IEEE80211_STYPE_ACTION:
- if (skb->len < IEEE80211_MIN_ACTION_SIZE)
- return RX_DROP_MONITOR;
- /* fall through */
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
skb_queue_tail(&ifmsh->skb_queue, skb);
goto handled;
}
break;
+ case MESH_PLINK_CATEGORY:
+ case MESH_PATH_SEL_CATEGORY:
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
+ break;
}
/*
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
+ sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+ rcu_read_lock_held() ||
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
while (sta) {
if (sta->sdata == sdata &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
- sta = rcu_dereference(sta->hnext);
+ sta = rcu_dereference_check(sta->hnext,
+ rcu_read_lock_held() ||
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
}
return sta;
}
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
- sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
+ sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
+ rcu_read_lock_held() ||
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
while (sta) {
if ((sta->sdata == sdata ||
sta->sdata->bss == sdata->bss) &&
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
break;
- sta = rcu_dereference(sta->hnext);
+ sta = rcu_dereference_check(sta->hnext,
+ rcu_read_lock_held() ||
+ lockdep_is_held(&local->sta_lock) ||
+ lockdep_is_held(&local->sta_mtx));
}
return sta;
}
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCSIFFLAGS:
- if (!net_eq(sock_net(sk), &init_net))
- return -ENOIOCTLCMD;
return inet_dgram_ops.ioctl(sock, cmd, arg);
#endif
};
#endif
+
+int x25_parse_address_block(struct sk_buff *skb,
+ struct x25_address *called_addr,
+ struct x25_address *calling_addr)
+{
+ unsigned char len;
+ int needed;
+ int rc;
+
+ if (skb->len < 1) {
+ /* packet has no address block */
+ rc = 0;
+ goto empty;
+ }
+
+ len = *skb->data;
+ needed = 1 + (len >> 4) + (len & 0x0f);
+
+ if (skb->len < needed) {
+ /* packet is too short to hold the addresses it claims
+ to hold */
+ rc = -1;
+ goto empty;
+ }
+
+ return x25_addr_ntoa(skb->data, called_addr, calling_addr);
+
+empty:
+ *called_addr->x25_addr = 0;
+ *calling_addr->x25_addr = 0;
+
+ return rc;
+}
+
+
int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
struct x25_address *calling_addr)
{
x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
x25->facilities.pacsize_in = X25_DEFAULT_PACKET_SIZE;
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
- x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
+ x25->facilities.throughput = 0; /* by default don't negotiate
+ throughput */
x25->facilities.reverse = X25_DEFAULT_REVERSE;
x25->dte_facilities.calling_len = 0;
x25->dte_facilities.called_len = 0;
/*
* Extract the X.25 addresses and convert them to ASCII strings,
* and remove them.
+ *
+ * Address block is mandatory in call request packets
*/
- addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+ addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr);
+ if (addr_len <= 0)
+ goto out_clear_request;
skb_pull(skb, addr_len);
/*
* Get the length of the facilities, skip past them for the moment
* get the call user data because this is needed to determine
* the correct listener
+ *
+ * Facilities length is mandatory in call request packets
*/
+ if (skb->len < 1)
+ goto out_clear_request;
len = skb->data[0] + 1;
+ if (skb->len < len)
+ goto out_clear_request;
skb_pull(skb,len);
/*
if (facilities.winsize_in < 1 ||
facilities.winsize_in > 127)
break;
- if (facilities.throughput < 0x03 ||
- facilities.throughput > 0xDD)
- break;
+ if (facilities.throughput) {
+ int out = facilities.throughput & 0xf0;
+ int in = facilities.throughput & 0x0f;
+ if (!out)
+ facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT << 4;
+ else if (out < 0x30 || out > 0xD0)
+ break;
+ if (!in)
+ facilities.throughput |=
+ X25_DEFAULT_THROUGHPUT;
+ else if (in < 0x03 || in > 0x0D)
+ break;
+ }
if (facilities.reverse &&
(facilities.reverse & 0x81) != 0x81)
break;
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
{
unsigned char *p = skb->data;
- unsigned int len = *p++;
+ unsigned int len;
*vc_fac_mask = 0;
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
+ if (skb->len < 1)
+ return 0;
+
+ len = *p++;
+
+ if (len >= skb->len)
+ return -1;
+
while (len > 0) {
switch (*p & X25_FAC_CLASS_MASK) {
case X25_FAC_CLASS_A:
memcpy(new, ours, sizeof(*new));
len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
+ if (len < 0)
+ return len;
/*
* They want reverse charging, we won't accept it.
new->reverse = theirs.reverse;
if (theirs.throughput) {
- if (theirs.throughput < ours->throughput) {
- SOCK_DEBUG(sk, "X.25: throughput negotiated down\n");
- new->throughput = theirs.throughput;
+ int theirs_in = theirs.throughput & 0x0f;
+ int theirs_out = theirs.throughput & 0xf0;
+ int ours_in = ours->throughput & 0x0f;
+ int ours_out = ours->throughput & 0xf0;
+ if (!ours_in || theirs_in < ours_in) {
+ SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n");
+ new->throughput = (new->throughput & 0xf0) | theirs_in;
+ }
+ if (!ours_out || theirs_out < ours_out) {
+ SOCK_DEBUG(sk,
+ "X.25: outbound throughput negotiated\n");
+ new->throughput = (new->throughput & 0x0f) | theirs_out;
}
}
static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
struct x25_address source_addr, dest_addr;
+ int len;
switch (frametype) {
case X25_CALL_ACCEPTED: {
* Parse the data in the frame.
*/
skb_pull(skb, X25_STD_MIN_LEN);
- skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
- skb_pull(skb,
- x25_parse_facilities(skb, &x25->facilities,
+
+ len = x25_parse_address_block(skb, &source_addr,
+ &dest_addr);
+ if (len > 0)
+ skb_pull(skb, len);
+
+ len = x25_parse_facilities(skb, &x25->facilities,
&x25->dte_facilities,
- &x25->vc_facil_mask));
+ &x25->vc_facil_mask);
+ if (len > 0)
+ skb_pull(skb, len);
/*
* Copy any Call User Data.
*/
mutex_lock(&parent->d_inode->i_mutex);
*dentry = lookup_one_len(name, parent, strlen(name));
- if (!IS_ERR(dentry)) {
+ if (!IS_ERR(*dentry)) {
if ((mode & S_IFMT) == S_IFDIR)
error = mkdir(parent->d_inode, *dentry, mode);
else
error = create(parent->d_inode, *dentry, mode);
} else
- error = PTR_ERR(dentry);
+ error = PTR_ERR(*dentry);
mutex_unlock(&parent->d_inode->i_mutex);
return error;
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define MAX_AVTAB_HASH_BITS 13
+#define MAX_AVTAB_HASH_BITS 11
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
#define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
struct mm_struct *mm)
{
struct kvm *kvm = mmu_notifier_to_kvm(mn);
+ int idx;
+
+ idx = srcu_read_lock(&kvm->srcu);
kvm_arch_flush_shadow(kvm);
+ srcu_read_unlock(&kvm->srcu, idx);
}
static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
/* Allocate page dirty bitmap if needed */
if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
- unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;
+ unsigned long dirty_bytes = kvm_dirty_bitmap_bytes(&new);
new.dirty_bitmap = vmalloc(dirty_bytes);
if (!new.dirty_bitmap)
{
struct kvm_memory_slot *memslot;
int r, i;
- int n;
+ unsigned long n;
unsigned long any = 0;
r = -EINVAL;
if (!memslot->dirty_bitmap)
goto out;
- n = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+ n = kvm_dirty_bitmap_bytes(memslot);
for (i = 0; !any && i < n/sizeof(long); ++i)
any = memslot->dirty_bitmap[i];
memslot = gfn_to_memslot_unaliased(kvm, gfn);
if (memslot && memslot->dirty_bitmap) {
unsigned long rel_gfn = gfn - memslot->base_gfn;
+ unsigned long *p = memslot->dirty_bitmap +
+ rel_gfn / BITS_PER_LONG;
+ int offset = rel_gfn % BITS_PER_LONG;
/* avoid RMW */
- if (!generic_test_le_bit(rel_gfn, memslot->dirty_bitmap))
- generic___set_le_bit(rel_gfn, memslot->dirty_bitmap);
+ if (!generic_test_le_bit(offset, p))
+ generic___set_le_bit(offset, p);
}
}