Merge branch 'akpm' (Andrew's incoming - part two)
Says Andrew: "60 patches. That's good enough for -rc1 I guess. I have quite a lot of detritus to be rechecked, work through maintainers, etc. - most of the remains of MM - rtc - various misc - cgroups - memcg - cpusets - procfs - ipc - rapidio - sysctl - pps - w1 - drivers/misc - aio" * akpm: (60 commits) memcg: replace ss->id_lock with a rwlock aio: allocate kiocbs in batches drivers/misc/vmw_balloon.c: fix typo in code comment drivers/misc/vmw_balloon.c: determine page allocation flag can_sleep outside loop w1: disable irqs in critical section drivers/w1/w1_int.c: multiple masters used same init_name drivers/power/ds2780_battery.c: fix deadlock upon insertion and removal drivers/power/ds2780_battery.c: add a nolock function to w1 interface drivers/power/ds2780_battery.c: create central point for calling w1 interface w1: ds2760 and ds2780, use ida for id and ida_simple_get() to get it pps gpio client: add missing dependency pps: new client driver using GPIO pps: default echo function include/linux/dma-mapping.h: add dma_zalloc_coherent() sysctl: make CONFIG_SYSCTL_SYSCALL default to n sysctl: add support for poll() RapidIO: documentation update drivers/net/rionet.c: fix ethernet address macros for LE platforms RapidIO: fix potential null deref in rio_setup_device() RapidIO: add mport driver for Tsi721 bridge ...
This commit is contained in:
commit
092f4c56c1
70 changed files with 4915 additions and 1041 deletions
|
@ -50,6 +50,13 @@ specify the GFP_ flags (see kmalloc) for the allocation (the
|
|||
implementation may choose to ignore flags that affect the location of
|
||||
the returned memory, like GFP_DMA).
|
||||
|
||||
void *
|
||||
dma_zalloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
|
||||
Wraps dma_alloc_coherent() and also zeroes the returned memory if the
|
||||
allocation attempt succeeded.
|
||||
|
||||
void
|
||||
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_handle)
|
||||
|
|
|
@ -418,7 +418,6 @@ total_unevictable - sum of all children's "unevictable"
|
|||
|
||||
# The following additional stats are dependent on CONFIG_DEBUG_VM.
|
||||
|
||||
inactive_ratio - VM internal parameter. (see mm/page_alloc.c)
|
||||
recent_rotated_anon - VM internal parameter. (see mm/vmscan.c)
|
||||
recent_rotated_file - VM internal parameter. (see mm/vmscan.c)
|
||||
recent_scanned_anon - VM internal parameter. (see mm/vmscan.c)
|
||||
|
|
|
@ -133,41 +133,6 @@ Who: Pavel Machek <pavel@ucw.cz>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: sys_sysctl
|
||||
When: September 2010
|
||||
Option: CONFIG_SYSCTL_SYSCALL
|
||||
Why: The same information is available in a more convenient from
|
||||
/proc/sys, and none of the sysctl variables appear to be
|
||||
important performance wise.
|
||||
|
||||
Binary sysctls are a long standing source of subtle kernel
|
||||
bugs and security issues.
|
||||
|
||||
When I looked several months ago all I could find after
|
||||
searching several distributions were 5 user space programs and
|
||||
glibc (which falls back to /proc/sys) using this syscall.
|
||||
|
||||
The man page for sysctl(2) documents it as unusable for user
|
||||
space programs.
|
||||
|
||||
sysctl(2) is not generally ABI compatible to a 32bit user
|
||||
space application on a 64bit and a 32bit kernel.
|
||||
|
||||
For the last several months the policy has been no new binary
|
||||
sysctls and no one has put forward an argument to use them.
|
||||
|
||||
Binary sysctls issues seem to keep happening appearing so
|
||||
properly deprecating them (with a warning to user space) and a
|
||||
2 year grace warning period will mean eventually we can kill
|
||||
them and end the pain.
|
||||
|
||||
In the mean time individual binary sysctls can be dealt with
|
||||
in a piecewise fashion.
|
||||
|
||||
Who: Eric Biederman <ebiederm@xmission.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: /proc/<pid>/oom_adj
|
||||
When: August 2012
|
||||
Why: /proc/<pid>/oom_adj allows userspace to influence the oom killer's
|
||||
|
|
|
@ -144,7 +144,7 @@ and the default device ID in order to access the device on the active port.
|
|||
|
||||
After the host has completed enumeration of the entire network it releases
|
||||
devices by clearing device ID locks (calls rio_clear_locks()). For each endpoint
|
||||
in the system, it sets the Master Enable bit in the Port General Control CSR
|
||||
in the system, it sets the Discovered bit in the Port General Control CSR
|
||||
to indicate that enumeration is completed and agents are allowed to execute
|
||||
passive discovery of the network.
|
||||
|
||||
|
|
49
Documentation/rapidio/tsi721.txt
Normal file
49
Documentation/rapidio/tsi721.txt
Normal file
|
@ -0,0 +1,49 @@
|
|||
RapidIO subsystem mport driver for IDT Tsi721 PCI Express-to-SRIO bridge.
|
||||
=========================================================================
|
||||
|
||||
I. Overview
|
||||
|
||||
This driver implements all currently defined RapidIO mport callback functions.
|
||||
It supports maintenance read and write operations, inbound and outbound RapidIO
|
||||
doorbells, inbound maintenance port-writes and RapidIO messaging.
|
||||
|
||||
To generate SRIO maintenance transactions this driver uses one of Tsi721 DMA
|
||||
channels. This mechanism provides access to larger range of hop counts and
|
||||
destination IDs without need for changes in outbound window translation.
|
||||
|
||||
RapidIO messaging support uses dedicated messaging channels for each mailbox.
|
||||
For inbound messages this driver uses destination ID matching to forward messages
|
||||
into the corresponding message queue. Messaging callbacks are implemented to be
|
||||
fully compatible with RIONET driver (Ethernet over RapidIO messaging services).
|
||||
|
||||
II. Known problems
|
||||
|
||||
None.
|
||||
|
||||
III. To do
|
||||
|
||||
Add DMA data transfers (non-messaging).
|
||||
Add inbound region (SRIO-to-PCIe) mapping.
|
||||
|
||||
IV. Version History
|
||||
|
||||
1.0.0 - Initial driver release.
|
||||
|
||||
V. License
|
||||
-----------------------------------------------
|
||||
|
||||
Copyright(c) 2011 Integrated Device Technology, Inc. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License 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.
|
|
@ -16,16 +16,6 @@
|
|||
|
||||
#ifdef __HAVE_ARCH_PTE_SPECIAL
|
||||
|
||||
static inline void get_huge_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* __split_huge_page_refcount() cannot run
|
||||
* from under us.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) < 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
/*
|
||||
* The performance critical leaf functions are made noinline otherwise gcc
|
||||
* inlines everything into a single function which results in too much
|
||||
|
@ -57,8 +47,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
|||
put_page(page);
|
||||
return 0;
|
||||
}
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
|||
{
|
||||
unsigned long mask;
|
||||
unsigned long pte_end;
|
||||
struct page *head, *page;
|
||||
struct page *head, *page, *tail;
|
||||
pte_t pte;
|
||||
int refs;
|
||||
|
||||
|
@ -413,6 +413,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
|||
head = pte_page(pte);
|
||||
|
||||
page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
|
@ -428,10 +429,20 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add
|
|||
|
||||
if (unlikely(pte_val(pte) != pte_val(*ptep))) {
|
||||
/* Could be optimized better */
|
||||
while (*nr) {
|
||||
put_page(page);
|
||||
(*nr)--;
|
||||
}
|
||||
*nr -= refs;
|
||||
while (refs--)
|
||||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -1608,6 +1608,7 @@ int fsl_rio_setup(struct platform_device *dev)
|
|||
return 0;
|
||||
err:
|
||||
iounmap(priv->regs_win);
|
||||
release_resource(&port->iores);
|
||||
err_res:
|
||||
kfree(priv);
|
||||
err_priv:
|
||||
|
|
|
@ -52,7 +52,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask, result;
|
||||
struct page *head, *page;
|
||||
struct page *head, *page, *tail;
|
||||
int refs;
|
||||
|
||||
result = write ? 0 : _SEGMENT_ENTRY_RO;
|
||||
|
@ -64,6 +64,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
refs = 0;
|
||||
head = pmd_page(pmd);
|
||||
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
|
@ -81,6 +82,17 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
*nr -= refs;
|
||||
while (refs--)
|
||||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -56,6 +56,8 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
|||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
if (head != page)
|
||||
get_huge_page_tail(page);
|
||||
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
|
|
@ -108,16 +108,6 @@ static inline void get_head_page_multiple(struct page *page, int nr)
|
|||
SetPageReferenced(page);
|
||||
}
|
||||
|
||||
static inline void get_huge_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* __split_huge_page_refcount() cannot run
|
||||
* from under us.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) < 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
|
|
|
@ -151,7 +151,7 @@ MODULE_LICENSE("GPL");
|
|||
struct vmballoon_stats {
|
||||
unsigned int timer;
|
||||
|
||||
/* allocation statustics */
|
||||
/* allocation statistics */
|
||||
unsigned int alloc;
|
||||
unsigned int alloc_fail;
|
||||
unsigned int sleep_alloc;
|
||||
|
@ -412,6 +412,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
|
|||
gfp_t flags;
|
||||
unsigned int hv_status;
|
||||
bool locked = false;
|
||||
flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP;
|
||||
|
||||
do {
|
||||
if (!can_sleep)
|
||||
|
@ -419,7 +420,6 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
|
|||
else
|
||||
STATS_INC(b->stats.sleep_alloc);
|
||||
|
||||
flags = can_sleep ? VMW_PAGE_ALLOC_CANSLEEP : VMW_PAGE_ALLOC_NOSLEEP;
|
||||
page = alloc_page(flags);
|
||||
if (!page) {
|
||||
if (!can_sleep)
|
||||
|
|
|
@ -88,8 +88,8 @@ static struct rio_dev **rionet_active;
|
|||
#define dev_rionet_capable(dev) \
|
||||
is_rionet_capable(dev->src_ops, dev->dst_ops)
|
||||
|
||||
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
|
||||
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
|
||||
#define RIONET_MAC_MATCH(x) (!memcmp((x), "\00\01\00\01", 4))
|
||||
#define RIONET_GET_DESTID(x) ((*((u8 *)x + 4) << 8) | *((u8 *)x + 5))
|
||||
|
||||
static int rionet_rx_clean(struct net_device *ndev)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@ struct ds2780_device_info {
|
|||
struct device *dev;
|
||||
struct power_supply bat;
|
||||
struct device *w1_dev;
|
||||
struct task_struct *mutex_holder;
|
||||
};
|
||||
|
||||
enum current_types {
|
||||
|
@ -49,8 +50,8 @@ enum current_types {
|
|||
static const char model[] = "DS2780";
|
||||
static const char manufacturer[] = "Maxim/Dallas";
|
||||
|
||||
static inline struct ds2780_device_info *to_ds2780_device_info(
|
||||
struct power_supply *psy)
|
||||
static inline struct ds2780_device_info *
|
||||
to_ds2780_device_info(struct power_supply *psy)
|
||||
{
|
||||
return container_of(psy, struct ds2780_device_info, bat);
|
||||
}
|
||||
|
@ -60,17 +61,28 @@ static inline struct power_supply *to_power_supply(struct device *dev)
|
|||
return dev_get_drvdata(dev);
|
||||
}
|
||||
|
||||
static inline int ds2780_read8(struct device *dev, u8 *val, int addr)
|
||||
static inline int ds2780_battery_io(struct ds2780_device_info *dev_info,
|
||||
char *buf, int addr, size_t count, int io)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, sizeof(u8), 0);
|
||||
if (dev_info->mutex_holder == current)
|
||||
return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io);
|
||||
else
|
||||
return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io);
|
||||
}
|
||||
|
||||
static int ds2780_read16(struct device *dev, s16 *val, int addr)
|
||||
static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val,
|
||||
int addr)
|
||||
{
|
||||
return ds2780_battery_io(dev_info, val, addr, sizeof(u8), 0);
|
||||
}
|
||||
|
||||
static int ds2780_read16(struct ds2780_device_info *dev_info, s16 *val,
|
||||
int addr)
|
||||
{
|
||||
int ret;
|
||||
u8 raw[2];
|
||||
|
||||
ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0);
|
||||
ret = ds2780_battery_io(dev_info, raw, addr, sizeof(raw), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -79,16 +91,16 @@ static int ds2780_read16(struct device *dev, s16 *val, int addr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int ds2780_read_block(struct device *dev, u8 *val, int addr,
|
||||
size_t count)
|
||||
static inline int ds2780_read_block(struct ds2780_device_info *dev_info,
|
||||
u8 *val, int addr, size_t count)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, count, 0);
|
||||
return ds2780_battery_io(dev_info, val, addr, count, 0);
|
||||
}
|
||||
|
||||
static inline int ds2780_write(struct device *dev, u8 *val, int addr,
|
||||
size_t count)
|
||||
static inline int ds2780_write(struct ds2780_device_info *dev_info, u8 *val,
|
||||
int addr, size_t count)
|
||||
{
|
||||
return w1_ds2780_io(dev, val, addr, count, 1);
|
||||
return ds2780_battery_io(dev_info, val, addr, count, 1);
|
||||
}
|
||||
|
||||
static inline int ds2780_store_eeprom(struct device *dev, int addr)
|
||||
|
@ -122,7 +134,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &conductance,
|
||||
ret = ds2780_write(dev_info, &conductance,
|
||||
DS2780_RSNSP_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -134,7 +146,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
|
|||
static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info,
|
||||
u16 *rsgain)
|
||||
{
|
||||
return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG);
|
||||
return ds2780_read16(dev_info, rsgain, DS2780_RSGAIN_MSB_REG);
|
||||
}
|
||||
|
||||
/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
|
||||
|
@ -144,8 +156,8 @@ static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info,
|
|||
int ret;
|
||||
u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, raw,
|
||||
DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2);
|
||||
ret = ds2780_write(dev_info, raw,
|
||||
DS2780_RSGAIN_MSB_REG, sizeof(raw));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -167,7 +179,7 @@ static int ds2780_get_voltage(struct ds2780_device_info *dev_info,
|
|||
* Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
|
||||
* voltage LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &voltage_raw,
|
||||
ret = ds2780_read16(dev_info, &voltage_raw,
|
||||
DS2780_VOLT_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -196,7 +208,7 @@ static int ds2780_get_temperature(struct ds2780_device_info *dev_info,
|
|||
* Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
|
||||
* temperature LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &temperature_raw,
|
||||
ret = ds2780_read16(dev_info, &temperature_raw,
|
||||
DS2780_TEMP_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -222,13 +234,13 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info,
|
|||
* The units of measurement for current are dependent on the value of
|
||||
* the sense resistor.
|
||||
*/
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (sense_res_raw == 0) {
|
||||
dev_err(dev_info->dev, "sense resistor value is 0\n");
|
||||
return -ENXIO;
|
||||
return -EINVAL;
|
||||
}
|
||||
sense_res = 1000 / sense_res_raw;
|
||||
|
||||
|
@ -248,7 +260,7 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info,
|
|||
* Bits 7 - 0 of the current value are in bits 7 - 0 of the current
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, reg_msb);
|
||||
ret = ds2780_read16(dev_info, ¤t_raw, reg_msb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -267,7 +279,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
|
|||
* The units of measurement for accumulated current are dependent on
|
||||
* the value of the sense resistor.
|
||||
*/
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -285,7 +297,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
|
|||
* Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, DS2780_ACR_MSB_REG);
|
||||
ret = ds2780_read16(dev_info, ¤t_raw, DS2780_ACR_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -299,7 +311,7 @@ static int ds2780_get_capacity(struct ds2780_device_info *dev_info,
|
|||
int ret;
|
||||
u8 raw;
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG);
|
||||
ret = ds2780_read8(dev_info, &raw, DS2780_RARC_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -345,7 +357,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
|
|||
* Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
|
||||
* LSB register
|
||||
*/
|
||||
ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG);
|
||||
ret = ds2780_read16(dev_info, &charge_raw, DS2780_RAAC_MSB_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -356,7 +368,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
|
|||
static int ds2780_get_control_register(struct ds2780_device_info *dev_info,
|
||||
u8 *control_reg)
|
||||
{
|
||||
return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG);
|
||||
return ds2780_read8(dev_info, control_reg, DS2780_CONTROL_REG);
|
||||
}
|
||||
|
||||
static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
|
||||
|
@ -364,7 +376,7 @@ static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &control_reg,
|
||||
ret = ds2780_write(dev_info, &control_reg,
|
||||
DS2780_CONTROL_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -503,7 +515,7 @@ static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
|
|||
struct power_supply *psy = to_power_supply(dev);
|
||||
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG);
|
||||
ret = ds2780_read8(dev_info, &sense_resistor, DS2780_RSNSP_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -584,7 +596,7 @@ static ssize_t ds2780_get_pio_pin(struct device *dev,
|
|||
struct power_supply *psy = to_power_supply(dev);
|
||||
struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
|
||||
|
||||
ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG);
|
||||
ret = ds2780_read8(dev_info, &sfr, DS2780_SFR_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -611,7 +623,7 @@ static ssize_t ds2780_set_pio_pin(struct device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, &new_setting,
|
||||
ret = ds2780_write(dev_info, &new_setting,
|
||||
DS2780_SFR_REG, sizeof(u8));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -632,7 +644,7 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
|
|||
DS2780_EEPROM_BLOCK1_END -
|
||||
DS2780_EEPROM_BLOCK1_START + 1 - off);
|
||||
|
||||
return ds2780_read_block(dev_info->w1_dev, buf,
|
||||
return ds2780_read_block(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK1_START + off, count);
|
||||
}
|
||||
|
||||
|
@ -650,7 +662,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
|
|||
DS2780_EEPROM_BLOCK1_END -
|
||||
DS2780_EEPROM_BLOCK1_START + 1 - off);
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, buf,
|
||||
ret = ds2780_write(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK1_START + off, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -685,9 +697,8 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
|
|||
DS2780_EEPROM_BLOCK0_END -
|
||||
DS2780_EEPROM_BLOCK0_START + 1 - off);
|
||||
|
||||
return ds2780_read_block(dev_info->w1_dev, buf,
|
||||
return ds2780_read_block(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK0_START + off, count);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
||||
|
@ -704,7 +715,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
|||
DS2780_EEPROM_BLOCK0_END -
|
||||
DS2780_EEPROM_BLOCK0_START + 1 - off);
|
||||
|
||||
ret = ds2780_write(dev_info->w1_dev, buf,
|
||||
ret = ds2780_write(dev_info, buf,
|
||||
DS2780_EEPROM_BLOCK0_START + off, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -768,6 +779,7 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
|||
dev_info->bat.properties = ds2780_battery_props;
|
||||
dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props);
|
||||
dev_info->bat.get_property = ds2780_battery_get_property;
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
ret = power_supply_register(&pdev->dev, &dev_info->bat);
|
||||
if (ret) {
|
||||
|
@ -797,6 +809,8 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev)
|
|||
goto fail_remove_bin_file;
|
||||
}
|
||||
|
||||
dev_info->mutex_holder = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_remove_bin_file:
|
||||
|
@ -816,6 +830,8 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
|
||||
|
||||
dev_info->mutex_holder = current;
|
||||
|
||||
/* remove attributes */
|
||||
sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
|
||||
|
||||
|
|
|
@ -29,4 +29,13 @@ config PPS_CLIENT_PARPORT
|
|||
If you say yes here you get support for a PPS source connected
|
||||
with the interrupt pin of your parallel port.
|
||||
|
||||
config PPS_CLIENT_GPIO
|
||||
tristate "PPS client using GPIO"
|
||||
depends on PPS && GENERIC_HARDIRQS
|
||||
help
|
||||
If you say yes here you get support for a PPS source using
|
||||
GPIO. To be useful you must also register a platform device
|
||||
specifying the GPIO pin and other options, usually in your board
|
||||
setup.
|
||||
|
||||
endif
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
|
||||
obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
|
||||
obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
|
||||
obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o
|
||||
|
||||
ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
|
||||
|
|
227
drivers/pps/clients/pps-gpio.c
Normal file
227
drivers/pps/clients/pps-gpio.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* pps-gpio.c -- PPS client driver using GPIO
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
|
||||
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#define PPS_GPIO_NAME "pps-gpio"
|
||||
#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pps_kernel.h>
|
||||
#include <linux/pps-gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/* Info for each registered platform device */
|
||||
struct pps_gpio_device_data {
|
||||
int irq; /* IRQ used as PPS source */
|
||||
struct pps_device *pps; /* PPS source device */
|
||||
struct pps_source_info info; /* PPS source information */
|
||||
const struct pps_gpio_platform_data *pdata;
|
||||
};
|
||||
|
||||
/*
|
||||
* Report the PPS event
|
||||
*/
|
||||
|
||||
static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
|
||||
{
|
||||
const struct pps_gpio_device_data *info;
|
||||
struct pps_event_time ts;
|
||||
int rising_edge;
|
||||
|
||||
/* Get the time stamp first */
|
||||
pps_get_ts(&ts);
|
||||
|
||||
info = data;
|
||||
|
||||
rising_edge = gpio_get_value(info->pdata->gpio_pin);
|
||||
if ((rising_edge && !info->pdata->assert_falling_edge) ||
|
||||
(!rising_edge && info->pdata->assert_falling_edge))
|
||||
pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
|
||||
else if (info->pdata->capture_clear &&
|
||||
((rising_edge && info->pdata->assert_falling_edge) ||
|
||||
(!rising_edge && !info->pdata->assert_falling_edge)))
|
||||
pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pps_gpio_setup(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
|
||||
if (ret) {
|
||||
pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = gpio_direction_input(pdata->gpio_pin);
|
||||
if (ret) {
|
||||
pr_warning("failed to set pin direction\n");
|
||||
gpio_free(pdata->gpio_pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
|
||||
{
|
||||
unsigned long flags = pdata->assert_falling_edge ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
|
||||
if (pdata->capture_clear) {
|
||||
flags |= ((flags & IRQF_TRIGGER_RISING) ?
|
||||
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int pps_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pps_gpio_device_data *data;
|
||||
int irq;
|
||||
int ret;
|
||||
int err;
|
||||
int pps_default_params;
|
||||
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
|
||||
/* GPIO setup */
|
||||
ret = pps_gpio_setup(pdev);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
/* IRQ setup */
|
||||
irq = gpio_to_irq(pdata->gpio_pin);
|
||||
if (irq < 0) {
|
||||
pr_err("failed to map GPIO to IRQ: %d\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* allocate space for device info */
|
||||
data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
|
||||
if (data == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
/* initialize PPS specific parts of the bookkeeping data structure. */
|
||||
data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
|
||||
PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
|
||||
if (pdata->capture_clear)
|
||||
data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
|
||||
PPS_ECHOCLEAR;
|
||||
data->info.owner = THIS_MODULE;
|
||||
snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
|
||||
pdev->name, pdev->id);
|
||||
|
||||
/* register PPS source */
|
||||
pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
|
||||
if (pdata->capture_clear)
|
||||
pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
|
||||
data->pps = pps_register_source(&data->info, pps_default_params);
|
||||
if (data->pps == NULL) {
|
||||
kfree(data);
|
||||
pr_err("failed to register IRQ %d as PPS source\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
data->irq = irq;
|
||||
data->pdata = pdata;
|
||||
|
||||
/* register IRQ interrupt handler */
|
||||
ret = request_irq(irq, pps_gpio_irq_handler,
|
||||
get_irqf_trigger_flags(pdata), data->info.name, data);
|
||||
if (ret) {
|
||||
pps_unregister_source(data->pps);
|
||||
kfree(data);
|
||||
pr_err("failed to acquire IRQ %d\n", irq);
|
||||
err = -EINVAL;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
|
||||
|
||||
return 0;
|
||||
|
||||
return_error:
|
||||
gpio_free(pdata->gpio_pin);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pps_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
|
||||
const struct pps_gpio_platform_data *pdata = data->pdata;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
free_irq(data->irq, data);
|
||||
gpio_free(pdata->gpio_pin);
|
||||
pps_unregister_source(data->pps);
|
||||
pr_info("removed IRQ %d as PPS source\n", data->irq);
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pps_gpio_driver = {
|
||||
.probe = pps_gpio_probe,
|
||||
.remove = __devexit_p(pps_gpio_remove),
|
||||
.driver = {
|
||||
.name = PPS_GPIO_NAME,
|
||||
.owner = THIS_MODULE
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pps_gpio_init(void)
|
||||
{
|
||||
int ret = platform_driver_register(&pps_gpio_driver);
|
||||
if (ret < 0)
|
||||
pr_err("failed to register platform driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit pps_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pps_gpio_driver);
|
||||
pr_debug("unregistered platform driver\n");
|
||||
}
|
||||
|
||||
module_init(pps_gpio_init);
|
||||
module_exit(pps_gpio_exit);
|
||||
|
||||
MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
|
||||
MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
|
||||
MODULE_DESCRIPTION("Use GPIO pin as PPS source");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("1.0.0");
|
|
@ -51,17 +51,6 @@ static void pps_ktimer_event(unsigned long ptr)
|
|||
mod_timer(&ktimer, jiffies + HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* The echo function
|
||||
*/
|
||||
|
||||
static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* The PPS info struct
|
||||
*/
|
||||
|
@ -72,7 +61,6 @@ static struct pps_source_info pps_ktimer_info = {
|
|||
.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
|
||||
PPS_ECHOASSERT |
|
||||
PPS_CANWAIT | PPS_TSFMT_TSPEC,
|
||||
.echo = pps_ktimer_echo,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -133,14 +133,6 @@ static void parport_irq(void *handle)
|
|||
return;
|
||||
}
|
||||
|
||||
/* the PPS echo function */
|
||||
static void pps_echo(struct pps_device *pps, int event, void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
static void parport_attach(struct parport *port)
|
||||
{
|
||||
struct pps_client_pp *device;
|
||||
|
@ -151,7 +143,6 @@ static void parport_attach(struct parport *port)
|
|||
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
|
||||
PPS_ECHOASSERT | PPS_ECHOCLEAR | \
|
||||
PPS_CANWAIT | PPS_TSFMT_TSPEC,
|
||||
.echo = pps_echo,
|
||||
.owner = THIS_MODULE,
|
||||
.dev = NULL
|
||||
};
|
||||
|
|
|
@ -52,6 +52,14 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
|
|||
ts->sec += offset->sec;
|
||||
}
|
||||
|
||||
static void pps_echo_client_default(struct pps_device *pps, int event,
|
||||
void *data)
|
||||
{
|
||||
dev_info(pps->dev, "echo %s %s\n",
|
||||
event & PPS_CAPTUREASSERT ? "assert" : "",
|
||||
event & PPS_CAPTURECLEAR ? "clear" : "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Exported functions
|
||||
*/
|
||||
|
@ -80,13 +88,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
|
|||
err = -EINVAL;
|
||||
goto pps_register_source_exit;
|
||||
}
|
||||
if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
|
||||
info->echo == NULL) {
|
||||
pr_err("%s: echo function is not defined\n",
|
||||
info->name);
|
||||
err = -EINVAL;
|
||||
goto pps_register_source_exit;
|
||||
}
|
||||
if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
|
||||
pr_err("%s: unspecified time format\n",
|
||||
info->name);
|
||||
|
@ -108,6 +109,11 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
|
|||
pps->params.mode = default_params;
|
||||
pps->info = *info;
|
||||
|
||||
/* check for default echo function */
|
||||
if ((pps->info.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) &&
|
||||
pps->info.echo == NULL)
|
||||
pps->info.echo = pps_echo_client_default;
|
||||
|
||||
init_waitqueue_head(&pps->queue);
|
||||
spin_lock_init(&pps->lock);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#
|
||||
# RapidIO configuration
|
||||
#
|
||||
source "drivers/rapidio/devices/Kconfig"
|
||||
|
||||
config RAPIDIO_DISC_TIMEOUT
|
||||
int "Discovery timeout duration (seconds)"
|
||||
depends on RAPIDIO
|
||||
|
@ -20,8 +22,6 @@ config RAPIDIO_ENABLE_RX_TX_PORTS
|
|||
ports for Input/Output direction to allow other traffic
|
||||
than Maintenance transfers.
|
||||
|
||||
source "drivers/rapidio/switches/Kconfig"
|
||||
|
||||
config RAPIDIO_DEBUG
|
||||
bool "RapidIO subsystem debug messages"
|
||||
depends on RAPIDIO
|
||||
|
@ -32,3 +32,5 @@ config RAPIDIO_DEBUG
|
|||
going on.
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
source "drivers/rapidio/switches/Kconfig"
|
||||
|
|
|
@ -4,5 +4,6 @@
|
|||
obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
|
||||
|
||||
obj-$(CONFIG_RAPIDIO) += switches/
|
||||
obj-$(CONFIG_RAPIDIO) += devices/
|
||||
|
||||
subdir-ccflags-$(CONFIG_RAPIDIO_DEBUG) := -DDEBUG
|
||||
|
|
10
drivers/rapidio/devices/Kconfig
Normal file
10
drivers/rapidio/devices/Kconfig
Normal file
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# RapidIO master port configuration
|
||||
#
|
||||
|
||||
config RAPIDIO_TSI721
|
||||
bool "IDT Tsi721 PCI Express SRIO Controller support"
|
||||
depends on RAPIDIO && PCIEPORTBUS
|
||||
default "n"
|
||||
---help---
|
||||
Include support for IDT Tsi721 PCI Express Serial RapidIO controller.
|
5
drivers/rapidio/devices/Makefile
Normal file
5
drivers/rapidio/devices/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for RapidIO devices
|
||||
#
|
||||
|
||||
obj-$(CONFIG_RAPIDIO_TSI721) += tsi721.o
|
2360
drivers/rapidio/devices/tsi721.c
Normal file
2360
drivers/rapidio/devices/tsi721.c
Normal file
File diff suppressed because it is too large
Load diff
766
drivers/rapidio/devices/tsi721.h
Normal file
766
drivers/rapidio/devices/tsi721.h
Normal file
|
@ -0,0 +1,766 @@
|
|||
/*
|
||||
* Tsi721 PCIExpress-to-SRIO bridge definitions
|
||||
*
|
||||
* Copyright 2011, Integrated Device Technology, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __TSI721_H
|
||||
#define __TSI721_H
|
||||
|
||||
#define DRV_NAME "tsi721"
|
||||
|
||||
#define DEFAULT_HOPCOUNT 0xff
|
||||
#define DEFAULT_DESTID 0xff
|
||||
|
||||
/* PCI device ID */
|
||||
#define PCI_DEVICE_ID_TSI721 0x80ab
|
||||
|
||||
#define BAR_0 0
|
||||
#define BAR_1 1
|
||||
#define BAR_2 2
|
||||
#define BAR_4 4
|
||||
|
||||
#define TSI721_PC2SR_BARS 2
|
||||
#define TSI721_PC2SR_WINS 8
|
||||
#define TSI721_PC2SR_ZONES 8
|
||||
#define TSI721_MAINT_WIN 0 /* Window for outbound maintenance requests */
|
||||
#define IDB_QUEUE 0 /* Inbound Doorbell Queue to use */
|
||||
#define IDB_QSIZE 512 /* Inbound Doorbell Queue size */
|
||||
|
||||
/* Memory space sizes */
|
||||
#define TSI721_REG_SPACE_SIZE (512 * 1024) /* 512K */
|
||||
#define TSI721_DB_WIN_SIZE (16 * 1024 * 1024) /* 16MB */
|
||||
|
||||
#define RIO_TT_CODE_8 0x00000000
|
||||
#define RIO_TT_CODE_16 0x00000001
|
||||
|
||||
#define TSI721_DMA_MAXCH 8
|
||||
#define TSI721_DMA_MINSTSSZ 32
|
||||
#define TSI721_DMA_STSBLKSZ 8
|
||||
|
||||
#define TSI721_SRIO_MAXCH 8
|
||||
|
||||
#define DBELL_SID(buf) (((u8)buf[2] << 8) | (u8)buf[3])
|
||||
#define DBELL_TID(buf) (((u8)buf[4] << 8) | (u8)buf[5])
|
||||
#define DBELL_INF(buf) (((u8)buf[0] << 8) | (u8)buf[1])
|
||||
|
||||
#define TSI721_RIO_PW_MSG_SIZE 16 /* Tsi721 saves only 16 bytes of PW msg */
|
||||
|
||||
/* Register definitions */
|
||||
|
||||
/*
|
||||
* Registers in PCIe configuration space
|
||||
*/
|
||||
|
||||
#define TSI721_PCIECFG_MSIXTBL 0x0a4
|
||||
#define TSI721_MSIXTBL_OFFSET 0x2c000
|
||||
#define TSI721_PCIECFG_MSIXPBA 0x0a8
|
||||
#define TSI721_MSIXPBA_OFFSET 0x2a000
|
||||
#define TSI721_PCIECFG_EPCTL 0x400
|
||||
|
||||
/*
|
||||
* Event Management Registers
|
||||
*/
|
||||
|
||||
#define TSI721_RIO_EM_INT_STAT 0x10910
|
||||
#define TSI721_RIO_EM_INT_STAT_PW_RX 0x00010000
|
||||
|
||||
#define TSI721_RIO_EM_INT_ENABLE 0x10914
|
||||
#define TSI721_RIO_EM_INT_ENABLE_PW_RX 0x00010000
|
||||
|
||||
#define TSI721_RIO_EM_DEV_INT_EN 0x10930
|
||||
#define TSI721_RIO_EM_DEV_INT_EN_INT 0x00000001
|
||||
|
||||
/*
|
||||
* Port-Write Block Registers
|
||||
*/
|
||||
|
||||
#define TSI721_RIO_PW_CTL 0x10a04
|
||||
#define TSI721_RIO_PW_CTL_PW_TIMER 0xf0000000
|
||||
#define TSI721_RIO_PW_CTL_PWT_DIS (0 << 28)
|
||||
#define TSI721_RIO_PW_CTL_PWT_103 (1 << 28)
|
||||
#define TSI721_RIO_PW_CTL_PWT_205 (1 << 29)
|
||||
#define TSI721_RIO_PW_CTL_PWT_410 (1 << 30)
|
||||
#define TSI721_RIO_PW_CTL_PWT_820 (1 << 31)
|
||||
#define TSI721_RIO_PW_CTL_PWC_MODE 0x01000000
|
||||
#define TSI721_RIO_PW_CTL_PWC_CONT 0x00000000
|
||||
#define TSI721_RIO_PW_CTL_PWC_REL 0x01000000
|
||||
|
||||
#define TSI721_RIO_PW_RX_STAT 0x10a10
|
||||
#define TSI721_RIO_PW_RX_STAT_WR_SIZE 0x0000f000
|
||||
#define TSI_RIO_PW_RX_STAT_WDPTR 0x00000100
|
||||
#define TSI721_RIO_PW_RX_STAT_PW_SHORT 0x00000008
|
||||
#define TSI721_RIO_PW_RX_STAT_PW_TRUNC 0x00000004
|
||||
#define TSI721_RIO_PW_RX_STAT_PW_DISC 0x00000002
|
||||
#define TSI721_RIO_PW_RX_STAT_PW_VAL 0x00000001
|
||||
|
||||
#define TSI721_RIO_PW_RX_CAPT(x) (0x10a20 + (x)*4)
|
||||
|
||||
/*
|
||||
* Inbound Doorbells
|
||||
*/
|
||||
|
||||
#define TSI721_IDB_ENTRY_SIZE 64
|
||||
|
||||
#define TSI721_IDQ_CTL(x) (0x20000 + (x) * 1000)
|
||||
#define TSI721_IDQ_SUSPEND 0x00000002
|
||||
#define TSI721_IDQ_INIT 0x00000001
|
||||
|
||||
#define TSI721_IDQ_STS(x) (0x20004 + (x) * 1000)
|
||||
#define TSI721_IDQ_RUN 0x00200000
|
||||
|
||||
#define TSI721_IDQ_MASK(x) (0x20008 + (x) * 1000)
|
||||
#define TSI721_IDQ_MASK_MASK 0xffff0000
|
||||
#define TSI721_IDQ_MASK_PATT 0x0000ffff
|
||||
|
||||
#define TSI721_IDQ_RP(x) (0x2000c + (x) * 1000)
|
||||
#define TSI721_IDQ_RP_PTR 0x0007ffff
|
||||
|
||||
#define TSI721_IDQ_WP(x) (0x20010 + (x) * 1000)
|
||||
#define TSI721_IDQ_WP_PTR 0x0007ffff
|
||||
|
||||
#define TSI721_IDQ_BASEL(x) (0x20014 + (x) * 1000)
|
||||
#define TSI721_IDQ_BASEL_ADDR 0xffffffc0
|
||||
#define TSI721_IDQ_BASEU(x) (0x20018 + (x) * 1000)
|
||||
#define TSI721_IDQ_SIZE(x) (0x2001c + (x) * 1000)
|
||||
#define TSI721_IDQ_SIZE_VAL(size) (__fls(size) - 4)
|
||||
#define TSI721_IDQ_SIZE_MIN 512
|
||||
#define TSI721_IDQ_SIZE_MAX (512 * 1024)
|
||||
|
||||
#define TSI721_SR_CHINT(x) (0x20040 + (x) * 1000)
|
||||
#define TSI721_SR_CHINTE(x) (0x20044 + (x) * 1000)
|
||||
#define TSI721_SR_CHINTSET(x) (0x20048 + (x) * 1000)
|
||||
#define TSI721_SR_CHINT_ODBOK 0x00000020
|
||||
#define TSI721_SR_CHINT_IDBQRCV 0x00000010
|
||||
#define TSI721_SR_CHINT_SUSP 0x00000008
|
||||
#define TSI721_SR_CHINT_ODBTO 0x00000004
|
||||
#define TSI721_SR_CHINT_ODBRTRY 0x00000002
|
||||
#define TSI721_SR_CHINT_ODBERR 0x00000001
|
||||
#define TSI721_SR_CHINT_ALL 0x0000003f
|
||||
|
||||
#define TSI721_IBWIN_NUM 8
|
||||
|
||||
#define TSI721_IBWINLB(x) (0x29000 + (x) * 20)
|
||||
#define TSI721_IBWINLB_BA 0xfffff000
|
||||
#define TSI721_IBWINLB_WEN 0x00000001
|
||||
|
||||
#define TSI721_SR2PC_GEN_INTE 0x29800
|
||||
#define TSI721_SR2PC_PWE 0x29804
|
||||
#define TSI721_SR2PC_GEN_INT 0x29808
|
||||
|
||||
#define TSI721_DEV_INTE 0x29840
|
||||
#define TSI721_DEV_INT 0x29844
|
||||
#define TSI721_DEV_INTSET 0x29848
|
||||
#define TSI721_DEV_INT_SMSG_CH 0x00000800
|
||||
#define TSI721_DEV_INT_SMSG_NCH 0x00000400
|
||||
#define TSI721_DEV_INT_SR2PC_CH 0x00000200
|
||||
#define TSI721_DEV_INT_SRIO 0x00000020
|
||||
|
||||
#define TSI721_DEV_CHAN_INTE 0x2984c
|
||||
#define TSI721_DEV_CHAN_INT 0x29850
|
||||
|
||||
#define TSI721_INT_SR2PC_CHAN_M 0xff000000
|
||||
#define TSI721_INT_SR2PC_CHAN(x) (1 << (24 + (x)))
|
||||
#define TSI721_INT_IMSG_CHAN_M 0x00ff0000
|
||||
#define TSI721_INT_IMSG_CHAN(x) (1 << (16 + (x)))
|
||||
#define TSI721_INT_OMSG_CHAN_M 0x0000ff00
|
||||
#define TSI721_INT_OMSG_CHAN(x) (1 << (8 + (x)))
|
||||
|
||||
/*
|
||||
* PC2SR block registers
|
||||
*/
|
||||
#define TSI721_OBWIN_NUM TSI721_PC2SR_WINS
|
||||
|
||||
#define TSI721_OBWINLB(x) (0x40000 + (x) * 20)
|
||||
#define TSI721_OBWINLB_BA 0xffff8000
|
||||
#define TSI721_OBWINLB_WEN 0x00000001
|
||||
|
||||
#define TSI721_OBWINUB(x) (0x40004 + (x) * 20)
|
||||
|
||||
#define TSI721_OBWINSZ(x) (0x40008 + (x) * 20)
|
||||
#define TSI721_OBWINSZ_SIZE 0x00001f00
|
||||
#define TSI721_OBWIN_SIZE(size) (__fls(size) - 15)
|
||||
|
||||
#define TSI721_ZONE_SEL 0x41300
|
||||
#define TSI721_ZONE_SEL_RD_WRB 0x00020000
|
||||
#define TSI721_ZONE_SEL_GO 0x00010000
|
||||
#define TSI721_ZONE_SEL_WIN 0x00000038
|
||||
#define TSI721_ZONE_SEL_ZONE 0x00000007
|
||||
|
||||
#define TSI721_LUT_DATA0 0x41304
|
||||
#define TSI721_LUT_DATA0_ADD 0xfffff000
|
||||
#define TSI721_LUT_DATA0_RDTYPE 0x00000f00
|
||||
#define TSI721_LUT_DATA0_NREAD 0x00000100
|
||||
#define TSI721_LUT_DATA0_MNTRD 0x00000200
|
||||
#define TSI721_LUT_DATA0_RDCRF 0x00000020
|
||||
#define TSI721_LUT_DATA0_WRCRF 0x00000010
|
||||
#define TSI721_LUT_DATA0_WRTYPE 0x0000000f
|
||||
#define TSI721_LUT_DATA0_NWR 0x00000001
|
||||
#define TSI721_LUT_DATA0_MNTWR 0x00000002
|
||||
#define TSI721_LUT_DATA0_NWR_R 0x00000004
|
||||
|
||||
#define TSI721_LUT_DATA1 0x41308
|
||||
|
||||
#define TSI721_LUT_DATA2 0x4130c
|
||||
#define TSI721_LUT_DATA2_HC 0xff000000
|
||||
#define TSI721_LUT_DATA2_ADD65 0x000c0000
|
||||
#define TSI721_LUT_DATA2_TT 0x00030000
|
||||
#define TSI721_LUT_DATA2_DSTID 0x0000ffff
|
||||
|
||||
#define TSI721_PC2SR_INTE 0x41310
|
||||
|
||||
#define TSI721_DEVCTL 0x48004
|
||||
#define TSI721_DEVCTL_SRBOOT_CMPL 0x00000004
|
||||
|
||||
#define TSI721_I2C_INT_ENABLE 0x49120
|
||||
|
||||
/*
|
||||
* Block DMA Engine Registers
|
||||
* x = 0..7
|
||||
*/
|
||||
|
||||
#define TSI721_DMAC_DWRCNT(x) (0x51000 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DRDCNT(x) (0x51004 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_DMAC_CTL(x) (0x51008 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_CTL_SUSP 0x00000002
|
||||
#define TSI721_DMAC_CTL_INIT 0x00000001
|
||||
|
||||
#define TSI721_DMAC_INT(x) (0x5100c + (x) * 0x1000)
|
||||
#define TSI721_DMAC_INT_STFULL 0x00000010
|
||||
#define TSI721_DMAC_INT_DONE 0x00000008
|
||||
#define TSI721_DMAC_INT_SUSP 0x00000004
|
||||
#define TSI721_DMAC_INT_ERR 0x00000002
|
||||
#define TSI721_DMAC_INT_IOFDONE 0x00000001
|
||||
#define TSI721_DMAC_INT_ALL 0x0000001f
|
||||
|
||||
#define TSI721_DMAC_INTSET(x) (0x51010 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_DMAC_STS(x) (0x51014 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_STS_ABORT 0x00400000
|
||||
#define TSI721_DMAC_STS_RUN 0x00200000
|
||||
#define TSI721_DMAC_STS_CS 0x001f0000
|
||||
|
||||
#define TSI721_DMAC_INTE(x) (0x51018 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_DMAC_DPTRL(x) (0x51024 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DPTRL_MASK 0xffffffe0
|
||||
|
||||
#define TSI721_DMAC_DPTRH(x) (0x51028 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_DMAC_DSBL(x) (0x5102c + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DSBL_MASK 0xffffffc0
|
||||
|
||||
#define TSI721_DMAC_DSBH(x) (0x51030 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_DMAC_DSSZ(x) (0x51034 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DSSZ_SIZE_M 0x0000000f
|
||||
#define TSI721_DMAC_DSSZ_SIZE(size) (__fls(size) - 4)
|
||||
|
||||
|
||||
#define TSI721_DMAC_DSRP(x) (0x51038 + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DSRP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_DMAC_DSWP(x) (0x5103c + (x) * 0x1000)
|
||||
#define TSI721_DMAC_DSWP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_BDMA_INTE 0x5f000
|
||||
|
||||
/*
|
||||
* Messaging definitions
|
||||
*/
|
||||
#define TSI721_MSG_BUFFER_SIZE RIO_MAX_MSG_SIZE
|
||||
#define TSI721_MSG_MAX_SIZE RIO_MAX_MSG_SIZE
|
||||
#define TSI721_IMSG_MAXCH 8
|
||||
#define TSI721_IMSG_CHNUM TSI721_IMSG_MAXCH
|
||||
#define TSI721_IMSGD_MIN_RING_SIZE 32
|
||||
#define TSI721_IMSGD_RING_SIZE 512
|
||||
|
||||
#define TSI721_OMSG_CHNUM 4 /* One channel per MBOX */
|
||||
#define TSI721_OMSGD_MIN_RING_SIZE 32
|
||||
#define TSI721_OMSGD_RING_SIZE 512
|
||||
|
||||
/*
|
||||
* Outbound Messaging Engine Registers
|
||||
* x = 0..7
|
||||
*/
|
||||
|
||||
#define TSI721_OBDMAC_DWRCNT(x) (0x61000 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_OBDMAC_DRDCNT(x) (0x61004 + (x) * 0x1000)
|
||||
|
||||
#define TSI721_OBDMAC_CTL(x) (0x61008 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_CTL_MASK 0x00000007
|
||||
#define TSI721_OBDMAC_CTL_RETRY_THR 0x00000004
|
||||
#define TSI721_OBDMAC_CTL_SUSPEND 0x00000002
|
||||
#define TSI721_OBDMAC_CTL_INIT 0x00000001
|
||||
|
||||
#define TSI721_OBDMAC_INT(x) (0x6100c + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_INTSET(x) (0x61010 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_INTE(x) (0x61018 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_INT_MASK 0x0000001F
|
||||
#define TSI721_OBDMAC_INT_ST_FULL 0x00000010
|
||||
#define TSI721_OBDMAC_INT_DONE 0x00000008
|
||||
#define TSI721_OBDMAC_INT_SUSPENDED 0x00000004
|
||||
#define TSI721_OBDMAC_INT_ERROR 0x00000002
|
||||
#define TSI721_OBDMAC_INT_IOF_DONE 0x00000001
|
||||
#define TSI721_OBDMAC_INT_ALL TSI721_OBDMAC_INT_MASK
|
||||
|
||||
#define TSI721_OBDMAC_STS(x) (0x61014 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_STS_MASK 0x007f0000
|
||||
#define TSI721_OBDMAC_STS_ABORT 0x00400000
|
||||
#define TSI721_OBDMAC_STS_RUN 0x00200000
|
||||
#define TSI721_OBDMAC_STS_CS 0x001f0000
|
||||
|
||||
#define TSI721_OBDMAC_PWE(x) (0x6101c + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_PWE_MASK 0x00000002
|
||||
#define TSI721_OBDMAC_PWE_ERROR_EN 0x00000002
|
||||
|
||||
#define TSI721_OBDMAC_DPTRL(x) (0x61020 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DPTRL_MASK 0xfffffff0
|
||||
|
||||
#define TSI721_OBDMAC_DPTRH(x) (0x61024 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DPTRH_MASK 0xffffffff
|
||||
|
||||
#define TSI721_OBDMAC_DSBL(x) (0x61040 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DSBL_MASK 0xffffffc0
|
||||
|
||||
#define TSI721_OBDMAC_DSBH(x) (0x61044 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DSBH_MASK 0xffffffff
|
||||
|
||||
#define TSI721_OBDMAC_DSSZ(x) (0x61048 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DSSZ_MASK 0x0000000f
|
||||
|
||||
#define TSI721_OBDMAC_DSRP(x) (0x6104c + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DSRP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_OBDMAC_DSWP(x) (0x61050 + (x) * 0x1000)
|
||||
#define TSI721_OBDMAC_DSWP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_RQRPTO 0x60010
|
||||
#define TSI721_RQRPTO_MASK 0x00ffffff
|
||||
#define TSI721_RQRPTO_VAL 400 /* Response TO value */
|
||||
|
||||
/*
|
||||
* Inbound Messaging Engine Registers
|
||||
* x = 0..7
|
||||
*/
|
||||
|
||||
#define TSI721_IB_DEVID_GLOBAL 0xffff
|
||||
#define TSI721_IBDMAC_FQBL(x) (0x61200 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQBL_MASK 0xffffffc0
|
||||
|
||||
#define TSI721_IBDMAC_FQBH(x) (0x61204 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQBH_MASK 0xffffffff
|
||||
|
||||
#define TSI721_IBDMAC_FQSZ_ENTRY_INX TSI721_IMSGD_RING_SIZE
|
||||
#define TSI721_IBDMAC_FQSZ(x) (0x61208 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQSZ_MASK 0x0000000f
|
||||
|
||||
#define TSI721_IBDMAC_FQRP(x) (0x6120c + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQRP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_IBDMAC_FQWP(x) (0x61210 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQWP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_IBDMAC_FQTH(x) (0x61214 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_FQTH_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_IB_DEVID 0x60020
|
||||
#define TSI721_IB_DEVID_MASK 0x0000ffff
|
||||
|
||||
#define TSI721_IBDMAC_CTL(x) (0x61240 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_CTL_MASK 0x00000003
|
||||
#define TSI721_IBDMAC_CTL_SUSPEND 0x00000002
|
||||
#define TSI721_IBDMAC_CTL_INIT 0x00000001
|
||||
|
||||
#define TSI721_IBDMAC_STS(x) (0x61244 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_STS_MASK 0x007f0000
|
||||
#define TSI721_IBSMAC_STS_ABORT 0x00400000
|
||||
#define TSI721_IBSMAC_STS_RUN 0x00200000
|
||||
#define TSI721_IBSMAC_STS_CS 0x001f0000
|
||||
|
||||
#define TSI721_IBDMAC_INT(x) (0x61248 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_INTSET(x) (0x6124c + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_INTE(x) (0x61250 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_INT_MASK 0x0000100f
|
||||
#define TSI721_IBDMAC_INT_SRTO 0x00001000
|
||||
#define TSI721_IBDMAC_INT_SUSPENDED 0x00000008
|
||||
#define TSI721_IBDMAC_INT_PC_ERROR 0x00000004
|
||||
#define TSI721_IBDMAC_INT_FQ_LOW 0x00000002
|
||||
#define TSI721_IBDMAC_INT_DQ_RCV 0x00000001
|
||||
#define TSI721_IBDMAC_INT_ALL TSI721_IBDMAC_INT_MASK
|
||||
|
||||
#define TSI721_IBDMAC_PWE(x) (0x61254 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_PWE_MASK 0x00001700
|
||||
#define TSI721_IBDMAC_PWE_SRTO 0x00001000
|
||||
#define TSI721_IBDMAC_PWE_ILL_FMT 0x00000400
|
||||
#define TSI721_IBDMAC_PWE_ILL_DEC 0x00000200
|
||||
#define TSI721_IBDMAC_PWE_IMP_SP 0x00000100
|
||||
|
||||
#define TSI721_IBDMAC_DQBL(x) (0x61300 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_DQBL_MASK 0xffffffc0
|
||||
#define TSI721_IBDMAC_DQBL_ADDR 0xffffffc0
|
||||
|
||||
#define TSI721_IBDMAC_DQBH(x) (0x61304 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_DQBH_MASK 0xffffffff
|
||||
|
||||
#define TSI721_IBDMAC_DQRP(x) (0x61308 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_DQRP_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_IBDMAC_DQWR(x) (0x6130c + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_DQWR_MASK 0x0007ffff
|
||||
|
||||
#define TSI721_IBDMAC_DQSZ(x) (0x61314 + (x) * 0x1000)
|
||||
#define TSI721_IBDMAC_DQSZ_MASK 0x0000000f
|
||||
|
||||
/*
|
||||
* Messaging Engine Interrupts
|
||||
*/
|
||||
|
||||
#define TSI721_SMSG_PWE 0x6a004
|
||||
|
||||
#define TSI721_SMSG_INTE 0x6a000
|
||||
#define TSI721_SMSG_INT 0x6a008
|
||||
#define TSI721_SMSG_INTSET 0x6a010
|
||||
#define TSI721_SMSG_INT_MASK 0x0086ffff
|
||||
#define TSI721_SMSG_INT_UNS_RSP 0x00800000
|
||||
#define TSI721_SMSG_INT_ECC_NCOR 0x00040000
|
||||
#define TSI721_SMSG_INT_ECC_COR 0x00020000
|
||||
#define TSI721_SMSG_INT_ECC_NCOR_CH 0x0000ff00
|
||||
#define TSI721_SMSG_INT_ECC_COR_CH 0x000000ff
|
||||
|
||||
#define TSI721_SMSG_ECC_LOG 0x6a014
|
||||
#define TSI721_SMSG_ECC_LOG_MASK 0x00070007
|
||||
#define TSI721_SMSG_ECC_LOG_ECC_NCOR_M 0x00070000
|
||||
#define TSI721_SMSG_ECC_LOG_ECC_COR_M 0x00000007
|
||||
|
||||
#define TSI721_RETRY_GEN_CNT 0x6a100
|
||||
#define TSI721_RETRY_GEN_CNT_MASK 0xffffffff
|
||||
|
||||
#define TSI721_RETRY_RX_CNT 0x6a104
|
||||
#define TSI721_RETRY_RX_CNT_MASK 0xffffffff
|
||||
|
||||
#define TSI721_SMSG_ECC_COR_LOG(x) (0x6a300 + (x) * 4)
|
||||
#define TSI721_SMSG_ECC_COR_LOG_MASK 0x000000ff
|
||||
|
||||
#define TSI721_SMSG_ECC_NCOR(x) (0x6a340 + (x) * 4)
|
||||
#define TSI721_SMSG_ECC_NCOR_MASK 0x000000ff
|
||||
|
||||
/*
|
||||
* Block DMA Descriptors
|
||||
*/
|
||||
|
||||
struct tsi721_dma_desc {
|
||||
__le32 type_id;
|
||||
|
||||
#define TSI721_DMAD_DEVID 0x0000ffff
|
||||
#define TSI721_DMAD_CRF 0x00010000
|
||||
#define TSI721_DMAD_PRIO 0x00060000
|
||||
#define TSI721_DMAD_RTYPE 0x00780000
|
||||
#define TSI721_DMAD_IOF 0x08000000
|
||||
#define TSI721_DMAD_DTYPE 0xe0000000
|
||||
|
||||
__le32 bcount;
|
||||
|
||||
#define TSI721_DMAD_BCOUNT1 0x03ffffff /* if DTYPE == 1 */
|
||||
#define TSI721_DMAD_BCOUNT2 0x0000000f /* if DTYPE == 2 */
|
||||
#define TSI721_DMAD_TT 0x0c000000
|
||||
#define TSI721_DMAD_RADDR0 0xc0000000
|
||||
|
||||
union {
|
||||
__le32 raddr_lo; /* if DTYPE == (1 || 2) */
|
||||
__le32 next_lo; /* if DTYPE == 3 */
|
||||
};
|
||||
|
||||
#define TSI721_DMAD_CFGOFF 0x00ffffff
|
||||
#define TSI721_DMAD_HOPCNT 0xff000000
|
||||
|
||||
union {
|
||||
__le32 raddr_hi; /* if DTYPE == (1 || 2) */
|
||||
__le32 next_hi; /* if DTYPE == 3 */
|
||||
};
|
||||
|
||||
union {
|
||||
struct { /* if DTYPE == 1 */
|
||||
__le32 bufptr_lo;
|
||||
__le32 bufptr_hi;
|
||||
__le32 s_dist;
|
||||
__le32 s_size;
|
||||
} t1;
|
||||
__le32 data[4]; /* if DTYPE == 2 */
|
||||
u32 reserved[4]; /* if DTYPE == 3 */
|
||||
};
|
||||
} __aligned(32);
|
||||
|
||||
/*
|
||||
* Inbound Messaging Descriptor
|
||||
*/
|
||||
struct tsi721_imsg_desc {
|
||||
__le32 type_id;
|
||||
|
||||
#define TSI721_IMD_DEVID 0x0000ffff
|
||||
#define TSI721_IMD_CRF 0x00010000
|
||||
#define TSI721_IMD_PRIO 0x00060000
|
||||
#define TSI721_IMD_TT 0x00180000
|
||||
#define TSI721_IMD_DTYPE 0xe0000000
|
||||
|
||||
__le32 msg_info;
|
||||
|
||||
#define TSI721_IMD_BCOUNT 0x00000ff8
|
||||
#define TSI721_IMD_SSIZE 0x0000f000
|
||||
#define TSI721_IMD_LETER 0x00030000
|
||||
#define TSI721_IMD_XMBOX 0x003c0000
|
||||
#define TSI721_IMD_MBOX 0x00c00000
|
||||
#define TSI721_IMD_CS 0x78000000
|
||||
#define TSI721_IMD_HO 0x80000000
|
||||
|
||||
__le32 bufptr_lo;
|
||||
__le32 bufptr_hi;
|
||||
u32 reserved[12];
|
||||
|
||||
} __aligned(64);
|
||||
|
||||
/*
|
||||
* Outbound Messaging Descriptor
|
||||
*/
|
||||
struct tsi721_omsg_desc {
|
||||
__le32 type_id;
|
||||
|
||||
#define TSI721_OMD_DEVID 0x0000ffff
|
||||
#define TSI721_OMD_CRF 0x00010000
|
||||
#define TSI721_OMD_PRIO 0x00060000
|
||||
#define TSI721_OMD_IOF 0x08000000
|
||||
#define TSI721_OMD_DTYPE 0xe0000000
|
||||
#define TSI721_OMD_RSRVD 0x17f80000
|
||||
|
||||
__le32 msg_info;
|
||||
|
||||
#define TSI721_OMD_BCOUNT 0x00000ff8
|
||||
#define TSI721_OMD_SSIZE 0x0000f000
|
||||
#define TSI721_OMD_LETER 0x00030000
|
||||
#define TSI721_OMD_XMBOX 0x003c0000
|
||||
#define TSI721_OMD_MBOX 0x00c00000
|
||||
#define TSI721_OMD_TT 0x0c000000
|
||||
|
||||
union {
|
||||
__le32 bufptr_lo; /* if DTYPE == 4 */
|
||||
__le32 next_lo; /* if DTYPE == 5 */
|
||||
};
|
||||
|
||||
union {
|
||||
__le32 bufptr_hi; /* if DTYPE == 4 */
|
||||
__le32 next_hi; /* if DTYPE == 5 */
|
||||
};
|
||||
|
||||
} __aligned(16);
|
||||
|
||||
struct tsi721_dma_sts {
|
||||
__le64 desc_sts[8];
|
||||
} __aligned(64);
|
||||
|
||||
struct tsi721_desc_sts_fifo {
|
||||
union {
|
||||
__le64 da64;
|
||||
struct {
|
||||
__le32 lo;
|
||||
__le32 hi;
|
||||
} da32;
|
||||
} stat[8];
|
||||
} __aligned(64);
|
||||
|
||||
/* Descriptor types for BDMA and Messaging blocks */
|
||||
enum dma_dtype {
|
||||
DTYPE1 = 1, /* Data Transfer DMA Descriptor */
|
||||
DTYPE2 = 2, /* Immediate Data Transfer DMA Descriptor */
|
||||
DTYPE3 = 3, /* Block Pointer DMA Descriptor */
|
||||
DTYPE4 = 4, /* Outbound Msg DMA Descriptor */
|
||||
DTYPE5 = 5, /* OB Messaging Block Pointer Descriptor */
|
||||
DTYPE6 = 6 /* Inbound Messaging Descriptor */
|
||||
};
|
||||
|
||||
enum dma_rtype {
|
||||
NREAD = 0,
|
||||
LAST_NWRITE_R = 1,
|
||||
ALL_NWRITE = 2,
|
||||
ALL_NWRITE_R = 3,
|
||||
MAINT_RD = 4,
|
||||
MAINT_WR = 5
|
||||
};
|
||||
|
||||
/*
|
||||
* mport Driver Definitions
|
||||
*/
|
||||
#define TSI721_DMA_CHNUM TSI721_DMA_MAXCH
|
||||
|
||||
#define TSI721_DMACH_MAINT 0 /* DMA channel for maint requests */
|
||||
#define TSI721_DMACH_MAINT_NBD 32 /* Number of BDs for maint requests */
|
||||
|
||||
#define MSG_DMA_ENTRY_INX_TO_SIZE(x) ((0x10 << (x)) & 0xFFFF0)
|
||||
|
||||
enum tsi721_smsg_int_flag {
|
||||
SMSG_INT_NONE = 0x00000000,
|
||||
SMSG_INT_ECC_COR_CH = 0x000000ff,
|
||||
SMSG_INT_ECC_NCOR_CH = 0x0000ff00,
|
||||
SMSG_INT_ECC_COR = 0x00020000,
|
||||
SMSG_INT_ECC_NCOR = 0x00040000,
|
||||
SMSG_INT_UNS_RSP = 0x00800000,
|
||||
SMSG_INT_ALL = 0x0006ffff
|
||||
};
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct tsi721_bdma_chan {
|
||||
int bd_num; /* number of buffer descriptors */
|
||||
void *bd_base; /* start of DMA descriptors */
|
||||
dma_addr_t bd_phys;
|
||||
void *sts_base; /* start of DMA BD status FIFO */
|
||||
dma_addr_t sts_phys;
|
||||
int sts_size;
|
||||
};
|
||||
|
||||
struct tsi721_imsg_ring {
|
||||
u32 size;
|
||||
/* VA/PA of data buffers for incoming messages */
|
||||
void *buf_base;
|
||||
dma_addr_t buf_phys;
|
||||
/* VA/PA of circular free buffer list */
|
||||
void *imfq_base;
|
||||
dma_addr_t imfq_phys;
|
||||
/* VA/PA of Inbound message descriptors */
|
||||
void *imd_base;
|
||||
dma_addr_t imd_phys;
|
||||
/* Inbound Queue buffer pointers */
|
||||
void *imq_base[TSI721_IMSGD_RING_SIZE];
|
||||
|
||||
u32 rx_slot;
|
||||
void *dev_id;
|
||||
u32 fq_wrptr;
|
||||
u32 desc_rdptr;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct tsi721_omsg_ring {
|
||||
u32 size;
|
||||
/* VA/PA of OB Msg descriptors */
|
||||
void *omd_base;
|
||||
dma_addr_t omd_phys;
|
||||
/* VA/PA of OB Msg data buffers */
|
||||
void *omq_base[TSI721_OMSGD_RING_SIZE];
|
||||
dma_addr_t omq_phys[TSI721_OMSGD_RING_SIZE];
|
||||
/* VA/PA of OB Msg descriptor status FIFO */
|
||||
void *sts_base;
|
||||
dma_addr_t sts_phys;
|
||||
u32 sts_size; /* # of allocated status entries */
|
||||
u32 sts_rdptr;
|
||||
|
||||
u32 tx_slot;
|
||||
void *dev_id;
|
||||
u32 wr_count;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum tsi721_flags {
|
||||
TSI721_USING_MSI = (1 << 0),
|
||||
TSI721_USING_MSIX = (1 << 1),
|
||||
TSI721_IMSGID_SET = (1 << 2),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
/*
|
||||
* MSI-X Table Entries (0 ... 69)
|
||||
*/
|
||||
#define TSI721_MSIX_DMACH_DONE(x) (0 + (x))
|
||||
#define TSI721_MSIX_DMACH_INT(x) (8 + (x))
|
||||
#define TSI721_MSIX_BDMA_INT 16
|
||||
#define TSI721_MSIX_OMSG_DONE(x) (17 + (x))
|
||||
#define TSI721_MSIX_OMSG_INT(x) (25 + (x))
|
||||
#define TSI721_MSIX_IMSG_DQ_RCV(x) (33 + (x))
|
||||
#define TSI721_MSIX_IMSG_INT(x) (41 + (x))
|
||||
#define TSI721_MSIX_MSG_INT 49
|
||||
#define TSI721_MSIX_SR2PC_IDBQ_RCV(x) (50 + (x))
|
||||
#define TSI721_MSIX_SR2PC_CH_INT(x) (58 + (x))
|
||||
#define TSI721_MSIX_SR2PC_INT 66
|
||||
#define TSI721_MSIX_PC2SR_INT 67
|
||||
#define TSI721_MSIX_SRIO_MAC_INT 68
|
||||
#define TSI721_MSIX_I2C_INT 69
|
||||
|
||||
/* MSI-X vector and init table entry indexes */
|
||||
enum tsi721_msix_vect {
|
||||
TSI721_VECT_IDB,
|
||||
TSI721_VECT_PWRX, /* PW_RX is part of SRIO MAC Interrupt reporting */
|
||||
TSI721_VECT_OMB0_DONE,
|
||||
TSI721_VECT_OMB1_DONE,
|
||||
TSI721_VECT_OMB2_DONE,
|
||||
TSI721_VECT_OMB3_DONE,
|
||||
TSI721_VECT_OMB0_INT,
|
||||
TSI721_VECT_OMB1_INT,
|
||||
TSI721_VECT_OMB2_INT,
|
||||
TSI721_VECT_OMB3_INT,
|
||||
TSI721_VECT_IMB0_RCV,
|
||||
TSI721_VECT_IMB1_RCV,
|
||||
TSI721_VECT_IMB2_RCV,
|
||||
TSI721_VECT_IMB3_RCV,
|
||||
TSI721_VECT_IMB0_INT,
|
||||
TSI721_VECT_IMB1_INT,
|
||||
TSI721_VECT_IMB2_INT,
|
||||
TSI721_VECT_IMB3_INT,
|
||||
TSI721_VECT_MAX
|
||||
};
|
||||
|
||||
#define IRQ_DEVICE_NAME_MAX 64
|
||||
|
||||
struct msix_irq {
|
||||
u16 vector;
|
||||
char irq_name[IRQ_DEVICE_NAME_MAX];
|
||||
};
|
||||
#endif /* CONFIG_PCI_MSI */
|
||||
|
||||
struct tsi721_device {
|
||||
struct pci_dev *pdev;
|
||||
struct rio_mport *mport;
|
||||
u32 flags;
|
||||
void __iomem *regs;
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
struct msix_irq msix[TSI721_VECT_MAX];
|
||||
#endif
|
||||
/* Doorbells */
|
||||
void __iomem *odb_base;
|
||||
void *idb_base;
|
||||
dma_addr_t idb_dma;
|
||||
struct work_struct idb_work;
|
||||
u32 db_discard_count;
|
||||
|
||||
/* Inbound Port-Write */
|
||||
struct work_struct pw_work;
|
||||
struct kfifo pw_fifo;
|
||||
spinlock_t pw_fifo_lock;
|
||||
u32 pw_discard_count;
|
||||
|
||||
/* BDMA Engine */
|
||||
struct tsi721_bdma_chan bdma[TSI721_DMA_CHNUM];
|
||||
|
||||
/* Inbound Messaging */
|
||||
int imsg_init[TSI721_IMSG_CHNUM];
|
||||
struct tsi721_imsg_ring imsg_ring[TSI721_IMSG_CHNUM];
|
||||
|
||||
/* Outbound Messaging */
|
||||
int omsg_init[TSI721_OMSG_CHNUM];
|
||||
struct tsi721_omsg_ring omsg_ring[TSI721_OMSG_CHNUM];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -516,7 +516,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net,
|
|||
return rdev;
|
||||
|
||||
cleanup:
|
||||
if (rio_is_switch(rdev))
|
||||
if (rswitch)
|
||||
kfree(rswitch->route_table);
|
||||
|
||||
kfree(rdev);
|
||||
|
@ -923,7 +923,7 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port,
|
|||
* rio_enum_complete- Tests if enumeration of a network is complete
|
||||
* @port: Master port to send transaction
|
||||
*
|
||||
* Tests the Component Tag CSR for non-zero value (enumeration
|
||||
* Tests the PGCCSR discovered bit for non-zero value (enumeration
|
||||
* complete flag). Return %1 if enumeration is complete or %0 if
|
||||
* enumeration is incomplete.
|
||||
*/
|
||||
|
@ -933,7 +933,7 @@ static int rio_enum_complete(struct rio_mport *port)
|
|||
|
||||
rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR,
|
||||
®val);
|
||||
return (regval & RIO_PORT_GEN_MASTER) ? 1 : 0;
|
||||
return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,16 +21,13 @@
|
|||
#include "rtc-core.h"
|
||||
|
||||
|
||||
static DEFINE_IDR(rtc_idr);
|
||||
static DEFINE_MUTEX(idr_lock);
|
||||
static DEFINE_IDA(rtc_ida);
|
||||
struct class *rtc_class;
|
||||
|
||||
static void rtc_device_release(struct device *dev)
|
||||
{
|
||||
struct rtc_device *rtc = to_rtc_device(dev);
|
||||
mutex_lock(&idr_lock);
|
||||
idr_remove(&rtc_idr, rtc->id);
|
||||
mutex_unlock(&idr_lock);
|
||||
ida_simple_remove(&rtc_ida, rtc->id);
|
||||
kfree(rtc);
|
||||
}
|
||||
|
||||
|
@ -146,25 +143,16 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
struct rtc_wkalrm alrm;
|
||||
int id, err;
|
||||
|
||||
if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
|
||||
err = -ENOMEM;
|
||||
id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
err = id;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
mutex_lock(&idr_lock);
|
||||
err = idr_get_new(&rtc_idr, NULL, &id);
|
||||
mutex_unlock(&idr_lock);
|
||||
|
||||
if (err < 0)
|
||||
goto exit;
|
||||
|
||||
id = id & MAX_ID_MASK;
|
||||
|
||||
rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
|
||||
if (rtc == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit_idr;
|
||||
goto exit_ida;
|
||||
}
|
||||
|
||||
rtc->id = id;
|
||||
|
@ -222,10 +210,8 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
|
|||
exit_kfree:
|
||||
kfree(rtc);
|
||||
|
||||
exit_idr:
|
||||
mutex_lock(&idr_lock);
|
||||
idr_remove(&rtc_idr, id);
|
||||
mutex_unlock(&idr_lock);
|
||||
exit_ida:
|
||||
ida_simple_remove(&rtc_ida, id);
|
||||
|
||||
exit:
|
||||
dev_err(dev, "rtc core: unable to register %s, err = %d\n",
|
||||
|
@ -276,7 +262,7 @@ static void __exit rtc_exit(void)
|
|||
{
|
||||
rtc_dev_exit();
|
||||
class_destroy(rtc_class);
|
||||
idr_destroy(&rtc_idr);
|
||||
ida_destroy(&rtc_ida);
|
||||
}
|
||||
|
||||
subsys_initcall(rtc_init);
|
||||
|
|
|
@ -34,6 +34,7 @@ enum ds_type {
|
|||
ds_1388,
|
||||
ds_3231,
|
||||
m41t00,
|
||||
mcp7941x,
|
||||
rx_8025,
|
||||
// rs5c372 too? different address...
|
||||
};
|
||||
|
@ -43,6 +44,7 @@ enum ds_type {
|
|||
#define DS1307_REG_SECS 0x00 /* 00-59 */
|
||||
# define DS1307_BIT_CH 0x80
|
||||
# define DS1340_BIT_nEOSC 0x80
|
||||
# define MCP7941X_BIT_ST 0x80
|
||||
#define DS1307_REG_MIN 0x01 /* 00-59 */
|
||||
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
|
||||
# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
|
||||
|
@ -50,6 +52,7 @@ enum ds_type {
|
|||
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
|
||||
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
|
||||
#define DS1307_REG_WDAY 0x03 /* 01-07 */
|
||||
# define MCP7941X_BIT_VBATEN 0x08
|
||||
#define DS1307_REG_MDAY 0x04 /* 01-31 */
|
||||
#define DS1307_REG_MONTH 0x05 /* 01-12 */
|
||||
# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
|
||||
|
@ -137,6 +140,8 @@ static const struct chip_desc chips[] = {
|
|||
},
|
||||
[m41t00] = {
|
||||
},
|
||||
[mcp7941x] = {
|
||||
},
|
||||
[rx_8025] = {
|
||||
}, };
|
||||
|
||||
|
@ -149,6 +154,7 @@ static const struct i2c_device_id ds1307_id[] = {
|
|||
{ "ds1340", ds_1340 },
|
||||
{ "ds3231", ds_3231 },
|
||||
{ "m41t00", m41t00 },
|
||||
{ "mcp7941x", mcp7941x },
|
||||
{ "pt7c4338", ds_1307 },
|
||||
{ "rx8025", rx_8025 },
|
||||
{ }
|
||||
|
@ -365,6 +371,10 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
|
|||
buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
|
||||
| DS1340_BIT_CENTURY;
|
||||
break;
|
||||
case mcp7941x:
|
||||
buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
|
||||
buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -808,6 +818,23 @@ static int __devinit ds1307_probe(struct i2c_client *client,
|
|||
i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
|
||||
dev_warn(&client->dev, "SET TIME!\n");
|
||||
}
|
||||
break;
|
||||
case mcp7941x:
|
||||
/* make sure that the backup battery is enabled */
|
||||
if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) {
|
||||
i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
|
||||
ds1307->regs[DS1307_REG_WDAY]
|
||||
| MCP7941X_BIT_VBATEN);
|
||||
}
|
||||
|
||||
/* clock halted? turn it on, so clock can tick. */
|
||||
if (!(tmp & MCP7941X_BIT_ST)) {
|
||||
i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
|
||||
MCP7941X_BIT_ST);
|
||||
dev_warn(&client->dev, "SET TIME!\n");
|
||||
goto read_rtc;
|
||||
}
|
||||
|
||||
break;
|
||||
case rx_8025:
|
||||
case ds_1337:
|
||||
|
|
|
@ -309,7 +309,7 @@ static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev)
|
||||
static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct mc13xxx_rtc *priv;
|
||||
|
@ -378,7 +378,7 @@ static int __devinit mc13xxx_rtc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit mc13xxx_rtc_remove(struct platform_device *pdev)
|
||||
static int __exit mc13xxx_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
|
||||
|
||||
|
@ -410,7 +410,7 @@ const struct platform_device_id mc13xxx_rtc_idtable[] = {
|
|||
|
||||
static struct platform_driver mc13xxx_rtc_driver = {
|
||||
.id_table = mc13xxx_rtc_idtable,
|
||||
.remove = __devexit_p(mc13xxx_rtc_remove),
|
||||
.remove = __exit_p(mc13xxx_rtc_remove),
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -114,43 +114,7 @@ static struct bin_attribute w1_ds2760_bin_attr = {
|
|||
.read = w1_ds2760_read_bin,
|
||||
};
|
||||
|
||||
static DEFINE_IDR(bat_idr);
|
||||
static DEFINE_MUTEX(bat_idr_lock);
|
||||
|
||||
static int new_bat_id(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
int id;
|
||||
|
||||
ret = idr_pre_get(&bat_idr, GFP_KERNEL);
|
||||
if (ret == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bat_idr_lock);
|
||||
ret = idr_get_new(&bat_idr, NULL, &id);
|
||||
mutex_unlock(&bat_idr_lock);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = id & MAX_ID_MASK;
|
||||
break;
|
||||
} else if (ret == -EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_bat_id(int id)
|
||||
{
|
||||
mutex_lock(&bat_idr_lock);
|
||||
idr_remove(&bat_idr, id);
|
||||
mutex_unlock(&bat_idr_lock);
|
||||
}
|
||||
static DEFINE_IDA(bat_ida);
|
||||
|
||||
static int w1_ds2760_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
|
@ -158,7 +122,7 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
|
|||
int id;
|
||||
struct platform_device *pdev;
|
||||
|
||||
id = new_bat_id();
|
||||
id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
goto noid;
|
||||
|
@ -187,7 +151,7 @@ static int w1_ds2760_add_slave(struct w1_slave *sl)
|
|||
pdev_add_failed:
|
||||
platform_device_unregister(pdev);
|
||||
pdev_alloc_failed:
|
||||
release_bat_id(id);
|
||||
ida_simple_remove(&bat_ida, id);
|
||||
noid:
|
||||
success:
|
||||
return ret;
|
||||
|
@ -199,7 +163,7 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
|
|||
int id = pdev->id;
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
release_bat_id(id);
|
||||
ida_simple_remove(&bat_ida, id);
|
||||
sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
|
||||
}
|
||||
|
||||
|
@ -217,14 +181,14 @@ static int __init w1_ds2760_init(void)
|
|||
{
|
||||
printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor "
|
||||
" chip - (c) 2004-2005, Szabolcs Gyurko\n");
|
||||
idr_init(&bat_idr);
|
||||
ida_init(&bat_ida);
|
||||
return w1_register_family(&w1_ds2760_family);
|
||||
}
|
||||
|
||||
static void __exit w1_ds2760_exit(void)
|
||||
{
|
||||
w1_unregister_family(&w1_ds2760_family);
|
||||
idr_destroy(&bat_idr);
|
||||
ida_destroy(&bat_ida);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(w1_ds2760_read);
|
||||
|
|
|
@ -26,20 +26,14 @@
|
|||
#include "../w1_family.h"
|
||||
#include "w1_ds2780.h"
|
||||
|
||||
int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io)
|
||||
static int w1_ds2780_do_io(struct device *dev, char *buf, int addr,
|
||||
size_t count, int io)
|
||||
{
|
||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
if (addr > DS2780_DATA_SIZE || addr < 0)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
|
||||
if (addr > DS2780_DATA_SIZE || addr < 0) {
|
||||
count = 0;
|
||||
goto out;
|
||||
}
|
||||
count = min_t(int, count, DS2780_DATA_SIZE - addr);
|
||||
|
||||
if (w1_reset_select_slave(sl) == 0) {
|
||||
|
@ -47,7 +41,6 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
|||
w1_write_8(sl->master, W1_DS2780_WRITE_DATA);
|
||||
w1_write_8(sl->master, addr);
|
||||
w1_write_block(sl->master, buf, count);
|
||||
/* XXX w1_write_block returns void, not n_written */
|
||||
} else {
|
||||
w1_write_8(sl->master, W1_DS2780_READ_DATA);
|
||||
w1_write_8(sl->master, addr);
|
||||
|
@ -55,13 +48,42 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
|||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io)
|
||||
{
|
||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&sl->master->mutex);
|
||||
|
||||
ret = w1_ds2780_do_io(dev, buf, addr, count, io);
|
||||
|
||||
mutex_unlock(&sl->master->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2780_io);
|
||||
|
||||
int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
ret = w1_ds2780_do_io(dev, buf, addr, count, io);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(w1_ds2780_io_nolock);
|
||||
|
||||
int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd)
|
||||
{
|
||||
struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
|
||||
|
@ -99,43 +121,7 @@ static struct bin_attribute w1_ds2780_bin_attr = {
|
|||
.read = w1_ds2780_read_bin,
|
||||
};
|
||||
|
||||
static DEFINE_IDR(bat_idr);
|
||||
static DEFINE_MUTEX(bat_idr_lock);
|
||||
|
||||
static int new_bat_id(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (1) {
|
||||
int id;
|
||||
|
||||
ret = idr_pre_get(&bat_idr, GFP_KERNEL);
|
||||
if (ret == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&bat_idr_lock);
|
||||
ret = idr_get_new(&bat_idr, NULL, &id);
|
||||
mutex_unlock(&bat_idr_lock);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = id & MAX_ID_MASK;
|
||||
break;
|
||||
} else if (ret == -EAGAIN) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void release_bat_id(int id)
|
||||
{
|
||||
mutex_lock(&bat_idr_lock);
|
||||
idr_remove(&bat_idr, id);
|
||||
mutex_unlock(&bat_idr_lock);
|
||||
}
|
||||
static DEFINE_IDA(bat_ida);
|
||||
|
||||
static int w1_ds2780_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
|
@ -143,7 +129,7 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
|
|||
int id;
|
||||
struct platform_device *pdev;
|
||||
|
||||
id = new_bat_id();
|
||||
id = ida_simple_get(&bat_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
goto noid;
|
||||
|
@ -172,7 +158,7 @@ static int w1_ds2780_add_slave(struct w1_slave *sl)
|
|||
pdev_add_failed:
|
||||
platform_device_unregister(pdev);
|
||||
pdev_alloc_failed:
|
||||
release_bat_id(id);
|
||||
ida_simple_remove(&bat_ida, id);
|
||||
noid:
|
||||
return ret;
|
||||
}
|
||||
|
@ -183,7 +169,7 @@ static void w1_ds2780_remove_slave(struct w1_slave *sl)
|
|||
int id = pdev->id;
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
release_bat_id(id);
|
||||
ida_simple_remove(&bat_ida, id);
|
||||
sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2780_bin_attr);
|
||||
}
|
||||
|
||||
|
@ -199,14 +185,14 @@ static struct w1_family w1_ds2780_family = {
|
|||
|
||||
static int __init w1_ds2780_init(void)
|
||||
{
|
||||
idr_init(&bat_idr);
|
||||
ida_init(&bat_ida);
|
||||
return w1_register_family(&w1_ds2780_family);
|
||||
}
|
||||
|
||||
static void __exit w1_ds2780_exit(void)
|
||||
{
|
||||
w1_unregister_family(&w1_ds2780_family);
|
||||
idr_destroy(&bat_idr);
|
||||
ida_destroy(&bat_ida);
|
||||
}
|
||||
|
||||
module_init(w1_ds2780_init);
|
||||
|
|
|
@ -124,6 +124,8 @@
|
|||
|
||||
extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count,
|
||||
int io);
|
||||
extern int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr,
|
||||
size_t count, int io);
|
||||
extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd);
|
||||
|
||||
#endif /* !_W1_DS2780_H */
|
||||
|
|
|
@ -78,6 +78,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
|
|||
memcpy(&dev->dev, device, sizeof(struct device));
|
||||
dev_set_name(&dev->dev, "w1_bus_master%u", dev->id);
|
||||
snprintf(dev->name, sizeof(dev->name), "w1_bus_master%u", dev->id);
|
||||
dev->dev.init_name = dev->name;
|
||||
|
||||
dev->driver = driver;
|
||||
|
||||
|
|
|
@ -158,13 +158,18 @@ EXPORT_SYMBOL_GPL(w1_write_8);
|
|||
static u8 w1_read_bit(struct w1_master *dev)
|
||||
{
|
||||
int result;
|
||||
unsigned long flags;
|
||||
|
||||
/* sample timing is critical here */
|
||||
local_irq_save(flags);
|
||||
dev->bus_master->write_bit(dev->bus_master->data, 0);
|
||||
w1_delay(6);
|
||||
dev->bus_master->write_bit(dev->bus_master->data, 1);
|
||||
w1_delay(9);
|
||||
|
||||
result = dev->bus_master->read_bit(dev->bus_master->data);
|
||||
local_irq_restore(flags);
|
||||
|
||||
w1_delay(55);
|
||||
|
||||
return result & 0x1;
|
||||
|
|
146
fs/aio.c
146
fs/aio.c
|
@ -440,8 +440,6 @@ void exit_aio(struct mm_struct *mm)
|
|||
static struct kiocb *__aio_get_req(struct kioctx *ctx)
|
||||
{
|
||||
struct kiocb *req = NULL;
|
||||
struct aio_ring *ring;
|
||||
int okay = 0;
|
||||
|
||||
req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL);
|
||||
if (unlikely(!req))
|
||||
|
@ -459,39 +457,114 @@ static struct kiocb *__aio_get_req(struct kioctx *ctx)
|
|||
INIT_LIST_HEAD(&req->ki_run_list);
|
||||
req->ki_eventfd = NULL;
|
||||
|
||||
/* Check if the completion queue has enough free space to
|
||||
* accept an event from this io.
|
||||
*/
|
||||
spin_lock_irq(&ctx->ctx_lock);
|
||||
ring = kmap_atomic(ctx->ring_info.ring_pages[0], KM_USER0);
|
||||
if (ctx->reqs_active < aio_ring_avail(&ctx->ring_info, ring)) {
|
||||
list_add(&req->ki_list, &ctx->active_reqs);
|
||||
ctx->reqs_active++;
|
||||
okay = 1;
|
||||
}
|
||||
kunmap_atomic(ring, KM_USER0);
|
||||
spin_unlock_irq(&ctx->ctx_lock);
|
||||
|
||||
if (!okay) {
|
||||
kmem_cache_free(kiocb_cachep, req);
|
||||
req = NULL;
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static inline struct kiocb *aio_get_req(struct kioctx *ctx)
|
||||
/*
|
||||
* struct kiocb's are allocated in batches to reduce the number of
|
||||
* times the ctx lock is acquired and released.
|
||||
*/
|
||||
#define KIOCB_BATCH_SIZE 32L
|
||||
struct kiocb_batch {
|
||||
struct list_head head;
|
||||
long count; /* number of requests left to allocate */
|
||||
};
|
||||
|
||||
static void kiocb_batch_init(struct kiocb_batch *batch, long total)
|
||||
{
|
||||
INIT_LIST_HEAD(&batch->head);
|
||||
batch->count = total;
|
||||
}
|
||||
|
||||
static void kiocb_batch_free(struct kiocb_batch *batch)
|
||||
{
|
||||
struct kiocb *req, *n;
|
||||
|
||||
list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
|
||||
list_del(&req->ki_batch);
|
||||
kmem_cache_free(kiocb_cachep, req);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a batch of kiocbs. This avoids taking and dropping the
|
||||
* context lock a lot during setup.
|
||||
*/
|
||||
static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
|
||||
{
|
||||
unsigned short allocated, to_alloc;
|
||||
long avail;
|
||||
bool called_fput = false;
|
||||
struct kiocb *req, *n;
|
||||
struct aio_ring *ring;
|
||||
|
||||
to_alloc = min(batch->count, KIOCB_BATCH_SIZE);
|
||||
for (allocated = 0; allocated < to_alloc; allocated++) {
|
||||
req = __aio_get_req(ctx);
|
||||
if (!req)
|
||||
/* allocation failed, go with what we've got */
|
||||
break;
|
||||
list_add(&req->ki_batch, &batch->head);
|
||||
}
|
||||
|
||||
if (allocated == 0)
|
||||
goto out;
|
||||
|
||||
retry:
|
||||
spin_lock_irq(&ctx->ctx_lock);
|
||||
ring = kmap_atomic(ctx->ring_info.ring_pages[0]);
|
||||
|
||||
avail = aio_ring_avail(&ctx->ring_info, ring) - ctx->reqs_active;
|
||||
BUG_ON(avail < 0);
|
||||
if (avail == 0 && !called_fput) {
|
||||
/*
|
||||
* Handle a potential starvation case. It is possible that
|
||||
* we hold the last reference on a struct file, causing us
|
||||
* to delay the final fput to non-irq context. In this case,
|
||||
* ctx->reqs_active is artificially high. Calling the fput
|
||||
* routine here may free up a slot in the event completion
|
||||
* ring, allowing this allocation to succeed.
|
||||
*/
|
||||
kunmap_atomic(ring);
|
||||
spin_unlock_irq(&ctx->ctx_lock);
|
||||
aio_fput_routine(NULL);
|
||||
called_fput = true;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (avail < allocated) {
|
||||
/* Trim back the number of requests. */
|
||||
list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
|
||||
list_del(&req->ki_batch);
|
||||
kmem_cache_free(kiocb_cachep, req);
|
||||
if (--allocated <= avail)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
batch->count -= allocated;
|
||||
list_for_each_entry(req, &batch->head, ki_batch) {
|
||||
list_add(&req->ki_list, &ctx->active_reqs);
|
||||
ctx->reqs_active++;
|
||||
}
|
||||
|
||||
kunmap_atomic(ring);
|
||||
spin_unlock_irq(&ctx->ctx_lock);
|
||||
|
||||
out:
|
||||
return allocated;
|
||||
}
|
||||
|
||||
static inline struct kiocb *aio_get_req(struct kioctx *ctx,
|
||||
struct kiocb_batch *batch)
|
||||
{
|
||||
struct kiocb *req;
|
||||
/* Handle a potential starvation case -- should be exceedingly rare as
|
||||
* requests will be stuck on fput_head only if the aio_fput_routine is
|
||||
* delayed and the requests were the last user of the struct file.
|
||||
*/
|
||||
req = __aio_get_req(ctx);
|
||||
if (unlikely(NULL == req)) {
|
||||
aio_fput_routine(NULL);
|
||||
req = __aio_get_req(ctx);
|
||||
}
|
||||
|
||||
if (list_empty(&batch->head))
|
||||
if (kiocb_batch_refill(ctx, batch) == 0)
|
||||
return NULL;
|
||||
req = list_first_entry(&batch->head, struct kiocb, ki_batch);
|
||||
list_del(&req->ki_batch);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -1515,7 +1588,8 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat)
|
|||
}
|
||||
|
||||
static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
|
||||
struct iocb *iocb, bool compat)
|
||||
struct iocb *iocb, struct kiocb_batch *batch,
|
||||
bool compat)
|
||||
{
|
||||
struct kiocb *req;
|
||||
struct file *file;
|
||||
|
@ -1541,7 +1615,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
|
|||
if (unlikely(!file))
|
||||
return -EBADF;
|
||||
|
||||
req = aio_get_req(ctx); /* returns with 2 references to req */
|
||||
req = aio_get_req(ctx, batch); /* returns with 2 references to req */
|
||||
if (unlikely(!req)) {
|
||||
fput(file);
|
||||
return -EAGAIN;
|
||||
|
@ -1621,8 +1695,9 @@ long do_io_submit(aio_context_t ctx_id, long nr,
|
|||
{
|
||||
struct kioctx *ctx;
|
||||
long ret = 0;
|
||||
int i;
|
||||
int i = 0;
|
||||
struct blk_plug plug;
|
||||
struct kiocb_batch batch;
|
||||
|
||||
if (unlikely(nr < 0))
|
||||
return -EINVAL;
|
||||
|
@ -1639,6 +1714,8 @@ long do_io_submit(aio_context_t ctx_id, long nr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
kiocb_batch_init(&batch, nr);
|
||||
|
||||
blk_start_plug(&plug);
|
||||
|
||||
/*
|
||||
|
@ -1659,12 +1736,13 @@ long do_io_submit(aio_context_t ctx_id, long nr,
|
|||
break;
|
||||
}
|
||||
|
||||
ret = io_submit_one(ctx, user_iocb, &tmp, compat);
|
||||
ret = io_submit_one(ctx, user_iocb, &tmp, &batch, compat);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
blk_finish_plug(&plug);
|
||||
|
||||
kiocb_batch_free(&batch);
|
||||
put_ioctx(ctx);
|
||||
return i ? i : ret;
|
||||
}
|
||||
|
|
|
@ -795,7 +795,16 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
|
|||
* might try to exec. This is because the brk will
|
||||
* follow the loader, and is not movable. */
|
||||
#if defined(CONFIG_X86) || defined(CONFIG_ARM)
|
||||
load_bias = 0;
|
||||
/* Memory randomization might have been switched off
|
||||
* in runtime via sysctl.
|
||||
* If that is the case, retain the original non-zero
|
||||
* load_bias value in order to establish proper
|
||||
* non-randomized mappings.
|
||||
*/
|
||||
if (current->flags & PF_RANDOMIZE)
|
||||
load_bias = 0;
|
||||
else
|
||||
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
|
||||
#else
|
||||
load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
|
||||
#endif
|
||||
|
|
|
@ -46,11 +46,26 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
|
|||
case HFS_EXT_CNID:
|
||||
hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize,
|
||||
mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz));
|
||||
if (HFS_I(tree->inode)->alloc_blocks >
|
||||
HFS_I(tree->inode)->first_blocks) {
|
||||
printk(KERN_ERR "hfs: invalid btree extent records\n");
|
||||
unlock_new_inode(tree->inode);
|
||||
goto free_inode;
|
||||
}
|
||||
|
||||
tree->inode->i_mapping->a_ops = &hfs_btree_aops;
|
||||
break;
|
||||
case HFS_CAT_CNID:
|
||||
hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize,
|
||||
mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz));
|
||||
|
||||
if (!HFS_I(tree->inode)->first_blocks) {
|
||||
printk(KERN_ERR "hfs: invalid btree extent records "
|
||||
"(0 size).\n");
|
||||
unlock_new_inode(tree->inode);
|
||||
goto free_inode;
|
||||
}
|
||||
|
||||
tree->inode->i_mapping->a_ops = &hfs_btree_aops;
|
||||
break;
|
||||
default:
|
||||
|
@ -59,11 +74,6 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
|
|||
}
|
||||
unlock_new_inode(tree->inode);
|
||||
|
||||
if (!HFS_I(tree->inode)->first_blocks) {
|
||||
printk(KERN_ERR "hfs: invalid btree extent records (0 size).\n");
|
||||
goto free_inode;
|
||||
}
|
||||
|
||||
mapping = tree->inode->i_mapping;
|
||||
page = read_mapping_page(mapping, 0, NULL);
|
||||
if (IS_ERR(page))
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/statfs.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/mpage.h>
|
||||
|
||||
#include "isofs.h"
|
||||
#include "zisofs.h"
|
||||
|
@ -1148,7 +1149,13 @@ struct buffer_head *isofs_bread(struct inode *inode, sector_t block)
|
|||
|
||||
static int isofs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
return block_read_full_page(page,isofs_get_block);
|
||||
return mpage_readpage(page, isofs_get_block);
|
||||
}
|
||||
|
||||
static int isofs_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
return mpage_readpages(mapping, pages, nr_pages, isofs_get_block);
|
||||
}
|
||||
|
||||
static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
|
||||
|
@ -1158,6 +1165,7 @@ static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
|
|||
|
||||
static const struct address_space_operations isofs_aops = {
|
||||
.readpage = isofs_readpage,
|
||||
.readpages = isofs_readpages,
|
||||
.bmap = _isofs_bmap
|
||||
};
|
||||
|
||||
|
|
142
fs/proc/base.c
142
fs/proc/base.c
|
@ -1652,12 +1652,46 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
|
|||
return error;
|
||||
}
|
||||
|
||||
static int proc_pid_fd_link_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct task_struct *task = get_proc_task(inode);
|
||||
int rc;
|
||||
|
||||
if (task == NULL)
|
||||
return -ESRCH;
|
||||
|
||||
rc = -EACCES;
|
||||
if (lock_trace(task))
|
||||
goto out_task;
|
||||
|
||||
generic_fillattr(inode, stat);
|
||||
unlock_trace(task);
|
||||
rc = 0;
|
||||
out_task:
|
||||
put_task_struct(task);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct inode_operations proc_pid_link_inode_operations = {
|
||||
.readlink = proc_pid_readlink,
|
||||
.follow_link = proc_pid_follow_link,
|
||||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
static const struct inode_operations proc_fdinfo_link_inode_operations = {
|
||||
.setattr = proc_setattr,
|
||||
.getattr = proc_pid_fd_link_getattr,
|
||||
};
|
||||
|
||||
static const struct inode_operations proc_fd_link_inode_operations = {
|
||||
.readlink = proc_pid_readlink,
|
||||
.follow_link = proc_pid_follow_link,
|
||||
.setattr = proc_setattr,
|
||||
.getattr = proc_pid_fd_link_getattr,
|
||||
};
|
||||
|
||||
|
||||
/* building an inode */
|
||||
|
||||
|
@ -1889,49 +1923,61 @@ static unsigned name_to_int(struct dentry *dentry)
|
|||
|
||||
static int proc_fd_info(struct inode *inode, struct path *path, char *info)
|
||||
{
|
||||
struct task_struct *task = get_proc_task(inode);
|
||||
struct files_struct *files = NULL;
|
||||
struct task_struct *task;
|
||||
struct files_struct *files;
|
||||
struct file *file;
|
||||
int fd = proc_fd(inode);
|
||||
int rc;
|
||||
|
||||
if (task) {
|
||||
files = get_files_struct(task);
|
||||
put_task_struct(task);
|
||||
}
|
||||
if (files) {
|
||||
/*
|
||||
* We are not taking a ref to the file structure, so we must
|
||||
* hold ->file_lock.
|
||||
*/
|
||||
spin_lock(&files->file_lock);
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
unsigned int f_flags;
|
||||
struct fdtable *fdt;
|
||||
task = get_proc_task(inode);
|
||||
if (!task)
|
||||
return -ENOENT;
|
||||
|
||||
fdt = files_fdtable(files);
|
||||
f_flags = file->f_flags & ~O_CLOEXEC;
|
||||
if (FD_ISSET(fd, fdt->close_on_exec))
|
||||
f_flags |= O_CLOEXEC;
|
||||
rc = -EACCES;
|
||||
if (lock_trace(task))
|
||||
goto out_task;
|
||||
|
||||
if (path) {
|
||||
*path = file->f_path;
|
||||
path_get(&file->f_path);
|
||||
}
|
||||
if (info)
|
||||
snprintf(info, PROC_FDINFO_MAX,
|
||||
"pos:\t%lli\n"
|
||||
"flags:\t0%o\n",
|
||||
(long long) file->f_pos,
|
||||
f_flags);
|
||||
spin_unlock(&files->file_lock);
|
||||
put_files_struct(files);
|
||||
return 0;
|
||||
rc = -ENOENT;
|
||||
files = get_files_struct(task);
|
||||
if (files == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* We are not taking a ref to the file structure, so we must
|
||||
* hold ->file_lock.
|
||||
*/
|
||||
spin_lock(&files->file_lock);
|
||||
file = fcheck_files(files, fd);
|
||||
if (file) {
|
||||
unsigned int f_flags;
|
||||
struct fdtable *fdt;
|
||||
|
||||
fdt = files_fdtable(files);
|
||||
f_flags = file->f_flags & ~O_CLOEXEC;
|
||||
if (FD_ISSET(fd, fdt->close_on_exec))
|
||||
f_flags |= O_CLOEXEC;
|
||||
|
||||
if (path) {
|
||||
*path = file->f_path;
|
||||
path_get(&file->f_path);
|
||||
}
|
||||
spin_unlock(&files->file_lock);
|
||||
put_files_struct(files);
|
||||
}
|
||||
return -ENOENT;
|
||||
if (info)
|
||||
snprintf(info, PROC_FDINFO_MAX,
|
||||
"pos:\t%lli\n"
|
||||
"flags:\t0%o\n",
|
||||
(long long) file->f_pos,
|
||||
f_flags);
|
||||
rc = 0;
|
||||
} else
|
||||
rc = -ENOENT;
|
||||
spin_unlock(&files->file_lock);
|
||||
put_files_struct(files);
|
||||
|
||||
out_unlock:
|
||||
unlock_trace(task);
|
||||
out_task:
|
||||
put_task_struct(task);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int proc_fd_link(struct inode *inode, struct path *path)
|
||||
|
@ -2026,7 +2072,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
|
|||
spin_unlock(&files->file_lock);
|
||||
put_files_struct(files);
|
||||
|
||||
inode->i_op = &proc_pid_link_inode_operations;
|
||||
inode->i_op = &proc_fd_link_inode_operations;
|
||||
inode->i_size = 64;
|
||||
ei->op.proc_get_link = proc_fd_link;
|
||||
d_set_d_op(dentry, &tid_fd_dentry_operations);
|
||||
|
@ -2058,7 +2104,12 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
|
|||
if (fd == ~0U)
|
||||
goto out;
|
||||
|
||||
result = ERR_PTR(-EACCES);
|
||||
if (lock_trace(task))
|
||||
goto out;
|
||||
|
||||
result = instantiate(dir, dentry, task, &fd);
|
||||
unlock_trace(task);
|
||||
out:
|
||||
put_task_struct(task);
|
||||
out_no_task:
|
||||
|
@ -2078,23 +2129,28 @@ static int proc_readfd_common(struct file * filp, void * dirent,
|
|||
retval = -ENOENT;
|
||||
if (!p)
|
||||
goto out_no_task;
|
||||
|
||||
retval = -EACCES;
|
||||
if (lock_trace(p))
|
||||
goto out;
|
||||
|
||||
retval = 0;
|
||||
|
||||
fd = filp->f_pos;
|
||||
switch (fd) {
|
||||
case 0:
|
||||
if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
filp->f_pos++;
|
||||
case 1:
|
||||
ino = parent_ino(dentry);
|
||||
if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
filp->f_pos++;
|
||||
default:
|
||||
files = get_files_struct(p);
|
||||
if (!files)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
rcu_read_lock();
|
||||
for (fd = filp->f_pos-2;
|
||||
fd < files_fdtable(files)->max_fds;
|
||||
|
@ -2118,6 +2174,9 @@ static int proc_readfd_common(struct file * filp, void * dirent,
|
|||
rcu_read_unlock();
|
||||
put_files_struct(files);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
unlock_trace(p);
|
||||
out:
|
||||
put_task_struct(p);
|
||||
out_no_task:
|
||||
|
@ -2195,6 +2254,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
|
|||
ei->fd = fd;
|
||||
inode->i_mode = S_IFREG | S_IRUSR;
|
||||
inode->i_fop = &proc_fdinfo_file_operations;
|
||||
inode->i_op = &proc_fdinfo_link_inode_operations;
|
||||
d_set_d_op(dentry, &tid_fd_dentry_operations);
|
||||
d_add(dentry, inode);
|
||||
/* Close the race of the process dying before we return the dentry */
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/namei.h>
|
||||
|
@ -14,6 +15,15 @@ static const struct inode_operations proc_sys_inode_operations;
|
|||
static const struct file_operations proc_sys_dir_file_operations;
|
||||
static const struct inode_operations proc_sys_dir_operations;
|
||||
|
||||
void proc_sys_poll_notify(struct ctl_table_poll *poll)
|
||||
{
|
||||
if (!poll)
|
||||
return;
|
||||
|
||||
atomic_inc(&poll->event);
|
||||
wake_up_interruptible(&poll->wait);
|
||||
}
|
||||
|
||||
static struct inode *proc_sys_make_inode(struct super_block *sb,
|
||||
struct ctl_table_header *head, struct ctl_table *table)
|
||||
{
|
||||
|
@ -176,6 +186,39 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
|
|||
return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
|
||||
}
|
||||
|
||||
static int proc_sys_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
|
||||
if (table->poll)
|
||||
filp->private_data = proc_sys_poll_event(table->poll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int proc_sys_poll(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||
struct ctl_table *table = PROC_I(inode)->sysctl_entry;
|
||||
unsigned long event = (unsigned long)filp->private_data;
|
||||
unsigned int ret = DEFAULT_POLLMASK;
|
||||
|
||||
if (!table->proc_handler)
|
||||
goto out;
|
||||
|
||||
if (!table->poll)
|
||||
goto out;
|
||||
|
||||
poll_wait(filp, &table->poll->wait, wait);
|
||||
|
||||
if (event != atomic_read(&table->poll->event)) {
|
||||
filp->private_data = proc_sys_poll_event(table->poll);
|
||||
ret = POLLIN | POLLRDNORM | POLLERR | POLLPRI;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int proc_sys_fill_cache(struct file *filp, void *dirent,
|
||||
filldir_t filldir,
|
||||
|
@ -364,12 +407,15 @@ static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
|
|||
}
|
||||
|
||||
static const struct file_operations proc_sys_file_operations = {
|
||||
.open = proc_sys_open,
|
||||
.poll = proc_sys_poll,
|
||||
.read = proc_sys_read,
|
||||
.write = proc_sys_write,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static const struct file_operations proc_sys_dir_file_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = proc_sys_readdir,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
* caches is sufficient.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/highmem.h>
|
||||
|
@ -288,14 +287,7 @@ static int __init init_ramfs_fs(void)
|
|||
{
|
||||
return register_filesystem(&ramfs_fs_type);
|
||||
}
|
||||
|
||||
static void __exit exit_ramfs_fs(void)
|
||||
{
|
||||
unregister_filesystem(&ramfs_fs_type);
|
||||
}
|
||||
|
||||
module_init(init_ramfs_fs)
|
||||
module_exit(exit_ramfs_fs)
|
||||
|
||||
int __init init_rootfs(void)
|
||||
{
|
||||
|
@ -311,5 +303,3 @@ int __init init_rootfs(void)
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -117,6 +117,7 @@ struct kiocb {
|
|||
|
||||
struct list_head ki_list; /* the aio core uses this
|
||||
* for cancellation */
|
||||
struct list_head ki_batch; /* batch allocation */
|
||||
|
||||
/*
|
||||
* If the aio_resfd field of the userspace iocb is not zero,
|
||||
|
|
|
@ -516,7 +516,7 @@ struct cgroup_subsys {
|
|||
struct list_head sibling;
|
||||
/* used when use_id == true */
|
||||
struct idr idr;
|
||||
spinlock_t id_lock;
|
||||
rwlock_t id_lock;
|
||||
|
||||
/* should be defined only by modular subsystems */
|
||||
struct module *module;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _LINUX_DMA_MAPPING_H
|
||||
#define _LINUX_DMA_MAPPING_H
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/dma-attrs.h>
|
||||
|
@ -117,6 +118,15 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
static inline void *dma_zalloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
{
|
||||
void *ret = dma_alloc_coherent(dev, size, dma_handle, flag);
|
||||
if (ret)
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAS_DMA
|
||||
static inline int dma_get_cache_alignment(void)
|
||||
{
|
||||
|
|
|
@ -30,11 +30,11 @@
|
|||
#define ANON_INODE_FS_MAGIC 0x09041934
|
||||
#define PSTOREFS_MAGIC 0x6165676C
|
||||
|
||||
#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
|
||||
#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
|
||||
#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */
|
||||
#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */
|
||||
#define MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 fs */
|
||||
#define MINIX_SUPER_MAGIC 0x137F /* minix v1 fs, 14 char names */
|
||||
#define MINIX_SUPER_MAGIC2 0x138F /* minix v1 fs, 30 char names */
|
||||
#define MINIX2_SUPER_MAGIC 0x2468 /* minix v2 fs, 14 char names */
|
||||
#define MINIX2_SUPER_MAGIC2 0x2478 /* minix v2 fs, 30 char names */
|
||||
#define MINIX3_SUPER_MAGIC 0x4d5a /* minix v3 fs, 60 char names */
|
||||
|
||||
#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */
|
||||
#define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */
|
||||
|
|
|
@ -78,8 +78,8 @@ extern void mem_cgroup_uncharge_end(void);
|
|||
extern void mem_cgroup_uncharge_page(struct page *page);
|
||||
extern void mem_cgroup_uncharge_cache_page(struct page *page);
|
||||
|
||||
extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask);
|
||||
int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
|
||||
extern void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask);
|
||||
int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg);
|
||||
|
||||
extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
|
||||
extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
|
||||
|
@ -88,26 +88,28 @@ extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
|
|||
static inline
|
||||
int mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *cgroup)
|
||||
{
|
||||
struct mem_cgroup *mem;
|
||||
struct mem_cgroup *memcg;
|
||||
rcu_read_lock();
|
||||
mem = mem_cgroup_from_task(rcu_dereference((mm)->owner));
|
||||
memcg = mem_cgroup_from_task(rcu_dereference((mm)->owner));
|
||||
rcu_read_unlock();
|
||||
return cgroup == mem;
|
||||
return cgroup == memcg;
|
||||
}
|
||||
|
||||
extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem);
|
||||
extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg);
|
||||
|
||||
extern int
|
||||
mem_cgroup_prepare_migration(struct page *page,
|
||||
struct page *newpage, struct mem_cgroup **ptr, gfp_t gfp_mask);
|
||||
extern void mem_cgroup_end_migration(struct mem_cgroup *mem,
|
||||
extern void mem_cgroup_end_migration(struct mem_cgroup *memcg,
|
||||
struct page *oldpage, struct page *newpage, bool migration_ok);
|
||||
|
||||
/*
|
||||
* For memory reclaim.
|
||||
*/
|
||||
int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg);
|
||||
int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg);
|
||||
int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg,
|
||||
struct zone *zone);
|
||||
int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg,
|
||||
struct zone *zone);
|
||||
int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
|
||||
unsigned long mem_cgroup_zone_nr_lru_pages(struct mem_cgroup *memcg,
|
||||
int nid, int zid, unsigned int lrumask);
|
||||
|
@ -148,7 +150,7 @@ static inline void mem_cgroup_dec_page_stat(struct page *page,
|
|||
unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
|
||||
gfp_t gfp_mask,
|
||||
unsigned long *total_scanned);
|
||||
u64 mem_cgroup_get_limit(struct mem_cgroup *mem);
|
||||
u64 mem_cgroup_get_limit(struct mem_cgroup *memcg);
|
||||
|
||||
void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
|
@ -244,18 +246,20 @@ static inline struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *mem)
|
||||
static inline int mm_match_cgroup(struct mm_struct *mm,
|
||||
struct mem_cgroup *memcg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int task_in_mem_cgroup(struct task_struct *task,
|
||||
const struct mem_cgroup *mem)
|
||||
const struct mem_cgroup *memcg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *mem)
|
||||
static inline struct cgroup_subsys_state
|
||||
*mem_cgroup_css(struct mem_cgroup *memcg)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
@ -267,22 +271,22 @@ mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void mem_cgroup_end_migration(struct mem_cgroup *mem,
|
||||
static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg,
|
||||
struct page *oldpage, struct page *newpage, bool migration_ok)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *mem)
|
||||
static inline int mem_cgroup_get_reclaim_priority(struct mem_cgroup *memcg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
|
||||
static inline void mem_cgroup_note_reclaim_priority(struct mem_cgroup *memcg,
|
||||
int priority)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem,
|
||||
static inline void mem_cgroup_record_reclaim_priority(struct mem_cgroup *memcg,
|
||||
int priority)
|
||||
{
|
||||
}
|
||||
|
@ -293,13 +297,13 @@ static inline bool mem_cgroup_disabled(void)
|
|||
}
|
||||
|
||||
static inline int
|
||||
mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
|
||||
mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg, struct zone *zone)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
|
||||
mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg, struct zone *zone)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@ -348,7 +352,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
|
|||
}
|
||||
|
||||
static inline
|
||||
u64 mem_cgroup_get_limit(struct mem_cgroup *mem)
|
||||
u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -356,36 +356,50 @@ static inline struct page *compound_head(struct page *page)
|
|||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
* The atomic page->_mapcount, starts from -1: so that transitions
|
||||
* both from it and to it can be tracked, using atomic_inc_and_test
|
||||
* and atomic_add_negative(-1).
|
||||
*/
|
||||
static inline void reset_page_mapcount(struct page *page)
|
||||
{
|
||||
atomic_set(&(page)->_mapcount, -1);
|
||||
}
|
||||
|
||||
static inline int page_mapcount(struct page *page)
|
||||
{
|
||||
return atomic_read(&(page)->_mapcount) + 1;
|
||||
}
|
||||
|
||||
static inline int page_count(struct page *page)
|
||||
{
|
||||
return atomic_read(&compound_head(page)->_count);
|
||||
}
|
||||
|
||||
static inline void get_page(struct page *page)
|
||||
static inline void get_huge_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* Getting a normal page or the head of a compound page
|
||||
* requires to already have an elevated page->_count. Only if
|
||||
* we're getting a tail page, the elevated page->_count is
|
||||
* required only in the head page, so for tail pages the
|
||||
* bugcheck only verifies that the page->_count isn't
|
||||
* negative.
|
||||
* __split_huge_page_refcount() cannot run
|
||||
* from under us.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) < !PageTail(page));
|
||||
atomic_inc(&page->_count);
|
||||
VM_BUG_ON(page_mapcount(page) < 0);
|
||||
VM_BUG_ON(atomic_read(&page->_count) != 0);
|
||||
atomic_inc(&page->_mapcount);
|
||||
}
|
||||
|
||||
extern bool __get_page_tail(struct page *page);
|
||||
|
||||
static inline void get_page(struct page *page)
|
||||
{
|
||||
if (unlikely(PageTail(page)))
|
||||
if (likely(__get_page_tail(page)))
|
||||
return;
|
||||
/*
|
||||
* Getting a tail page will elevate both the head and tail
|
||||
* page->_count(s).
|
||||
* Getting a normal page or the head of a compound page
|
||||
* requires to already have an elevated page->_count.
|
||||
*/
|
||||
if (unlikely(PageTail(page))) {
|
||||
/*
|
||||
* This is safe only because
|
||||
* __split_huge_page_refcount can't run under
|
||||
* get_page().
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0);
|
||||
atomic_inc(&page->first_page->_count);
|
||||
}
|
||||
VM_BUG_ON(atomic_read(&page->_count) <= 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
|
||||
static inline struct page *virt_to_head_page(const void *x)
|
||||
|
@ -803,21 +817,6 @@ static inline pgoff_t page_index(struct page *page)
|
|||
return page->index;
|
||||
}
|
||||
|
||||
/*
|
||||
* The atomic page->_mapcount, like _count, starts from -1:
|
||||
* so that transitions both from it and to it can be tracked,
|
||||
* using atomic_inc_and_test and atomic_add_negative(-1).
|
||||
*/
|
||||
static inline void reset_page_mapcount(struct page *page)
|
||||
{
|
||||
atomic_set(&(page)->_mapcount, -1);
|
||||
}
|
||||
|
||||
static inline int page_mapcount(struct page *page)
|
||||
{
|
||||
return atomic_read(&(page)->_mapcount) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if this page is mapped into pagetables.
|
||||
*/
|
||||
|
|
|
@ -62,10 +62,23 @@ struct page {
|
|||
struct {
|
||||
|
||||
union {
|
||||
atomic_t _mapcount; /* Count of ptes mapped in mms,
|
||||
* to show when page is mapped
|
||||
* & limit reverse map searches.
|
||||
*/
|
||||
/*
|
||||
* Count of ptes mapped in
|
||||
* mms, to show when page is
|
||||
* mapped & limit reverse map
|
||||
* searches.
|
||||
*
|
||||
* Used also for tail pages
|
||||
* refcounting instead of
|
||||
* _count. Tail pages cannot
|
||||
* be mapped and keeping the
|
||||
* tail page _count zero at
|
||||
* all times guarantees
|
||||
* get_page_unless_zero() will
|
||||
* never succeed on tail
|
||||
* pages.
|
||||
*/
|
||||
atomic_t _mapcount;
|
||||
|
||||
struct {
|
||||
unsigned inuse:16;
|
||||
|
|
32
include/linux/pps-gpio.h
Normal file
32
include/linux/pps-gpio.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* pps-gpio.h -- PPS client for GPIOs
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _PPS_GPIO_H
|
||||
#define _PPS_GPIO_H
|
||||
|
||||
struct pps_gpio_platform_data {
|
||||
bool assert_falling_edge;
|
||||
bool capture_clear;
|
||||
unsigned int gpio_pin;
|
||||
const char *gpio_label;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -39,5 +39,6 @@
|
|||
#define RIO_DID_IDTCPS1616 0x0379
|
||||
#define RIO_DID_IDTVPS1616 0x0377
|
||||
#define RIO_DID_IDTSPS1616 0x0378
|
||||
#define RIO_DID_TSI721 0x80ab
|
||||
|
||||
#endif /* LINUX_RIO_IDS_H */
|
||||
|
|
|
@ -83,13 +83,6 @@ struct seminfo {
|
|||
|
||||
struct task_struct;
|
||||
|
||||
/* One semaphore structure for each semaphore in the system. */
|
||||
struct sem {
|
||||
int semval; /* current value */
|
||||
int sempid; /* pid of last operation */
|
||||
struct list_head sem_pending; /* pending single-sop operations */
|
||||
};
|
||||
|
||||
/* One sem_array data structure for each set of semaphores in the system. */
|
||||
struct sem_array {
|
||||
struct kern_ipc_perm ____cacheline_aligned_in_smp
|
||||
|
@ -103,51 +96,21 @@ struct sem_array {
|
|||
int complex_count; /* pending complex operations */
|
||||
};
|
||||
|
||||
/* One queue for each sleeping process in the system. */
|
||||
struct sem_queue {
|
||||
struct list_head simple_list; /* queue of pending operations */
|
||||
struct list_head list; /* queue of pending operations */
|
||||
struct task_struct *sleeper; /* this process */
|
||||
struct sem_undo *undo; /* undo structure */
|
||||
int pid; /* process id of requesting process */
|
||||
int status; /* completion status of operation */
|
||||
struct sembuf *sops; /* array of pending operations */
|
||||
int nsops; /* number of operations */
|
||||
int alter; /* does the operation alter the array? */
|
||||
};
|
||||
|
||||
/* Each task has a list of undo requests. They are executed automatically
|
||||
* when the process exits.
|
||||
*/
|
||||
struct sem_undo {
|
||||
struct list_head list_proc; /* per-process list: all undos from one process. */
|
||||
/* rcu protected */
|
||||
struct rcu_head rcu; /* rcu struct for sem_undo() */
|
||||
struct sem_undo_list *ulp; /* sem_undo_list for the process */
|
||||
struct list_head list_id; /* per semaphore array list: all undos for one array */
|
||||
int semid; /* semaphore set identifier */
|
||||
short * semadj; /* array of adjustments, one per semaphore */
|
||||
};
|
||||
|
||||
/* sem_undo_list controls shared access to the list of sem_undo structures
|
||||
* that may be shared among all a CLONE_SYSVSEM task group.
|
||||
*/
|
||||
struct sem_undo_list {
|
||||
atomic_t refcnt;
|
||||
spinlock_t lock;
|
||||
struct list_head list_proc;
|
||||
};
|
||||
#ifdef CONFIG_SYSVIPC
|
||||
|
||||
struct sysv_sem {
|
||||
struct sem_undo_list *undo_list;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SYSVIPC
|
||||
|
||||
extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk);
|
||||
extern void exit_sem(struct task_struct *tsk);
|
||||
|
||||
#else
|
||||
|
||||
struct sysv_sem {
|
||||
/* empty */
|
||||
};
|
||||
|
||||
static inline int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -931,6 +931,7 @@ enum
|
|||
#ifdef __KERNEL__
|
||||
#include <linux/list.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
/* For the /proc/sys support */
|
||||
struct ctl_table;
|
||||
|
@ -1011,6 +1012,26 @@ extern int proc_do_large_bitmap(struct ctl_table *, int,
|
|||
* cover common cases.
|
||||
*/
|
||||
|
||||
/* Support for userspace poll() to watch for changes */
|
||||
struct ctl_table_poll {
|
||||
atomic_t event;
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
static inline void *proc_sys_poll_event(struct ctl_table_poll *poll)
|
||||
{
|
||||
return (void *)(unsigned long)atomic_read(&poll->event);
|
||||
}
|
||||
|
||||
void proc_sys_poll_notify(struct ctl_table_poll *poll);
|
||||
|
||||
#define __CTL_TABLE_POLL_INITIALIZER(name) { \
|
||||
.event = ATOMIC_INIT(0), \
|
||||
.wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.wait) }
|
||||
|
||||
#define DEFINE_CTL_TABLE_POLL(name) \
|
||||
struct ctl_table_poll name = __CTL_TABLE_POLL_INITIALIZER(name)
|
||||
|
||||
/* A sysctl table is an array of struct ctl_table: */
|
||||
struct ctl_table
|
||||
{
|
||||
|
@ -1021,6 +1042,7 @@ struct ctl_table
|
|||
struct ctl_table *child;
|
||||
struct ctl_table *parent; /* Automatically set */
|
||||
proc_handler *proc_handler; /* Callback for text formatting */
|
||||
struct ctl_table_poll *poll;
|
||||
void *extra1;
|
||||
void *extra2;
|
||||
};
|
||||
|
|
|
@ -37,6 +37,14 @@ struct new_utsname {
|
|||
#include <linux/nsproxy.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
enum uts_proc {
|
||||
UTS_PROC_OSTYPE,
|
||||
UTS_PROC_OSRELEASE,
|
||||
UTS_PROC_VERSION,
|
||||
UTS_PROC_HOSTNAME,
|
||||
UTS_PROC_DOMAINNAME,
|
||||
};
|
||||
|
||||
struct user_namespace;
|
||||
extern struct user_namespace init_user_ns;
|
||||
|
||||
|
@ -80,6 +88,14 @@ static inline struct uts_namespace *copy_utsname(unsigned long flags,
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_SYSCTL
|
||||
extern void uts_proc_notify(enum uts_proc proc);
|
||||
#else
|
||||
static inline void uts_proc_notify(enum uts_proc proc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline struct new_utsname *utsname(void)
|
||||
{
|
||||
return ¤t->nsproxy->uts_ns->name;
|
||||
|
|
|
@ -947,7 +947,7 @@ config UID16
|
|||
config SYSCTL_SYSCALL
|
||||
bool "Sysctl syscall support" if EXPERT
|
||||
depends on PROC_SYSCTL
|
||||
default y
|
||||
default n
|
||||
select SYSCTL
|
||||
---help---
|
||||
sys_sysctl uses binary paths that have been found challenging
|
||||
|
@ -959,7 +959,7 @@ config SYSCTL_SYSCALL
|
|||
trying to save some space it is probably safe to disable this,
|
||||
making your kernel marginally smaller.
|
||||
|
||||
If unsure say Y here.
|
||||
If unsure say N here.
|
||||
|
||||
config KALLSYMS
|
||||
bool "Load all symbols for debugging/ksymoops" if EXPERT
|
||||
|
|
|
@ -28,7 +28,7 @@ int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
|
|||
int root_mountflags = MS_RDONLY | MS_SILENT;
|
||||
static char * __initdata root_device_name;
|
||||
static char __initdata saved_root_name[64];
|
||||
static int __initdata root_wait;
|
||||
static int root_wait;
|
||||
|
||||
dev_t ROOT_DEV;
|
||||
|
||||
|
@ -85,12 +85,15 @@ static int match_dev_by_uuid(struct device *dev, void *data)
|
|||
|
||||
/**
|
||||
* devt_from_partuuid - looks up the dev_t of a partition by its UUID
|
||||
* @uuid: 36 byte char array containing a hex ascii UUID
|
||||
* @uuid: min 36 byte char array containing a hex ascii UUID
|
||||
*
|
||||
* The function will return the first partition which contains a matching
|
||||
* UUID value in its partition_meta_info struct. This does not search
|
||||
* by filesystem UUIDs.
|
||||
*
|
||||
* If @uuid is followed by a "/PARTNROFF=%d", then the number will be
|
||||
* extracted and used as an offset from the partition identified by the UUID.
|
||||
*
|
||||
* Returns the matching dev_t on success or 0 on failure.
|
||||
*/
|
||||
static dev_t devt_from_partuuid(char *uuid_str)
|
||||
|
@ -98,6 +101,28 @@ static dev_t devt_from_partuuid(char *uuid_str)
|
|||
dev_t res = 0;
|
||||
struct device *dev = NULL;
|
||||
u8 uuid[16];
|
||||
struct gendisk *disk;
|
||||
struct hd_struct *part;
|
||||
int offset = 0;
|
||||
|
||||
if (strlen(uuid_str) < 36)
|
||||
goto done;
|
||||
|
||||
/* Check for optional partition number offset attributes. */
|
||||
if (uuid_str[36]) {
|
||||
char c = 0;
|
||||
/* Explicitly fail on poor PARTUUID syntax. */
|
||||
if (sscanf(&uuid_str[36],
|
||||
"/PARTNROFF=%d%c", &offset, &c) != 1) {
|
||||
printk(KERN_ERR "VFS: PARTUUID= is invalid.\n"
|
||||
"Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
|
||||
if (root_wait)
|
||||
printk(KERN_ERR
|
||||
"Disabling rootwait; root= is invalid.\n");
|
||||
root_wait = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pack the requested UUID in the expected format. */
|
||||
part_pack_uuid(uuid_str, uuid);
|
||||
|
@ -107,8 +132,21 @@ static dev_t devt_from_partuuid(char *uuid_str)
|
|||
goto done;
|
||||
|
||||
res = dev->devt;
|
||||
put_device(dev);
|
||||
|
||||
/* Attempt to find the partition by offset. */
|
||||
if (!offset)
|
||||
goto no_offset;
|
||||
|
||||
res = 0;
|
||||
disk = part_to_disk(dev_to_part(dev));
|
||||
part = disk_get_part(disk, dev_to_part(dev)->partno + offset);
|
||||
if (part) {
|
||||
res = part_devt(part);
|
||||
put_device(part_to_dev(part));
|
||||
}
|
||||
|
||||
no_offset:
|
||||
put_device(dev);
|
||||
done:
|
||||
return res;
|
||||
}
|
||||
|
@ -126,6 +164,8 @@ static dev_t devt_from_partuuid(char *uuid_str)
|
|||
* used when disk name of partitioned disk ends on a digit.
|
||||
* 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
|
||||
* unique id of a partition if the partition table provides it.
|
||||
* 7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
|
||||
* a partition with a known unique id.
|
||||
*
|
||||
* If name doesn't have fall into the categories above, we return (0,0).
|
||||
* block_class is used to check if something is a disk name. If the disk
|
||||
|
@ -143,8 +183,6 @@ dev_t name_to_dev_t(char *name)
|
|||
#ifdef CONFIG_BLOCK
|
||||
if (strncmp(name, "PARTUUID=", 9) == 0) {
|
||||
name += 9;
|
||||
if (strlen(name) != 36)
|
||||
goto fail;
|
||||
res = devt_from_partuuid(name);
|
||||
if (!res)
|
||||
goto fail;
|
||||
|
|
|
@ -119,6 +119,20 @@ identify_ramdisk_image(int fd, int start_block, decompress_fn *decompressor)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 512 bytes further to check if cramfs is padded
|
||||
*/
|
||||
sys_lseek(fd, start_block * BLOCK_SIZE + 0x200, 0);
|
||||
sys_read(fd, buf, size);
|
||||
|
||||
if (cramfsb->magic == CRAMFS_MAGIC) {
|
||||
printk(KERN_NOTICE
|
||||
"RAMDISK: cramfs filesystem found at block %d\n",
|
||||
start_block);
|
||||
nblocks = (cramfsb->size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read block 1 to test for minix and ext2 superblock
|
||||
*/
|
||||
|
|
56
ipc/sem.c
56
ipc/sem.c
|
@ -90,6 +90,52 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include "util.h"
|
||||
|
||||
/* One semaphore structure for each semaphore in the system. */
|
||||
struct sem {
|
||||
int semval; /* current value */
|
||||
int sempid; /* pid of last operation */
|
||||
struct list_head sem_pending; /* pending single-sop operations */
|
||||
};
|
||||
|
||||
/* One queue for each sleeping process in the system. */
|
||||
struct sem_queue {
|
||||
struct list_head simple_list; /* queue of pending operations */
|
||||
struct list_head list; /* queue of pending operations */
|
||||
struct task_struct *sleeper; /* this process */
|
||||
struct sem_undo *undo; /* undo structure */
|
||||
int pid; /* process id of requesting process */
|
||||
int status; /* completion status of operation */
|
||||
struct sembuf *sops; /* array of pending operations */
|
||||
int nsops; /* number of operations */
|
||||
int alter; /* does *sops alter the array? */
|
||||
};
|
||||
|
||||
/* Each task has a list of undo requests. They are executed automatically
|
||||
* when the process exits.
|
||||
*/
|
||||
struct sem_undo {
|
||||
struct list_head list_proc; /* per-process list: *
|
||||
* all undos from one process
|
||||
* rcu protected */
|
||||
struct rcu_head rcu; /* rcu struct for sem_undo */
|
||||
struct sem_undo_list *ulp; /* back ptr to sem_undo_list */
|
||||
struct list_head list_id; /* per semaphore array list:
|
||||
* all undos for one array */
|
||||
int semid; /* semaphore set identifier */
|
||||
short *semadj; /* array of adjustments */
|
||||
/* one per semaphore */
|
||||
};
|
||||
|
||||
/* sem_undo_list controls shared access to the list of sem_undo structures
|
||||
* that may be shared among all a CLONE_SYSVSEM task group.
|
||||
*/
|
||||
struct sem_undo_list {
|
||||
atomic_t refcnt;
|
||||
spinlock_t lock;
|
||||
struct list_head list_proc;
|
||||
};
|
||||
|
||||
|
||||
#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])
|
||||
|
||||
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
|
||||
|
@ -1426,6 +1472,8 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
|
|||
|
||||
queue.status = -EINTR;
|
||||
queue.sleeper = current;
|
||||
|
||||
sleep_again:
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
sem_unlock(sma);
|
||||
|
||||
|
@ -1460,7 +1508,6 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
|
|||
* Array removed? If yes, leave without sem_unlock().
|
||||
*/
|
||||
if (IS_ERR(sma)) {
|
||||
error = -EIDRM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
|
@ -1479,6 +1526,13 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
|
|||
*/
|
||||
if (timeout && jiffies_left == 0)
|
||||
error = -EAGAIN;
|
||||
|
||||
/*
|
||||
* If the wakeup was spurious, just retry
|
||||
*/
|
||||
if (error == -EINTR && !signal_pending(current))
|
||||
goto sleep_again;
|
||||
|
||||
unlink_queue(sma, &queue);
|
||||
|
||||
out_unlock_free:
|
||||
|
|
|
@ -2027,7 +2027,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
|||
goto out_free_group_list;
|
||||
|
||||
/* prevent changes to the threadgroup list while we take a snapshot. */
|
||||
rcu_read_lock();
|
||||
read_lock(&tasklist_lock);
|
||||
if (!thread_group_leader(leader)) {
|
||||
/*
|
||||
* a race with de_thread from another thread's exec() may strip
|
||||
|
@ -2036,7 +2036,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
|||
* throw this task away and try again (from cgroup_procs_write);
|
||||
* this is "double-double-toil-and-trouble-check locking".
|
||||
*/
|
||||
rcu_read_unlock();
|
||||
read_unlock(&tasklist_lock);
|
||||
retval = -EAGAIN;
|
||||
goto out_free_group_list;
|
||||
}
|
||||
|
@ -2057,7 +2057,7 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
|||
} while_each_thread(leader, tsk);
|
||||
/* remember the number of threads in the array for later. */
|
||||
group_size = i;
|
||||
rcu_read_unlock();
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
/*
|
||||
* step 1: check that we can legitimately attach to the cgroup.
|
||||
|
@ -2135,14 +2135,17 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader)
|
|||
oldcgrp = task_cgroup_from_root(tsk, root);
|
||||
if (cgrp == oldcgrp)
|
||||
continue;
|
||||
/* attach each task to each subsystem */
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss->attach_task)
|
||||
ss->attach_task(cgrp, tsk);
|
||||
}
|
||||
/* if the thread is PF_EXITING, it can just get skipped. */
|
||||
retval = cgroup_task_migrate(cgrp, oldcgrp, tsk, true);
|
||||
BUG_ON(retval != 0 && retval != -ESRCH);
|
||||
if (retval == 0) {
|
||||
/* attach each task to each subsystem */
|
||||
for_each_subsys(root, ss) {
|
||||
if (ss->attach_task)
|
||||
ss->attach_task(cgrp, tsk);
|
||||
}
|
||||
} else {
|
||||
BUG_ON(retval != -ESRCH);
|
||||
}
|
||||
}
|
||||
/* nothing is sensitive to fork() after this point. */
|
||||
|
||||
|
@ -4880,9 +4883,9 @@ void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css)
|
|||
|
||||
rcu_assign_pointer(id->css, NULL);
|
||||
rcu_assign_pointer(css->id, NULL);
|
||||
spin_lock(&ss->id_lock);
|
||||
write_lock(&ss->id_lock);
|
||||
idr_remove(&ss->idr, id->id);
|
||||
spin_unlock(&ss->id_lock);
|
||||
write_unlock(&ss->id_lock);
|
||||
kfree_rcu(id, rcu_head);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(free_css_id);
|
||||
|
@ -4908,10 +4911,10 @@ static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth)
|
|||
error = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
spin_lock(&ss->id_lock);
|
||||
write_lock(&ss->id_lock);
|
||||
/* Don't use 0. allocates an ID of 1-65535 */
|
||||
error = idr_get_new_above(&ss->idr, newid, 1, &myid);
|
||||
spin_unlock(&ss->id_lock);
|
||||
write_unlock(&ss->id_lock);
|
||||
|
||||
/* Returns error when there are no free spaces for new ID.*/
|
||||
if (error) {
|
||||
|
@ -4926,9 +4929,9 @@ static struct css_id *get_new_cssid(struct cgroup_subsys *ss, int depth)
|
|||
return newid;
|
||||
remove_idr:
|
||||
error = -ENOSPC;
|
||||
spin_lock(&ss->id_lock);
|
||||
write_lock(&ss->id_lock);
|
||||
idr_remove(&ss->idr, myid);
|
||||
spin_unlock(&ss->id_lock);
|
||||
write_unlock(&ss->id_lock);
|
||||
err_out:
|
||||
kfree(newid);
|
||||
return ERR_PTR(error);
|
||||
|
@ -4940,7 +4943,7 @@ static int __init_or_module cgroup_init_idr(struct cgroup_subsys *ss,
|
|||
{
|
||||
struct css_id *newid;
|
||||
|
||||
spin_lock_init(&ss->id_lock);
|
||||
rwlock_init(&ss->id_lock);
|
||||
idr_init(&ss->idr);
|
||||
|
||||
newid = get_new_cssid(ss, 0);
|
||||
|
@ -5035,9 +5038,9 @@ css_get_next(struct cgroup_subsys *ss, int id,
|
|||
* scan next entry from bitmap(tree), tmpid is updated after
|
||||
* idr_get_next().
|
||||
*/
|
||||
spin_lock(&ss->id_lock);
|
||||
read_lock(&ss->id_lock);
|
||||
tmp = idr_get_next(&ss->idr, &tmpid);
|
||||
spin_unlock(&ss->id_lock);
|
||||
read_unlock(&ss->id_lock);
|
||||
|
||||
if (!tmp)
|
||||
break;
|
||||
|
|
|
@ -949,6 +949,8 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
|
|||
static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
||||
nodemask_t *newmems)
|
||||
{
|
||||
bool masks_disjoint = !nodes_intersects(*newmems, tsk->mems_allowed);
|
||||
|
||||
repeat:
|
||||
/*
|
||||
* Allow tasks that have access to memory reserves because they have
|
||||
|
@ -963,7 +965,6 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
|||
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
|
||||
mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1);
|
||||
|
||||
|
||||
/*
|
||||
* ensure checking ->mems_allowed_change_disable after setting all new
|
||||
* allowed nodes.
|
||||
|
@ -980,9 +981,11 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
|
|||
|
||||
/*
|
||||
* Allocation of memory is very fast, we needn't sleep when waiting
|
||||
* for the read-side.
|
||||
* for the read-side. No wait is necessary, however, if at least one
|
||||
* node remains unchanged.
|
||||
*/
|
||||
while (ACCESS_ONCE(tsk->mems_allowed_change_disable)) {
|
||||
while (masks_disjoint &&
|
||||
ACCESS_ONCE(tsk->mems_allowed_change_disable)) {
|
||||
task_unlock(tsk);
|
||||
if (!task_curr(tsk))
|
||||
yield();
|
||||
|
|
|
@ -1286,6 +1286,7 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
|
|||
memset(u->nodename + len, 0, sizeof(u->nodename) - len);
|
||||
errno = 0;
|
||||
}
|
||||
uts_proc_notify(UTS_PROC_HOSTNAME);
|
||||
up_write(&uts_sem);
|
||||
return errno;
|
||||
}
|
||||
|
@ -1336,6 +1337,7 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
|
|||
memset(u->domainname + len, 0, sizeof(u->domainname) - len);
|
||||
errno = 0;
|
||||
}
|
||||
uts_proc_notify(UTS_PROC_DOMAINNAME);
|
||||
up_write(&uts_sem);
|
||||
return errno;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <linux/uts.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
static void *get_uts(ctl_table *table, int write)
|
||||
{
|
||||
|
@ -51,12 +52,19 @@ static int proc_do_uts_string(ctl_table *table, int write,
|
|||
uts_table.data = get_uts(table, write);
|
||||
r = proc_dostring(&uts_table,write,buffer,lenp, ppos);
|
||||
put_uts(table, write, uts_table.data);
|
||||
|
||||
if (write)
|
||||
proc_sys_poll_notify(table->poll);
|
||||
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
#define proc_do_uts_string NULL
|
||||
#endif
|
||||
|
||||
static DEFINE_CTL_TABLE_POLL(hostname_poll);
|
||||
static DEFINE_CTL_TABLE_POLL(domainname_poll);
|
||||
|
||||
static struct ctl_table uts_kern_table[] = {
|
||||
{
|
||||
.procname = "ostype",
|
||||
|
@ -85,6 +93,7 @@ static struct ctl_table uts_kern_table[] = {
|
|||
.maxlen = sizeof(init_uts_ns.name.nodename),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_do_uts_string,
|
||||
.poll = &hostname_poll,
|
||||
},
|
||||
{
|
||||
.procname = "domainname",
|
||||
|
@ -92,6 +101,7 @@ static struct ctl_table uts_kern_table[] = {
|
|||
.maxlen = sizeof(init_uts_ns.name.domainname),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_do_uts_string,
|
||||
.poll = &domainname_poll,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
@ -105,6 +115,19 @@ static struct ctl_table uts_root_table[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PROC_SYSCTL
|
||||
/*
|
||||
* Notify userspace about a change in a certain entry of uts_kern_table,
|
||||
* identified by the parameter proc.
|
||||
*/
|
||||
void uts_proc_notify(enum uts_proc proc)
|
||||
{
|
||||
struct ctl_table *table = &uts_kern_table[proc];
|
||||
|
||||
proc_sys_poll_notify(table->poll);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init utsname_sysctl_init(void)
|
||||
{
|
||||
register_sysctl_table(uts_root_table);
|
||||
|
|
11
lib/idr.c
11
lib/idr.c
|
@ -944,6 +944,7 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
|||
{
|
||||
int ret, id;
|
||||
unsigned int max;
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON((int)start < 0);
|
||||
BUG_ON((int)end < 0);
|
||||
|
@ -959,7 +960,7 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
|||
if (!ida_pre_get(ida, gfp_mask))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&simple_ida_lock);
|
||||
spin_lock_irqsave(&simple_ida_lock, flags);
|
||||
ret = ida_get_new_above(ida, start, &id);
|
||||
if (!ret) {
|
||||
if (id > max) {
|
||||
|
@ -969,7 +970,7 @@ int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
|
|||
ret = id;
|
||||
}
|
||||
}
|
||||
spin_unlock(&simple_ida_lock);
|
||||
spin_unlock_irqrestore(&simple_ida_lock, flags);
|
||||
|
||||
if (unlikely(ret == -EAGAIN))
|
||||
goto again;
|
||||
|
@ -985,10 +986,12 @@ EXPORT_SYMBOL(ida_simple_get);
|
|||
*/
|
||||
void ida_simple_remove(struct ida *ida, unsigned int id)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON((int)id < 0);
|
||||
spin_lock(&simple_ida_lock);
|
||||
spin_lock_irqsave(&simple_ida_lock, flags);
|
||||
ida_remove(ida, id);
|
||||
spin_unlock(&simple_ida_lock);
|
||||
spin_unlock_irqrestore(&simple_ida_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(ida_simple_remove);
|
||||
|
||||
|
|
|
@ -990,7 +990,7 @@ struct page *follow_trans_huge_pmd(struct mm_struct *mm,
|
|||
page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT;
|
||||
VM_BUG_ON(!PageCompound(page));
|
||||
if (flags & FOLL_GET)
|
||||
get_page(page);
|
||||
get_page_foll(page);
|
||||
|
||||
out:
|
||||
return page;
|
||||
|
@ -1202,6 +1202,7 @@ static void __split_huge_page_refcount(struct page *page)
|
|||
unsigned long head_index = page->index;
|
||||
struct zone *zone = page_zone(page);
|
||||
int zonestat;
|
||||
int tail_count = 0;
|
||||
|
||||
/* prevent PageLRU to go away from under us, and freeze lru stats */
|
||||
spin_lock_irq(&zone->lru_lock);
|
||||
|
@ -1210,11 +1211,27 @@ static void __split_huge_page_refcount(struct page *page)
|
|||
for (i = 1; i < HPAGE_PMD_NR; i++) {
|
||||
struct page *page_tail = page + i;
|
||||
|
||||
/* tail_page->_count cannot change */
|
||||
atomic_sub(atomic_read(&page_tail->_count), &page->_count);
|
||||
BUG_ON(page_count(page) <= 0);
|
||||
atomic_add(page_mapcount(page) + 1, &page_tail->_count);
|
||||
BUG_ON(atomic_read(&page_tail->_count) <= 0);
|
||||
/* tail_page->_mapcount cannot change */
|
||||
BUG_ON(page_mapcount(page_tail) < 0);
|
||||
tail_count += page_mapcount(page_tail);
|
||||
/* check for overflow */
|
||||
BUG_ON(tail_count < 0);
|
||||
BUG_ON(atomic_read(&page_tail->_count) != 0);
|
||||
/*
|
||||
* tail_page->_count is zero and not changing from
|
||||
* under us. But get_page_unless_zero() may be running
|
||||
* from under us on the tail_page. If we used
|
||||
* atomic_set() below instead of atomic_add(), we
|
||||
* would then run atomic_set() concurrently with
|
||||
* get_page_unless_zero(), and atomic_set() is
|
||||
* implemented in C not using locked ops. spin_unlock
|
||||
* on x86 sometime uses locked ops because of PPro
|
||||
* errata 66, 92, so unless somebody can guarantee
|
||||
* atomic_set() here would be safe on all archs (and
|
||||
* not only on x86), it's safer to use atomic_add().
|
||||
*/
|
||||
atomic_add(page_mapcount(page) + page_mapcount(page_tail) + 1,
|
||||
&page_tail->_count);
|
||||
|
||||
/* after clearing PageTail the gup refcount can be released */
|
||||
smp_mb();
|
||||
|
@ -1232,10 +1249,7 @@ static void __split_huge_page_refcount(struct page *page)
|
|||
(1L << PG_uptodate)));
|
||||
page_tail->flags |= (1L << PG_dirty);
|
||||
|
||||
/*
|
||||
* 1) clear PageTail before overwriting first_page
|
||||
* 2) clear PageTail before clearing PageHead for VM_BUG_ON
|
||||
*/
|
||||
/* clear PageTail before overwriting first_page */
|
||||
smp_wmb();
|
||||
|
||||
/*
|
||||
|
@ -1252,7 +1266,6 @@ static void __split_huge_page_refcount(struct page *page)
|
|||
* status is achieved setting a reserved bit in the
|
||||
* pmd, not by clearing the present bit.
|
||||
*/
|
||||
BUG_ON(page_mapcount(page_tail));
|
||||
page_tail->_mapcount = page->_mapcount;
|
||||
|
||||
BUG_ON(page_tail->mapping);
|
||||
|
@ -1269,6 +1282,8 @@ static void __split_huge_page_refcount(struct page *page)
|
|||
|
||||
lru_add_page_tail(zone, page, page_tail);
|
||||
}
|
||||
atomic_sub(tail_count, &page->_count);
|
||||
BUG_ON(atomic_read(&page->_count) <= 0);
|
||||
|
||||
__dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
|
||||
__mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR);
|
||||
|
|
|
@ -37,6 +37,52 @@ static inline void __put_page(struct page *page)
|
|||
atomic_dec(&page->_count);
|
||||
}
|
||||
|
||||
static inline void __get_page_tail_foll(struct page *page,
|
||||
bool get_page_head)
|
||||
{
|
||||
/*
|
||||
* If we're getting a tail page, the elevated page->_count is
|
||||
* required only in the head page and we will elevate the head
|
||||
* page->_count and tail page->_mapcount.
|
||||
*
|
||||
* We elevate page_tail->_mapcount for tail pages to force
|
||||
* page_tail->_count to be zero at all times to avoid getting
|
||||
* false positives from get_page_unless_zero() with
|
||||
* speculative page access (like in
|
||||
* page_cache_get_speculative()) on tail pages.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0);
|
||||
VM_BUG_ON(atomic_read(&page->_count) != 0);
|
||||
VM_BUG_ON(page_mapcount(page) < 0);
|
||||
if (get_page_head)
|
||||
atomic_inc(&page->first_page->_count);
|
||||
atomic_inc(&page->_mapcount);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is meant to be called as the FOLL_GET operation of
|
||||
* follow_page() and it must be called while holding the proper PT
|
||||
* lock while the pte (or pmd_trans_huge) is still mapping the page.
|
||||
*/
|
||||
static inline void get_page_foll(struct page *page)
|
||||
{
|
||||
if (unlikely(PageTail(page)))
|
||||
/*
|
||||
* This is safe only because
|
||||
* __split_huge_page_refcount() can't run under
|
||||
* get_page_foll() because we hold the proper PT lock.
|
||||
*/
|
||||
__get_page_tail_foll(page, true);
|
||||
else {
|
||||
/*
|
||||
* Getting a normal page or the head of a compound page
|
||||
* requires to already have an elevated page->_count.
|
||||
*/
|
||||
VM_BUG_ON(atomic_read(&page->_count) <= 0);
|
||||
atomic_inc(&page->_count);
|
||||
}
|
||||
}
|
||||
|
||||
extern unsigned long highest_memmap_pfn;
|
||||
|
||||
/*
|
||||
|
|
1008
mm/memcontrol.c
1008
mm/memcontrol.c
File diff suppressed because it is too large
Load diff
|
@ -1503,7 +1503,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
|
|||
}
|
||||
|
||||
if (flags & FOLL_GET)
|
||||
get_page(page);
|
||||
get_page_foll(page);
|
||||
if (flags & FOLL_TOUCH) {
|
||||
if ((flags & FOLL_WRITE) &&
|
||||
!pte_dirty(pte) && !PageDirty(page))
|
||||
|
|
|
@ -133,10 +133,13 @@ struct page *lookup_cgroup_page(struct page_cgroup *pc)
|
|||
static void *__meminit alloc_page_cgroup(size_t size, int nid)
|
||||
{
|
||||
void *addr = NULL;
|
||||
gfp_t flags = GFP_KERNEL | __GFP_NOWARN;
|
||||
|
||||
addr = alloc_pages_exact_nid(nid, size, GFP_KERNEL | __GFP_NOWARN);
|
||||
if (addr)
|
||||
addr = alloc_pages_exact_nid(nid, size, flags);
|
||||
if (addr) {
|
||||
kmemleak_alloc(addr, size, 1, flags);
|
||||
return addr;
|
||||
}
|
||||
|
||||
if (node_state(nid, N_HIGH_MEMORY))
|
||||
addr = vmalloc_node(size, nid);
|
||||
|
@ -357,7 +360,7 @@ struct swap_cgroup_ctrl {
|
|||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
|
||||
static struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
|
||||
|
||||
struct swap_cgroup {
|
||||
unsigned short id;
|
||||
|
|
83
mm/swap.c
83
mm/swap.c
|
@ -78,39 +78,22 @@ static void put_compound_page(struct page *page)
|
|||
{
|
||||
if (unlikely(PageTail(page))) {
|
||||
/* __split_huge_page_refcount can run under us */
|
||||
struct page *page_head = page->first_page;
|
||||
smp_rmb();
|
||||
/*
|
||||
* If PageTail is still set after smp_rmb() we can be sure
|
||||
* that the page->first_page we read wasn't a dangling pointer.
|
||||
* See __split_huge_page_refcount() smp_wmb().
|
||||
*/
|
||||
if (likely(PageTail(page) && get_page_unless_zero(page_head))) {
|
||||
struct page *page_head = compound_trans_head(page);
|
||||
|
||||
if (likely(page != page_head &&
|
||||
get_page_unless_zero(page_head))) {
|
||||
unsigned long flags;
|
||||
/*
|
||||
* Verify that our page_head wasn't converted
|
||||
* to a a regular page before we got a
|
||||
* reference on it.
|
||||
* page_head wasn't a dangling pointer but it
|
||||
* may not be a head page anymore by the time
|
||||
* we obtain the lock. That is ok as long as it
|
||||
* can't be freed from under us.
|
||||
*/
|
||||
if (unlikely(!PageHead(page_head))) {
|
||||
/* PageHead is cleared after PageTail */
|
||||
smp_rmb();
|
||||
VM_BUG_ON(PageTail(page));
|
||||
goto out_put_head;
|
||||
}
|
||||
/*
|
||||
* Only run compound_lock on a valid PageHead,
|
||||
* after having it pinned with
|
||||
* get_page_unless_zero() above.
|
||||
*/
|
||||
smp_mb();
|
||||
/* page_head wasn't a dangling pointer */
|
||||
flags = compound_lock_irqsave(page_head);
|
||||
if (unlikely(!PageTail(page))) {
|
||||
/* __split_huge_page_refcount run before us */
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
VM_BUG_ON(PageHead(page_head));
|
||||
out_put_head:
|
||||
if (put_page_testzero(page_head))
|
||||
__put_single_page(page_head);
|
||||
out_put_single:
|
||||
|
@ -121,16 +104,17 @@ static void put_compound_page(struct page *page)
|
|||
VM_BUG_ON(page_head != page->first_page);
|
||||
/*
|
||||
* We can release the refcount taken by
|
||||
* get_page_unless_zero now that
|
||||
* split_huge_page_refcount is blocked on the
|
||||
* compound_lock.
|
||||
* get_page_unless_zero() now that
|
||||
* __split_huge_page_refcount() is blocked on
|
||||
* the compound_lock.
|
||||
*/
|
||||
if (put_page_testzero(page_head))
|
||||
VM_BUG_ON(1);
|
||||
/* __split_huge_page_refcount will wait now */
|
||||
VM_BUG_ON(atomic_read(&page->_count) <= 0);
|
||||
atomic_dec(&page->_count);
|
||||
VM_BUG_ON(page_mapcount(page) <= 0);
|
||||
atomic_dec(&page->_mapcount);
|
||||
VM_BUG_ON(atomic_read(&page_head->_count) <= 0);
|
||||
VM_BUG_ON(atomic_read(&page->_count) != 0);
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
if (put_page_testzero(page_head)) {
|
||||
if (PageHead(page_head))
|
||||
|
@ -160,6 +144,45 @@ void put_page(struct page *page)
|
|||
}
|
||||
EXPORT_SYMBOL(put_page);
|
||||
|
||||
/*
|
||||
* This function is exported but must not be called by anything other
|
||||
* than get_page(). It implements the slow path of get_page().
|
||||
*/
|
||||
bool __get_page_tail(struct page *page)
|
||||
{
|
||||
/*
|
||||
* This takes care of get_page() if run on a tail page
|
||||
* returned by one of the get_user_pages/follow_page variants.
|
||||
* get_user_pages/follow_page itself doesn't need the compound
|
||||
* lock because it runs __get_page_tail_foll() under the
|
||||
* proper PT lock that already serializes against
|
||||
* split_huge_page().
|
||||
*/
|
||||
unsigned long flags;
|
||||
bool got = false;
|
||||
struct page *page_head = compound_trans_head(page);
|
||||
|
||||
if (likely(page != page_head && get_page_unless_zero(page_head))) {
|
||||
/*
|
||||
* page_head wasn't a dangling pointer but it
|
||||
* may not be a head page anymore by the time
|
||||
* we obtain the lock. That is ok as long as it
|
||||
* can't be freed from under us.
|
||||
*/
|
||||
flags = compound_lock_irqsave(page_head);
|
||||
/* here __split_huge_page_refcount won't run anymore */
|
||||
if (likely(PageTail(page))) {
|
||||
__get_page_tail_foll(page, false);
|
||||
got = true;
|
||||
}
|
||||
compound_unlock_irqrestore(page_head, flags);
|
||||
if (unlikely(!got))
|
||||
put_page(page_head);
|
||||
}
|
||||
return got;
|
||||
}
|
||||
EXPORT_SYMBOL(__get_page_tail);
|
||||
|
||||
/**
|
||||
* put_pages_list() - release a list of pages
|
||||
* @pages: list of pages threaded on page->lru
|
||||
|
|
|
@ -1767,7 +1767,7 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
|
|||
if (scanning_global_lru(sc))
|
||||
low = inactive_anon_is_low_global(zone);
|
||||
else
|
||||
low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup);
|
||||
low = mem_cgroup_inactive_anon_is_low(sc->mem_cgroup, zone);
|
||||
return low;
|
||||
}
|
||||
#else
|
||||
|
@ -1810,7 +1810,7 @@ static int inactive_file_is_low(struct zone *zone, struct scan_control *sc)
|
|||
if (scanning_global_lru(sc))
|
||||
low = inactive_file_is_low_global(zone);
|
||||
else
|
||||
low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup);
|
||||
low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup, zone);
|
||||
return low;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue