Merge branch 'android11-5.4' into android11-5.4-lts

Sync up with android11-5.4 for the following commits:

d0f21836e3 ANDROID: Revert "tracing/ring-buffer: Have polling block on watermark"
5a8d108cc6 Merge "Merge tag 'android11-5.4.226_r00' into android11-5.4" into android11-5.4
c429b23536 UPSTREAM: usb: gadget: f_hid: fix f_hidg lifetime vs cdev
28b985f146 UPSTREAM: usb: gadget: f_hid: optional SETUP/SET_REPORT mode
15a5e4ad4f ANDROID: add TEST_MAPPING for net/, include/net
f5b4a7be57 UPSTREAM: nfp: fix use-after-free in area_cache_get()
5a9d35543f UPSTREAM: proc: avoid integer type confusion in get_proc_long
cffda199e1 UPSTREAM: proc: proc_skip_spaces() shouldn't think it is working on C strings
e418b27c0c ANDROID: usb: f_accessory: Check buffer size when initialised via composite
98d8600199 Merge tag 'android11-5.4.226_r00' into android11-5.4
8912db2538 BACKPORT: mm: don't be stuck to rmap lock on reclaim path
a69a8cd3c5 ANDROID: Add more hvc devices for virtio-console.
7b7c361b98 UPSTREAM: HID: playstation: support updated DualSense rumble mode.
ff79b92f34 UPSTREAM: HID: playstation: add initial DualSense Edge controller support
9c127a4a06 UPSTREAM: HID: playstation: stop DualSense output work on remove.
b32bdd3e88 UPSTREAM: HID: playstation: convert to use dev_groups
c1ac1f8001 UPSTREAM: HID: playstation: fix return from dualsense_player_led_set_brightness()
d44545535e UPSTREAM: HID: playstation: expose DualSense player LEDs through LED class.
07dd46d289 BACKPORT: leds: add new LED_FUNCTION_PLAYER for player LEDs for game controllers.
f91c45c176 UPSTREAM: HID: playstation: expose DualSense lightbar through a multi-color LED.
749207d940 UPSTREAM: leds: flash: Fix multicolor no-ops registration by return 0
3e667a0854 UPSTREAM: leds: multicolor: Introduce a multicolor class definition
0b5ee17e7d ANDROID: GKI: enable mulitcolor-led
0ce03d1655 BACKPORT: Kconfig.debug: provide a little extra FRAME_WARN leeway when KASAN is enabled
20fb10aa4c UPSTREAM: bpf: Ensure correct locking around vulnerable function find_vpid()
0ec485223d UPSTREAM: HID: roccat: Fix use-after-free in roccat_read()
cbbd724281 ANDROID: arm64: mm: perform clean & invalidation in __dma_map_area

Change-Id: I31bed9dd4eb36433c1028ab9073df4839f5a78f6
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman 2023-01-25 17:54:20 +00:00
commit cc162d31ce
25 changed files with 809 additions and 41 deletions

View File

@ -0,0 +1,35 @@
What: /sys/class/leds/<led>/brightness
Date: March 2020
KernelVersion: 5.9
Contact: Dan Murphy <dmurphy@ti.com>
Description: read/write
Writing to this file will update all LEDs within the group to a
calculated percentage of what each color LED intensity is set
to. The percentage is calculated for each grouped LED via the
equation below:
led_brightness = brightness * multi_intensity/max_brightness
For additional details please refer to
Documentation/leds/leds-class-multicolor.rst.
The value of the LED is from 0 to
/sys/class/leds/<led>/max_brightness.
What: /sys/class/leds/<led>/multi_index
Date: March 2020
KernelVersion: 5.9
Contact: Dan Murphy <dmurphy@ti.com>
Description: read
The multi_index array, when read, will output the LED colors
as an array of strings as they are indexed in the
multi_intensity file.
What: /sys/class/leds/<led>/multi_intensity
Date: March 2020
KernelVersion: 5.9
Contact: Dan Murphy <dmurphy@ti.com>
Description: read/write
This file contains array of integers. Order of components is
described by the multi_index array. The maximum intensity should
not exceed /sys/class/leds/<led>/max_brightness.

View File

@ -9,6 +9,7 @@ LEDs
leds-class
leds-class-flash
leds-class-multicolor
ledtrig-oneshot
ledtrig-transient
ledtrig-usbport

View File

@ -0,0 +1,86 @@
.. SPDX-License-Identifier: GPL-2.0
====================================
Multicolor LED handling under Linux
====================================
Description
===========
The multicolor class groups monochrome LEDs and allows controlling two
aspects of the final combined color: hue and lightness. The former is
controlled via the multi_intensity array file and the latter is controlled
via brightness file.
Multicolor Class Control
========================
The multicolor class presents files that groups the colors as indexes in an
array. These files are children under the LED parent node created by the
led_class framework. The led_class framework is documented in led-class.rst
within this documentation directory.
Each colored LED will be indexed under the multi_* files. The order of the
colors will be arbitrary. The multi_index file can be read to determine the
color name to indexed value.
The multi_index file is an array that contains the string list of the colors as
they are defined in each multi_* array file.
The multi_intensity is an array that can be read or written to for the
individual color intensities. All elements within this array must be written in
order for the color LED intensities to be updated.
Directory Layout Example
========================
root:/sys/class/leds/multicolor:status# ls -lR
-rw-r--r-- 1 root root 4096 Oct 19 16:16 brightness
-r--r--r-- 1 root root 4096 Oct 19 16:16 max_brightness
-r--r--r-- 1 root root 4096 Oct 19 16:16 multi_index
-rw-r--r-- 1 root root 4096 Oct 19 16:16 multi_intensity
Multicolor Class Brightness Control
===================================
The brightness level for each LED is calculated based on the color LED
intensity setting divided by the global max_brightness setting multiplied by
the requested brightness.
led_brightness = brightness * multi_intensity/max_brightness
Example:
A user first writes the multi_intensity file with the brightness levels
for each LED that are necessary to achieve a certain color output from a
multicolor LED group.
cat /sys/class/leds/multicolor:status/multi_index
green blue red
echo 43 226 138 > /sys/class/leds/multicolor:status/multi_intensity
red -
intensity = 138
max_brightness = 255
green -
intensity = 43
max_brightness = 255
blue -
intensity = 226
max_brightness = 255
The user can control the brightness of that multicolor LED group by writing the
global 'brightness' control. Assuming a max_brightness of 255 the user
may want to dim the LED color group to half. The user would write a value of
128 to the global brightness file then the values written to each LED will be
adjusted base on this value.
cat /sys/class/leds/multicolor:status/max_brightness
255
echo 128 > /sys/class/leds/multicolor:status/brightness
adjusted_red_value = 128 * 138/255 = 69
adjusted_green_value = 128 * 43/255 = 21
adjusted_blue_value = 128 * 226/255 = 113
Reading the global brightness file will return the current brightness value of
the color LED group.
cat /sys/class/leds/multicolor:status/brightness
128

View File

@ -434,6 +434,7 @@ CONFIG_MMC_CRYPTO=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_LEDS_CLASS_FLASH=y
CONFIG_LEDS_CLASS_MULTICOLOR=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_EDAC=y
CONFIG_RTC_CLASS=y

View File

@ -228,6 +228,8 @@ ENDPIPROC(__dma_flush_area)
* - dir - DMA direction
*/
ENTRY(__dma_map_area)
cmp w2, #DMA_FROM_DEVICE
b.eq __dma_flush_area
b __dma_clean_area
ENDPIPROC(__dma_map_area)

View File

@ -381,6 +381,7 @@ CONFIG_MMC_CRYPTO=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_LEDS_CLASS_FLASH=y
CONFIG_LEDS_CLASS_MULTICOLOR=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_RTC_CLASS=y
CONFIG_DMADEVICES=y

View File

@ -1085,6 +1085,7 @@
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0
#define USB_DEVICE_ID_SONY_PS5_CONTROLLER 0x0ce6
#define USB_DEVICE_ID_SONY_PS5_CONTROLLER_2 0x0df2
#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002

View File

@ -11,6 +11,8 @@
#include <linux/hid.h>
#include <linux/idr.h>
#include <linux/input/mt.h>
#include <linux/leds.h>
#include <linux/led-class-multicolor.h>
#include <linux/module.h>
#include <asm/unaligned.h>
@ -38,11 +40,13 @@ struct ps_device {
uint8_t battery_capacity;
int battery_status;
const char *input_dev_name; /* Name of primary input device. */
uint8_t mac_address[6]; /* Note: stored in little endian order. */
uint32_t hw_version;
uint32_t fw_version;
int (*parse_report)(struct ps_device *dev, struct hid_report *report, u8 *data, int size);
void (*remove)(struct ps_device *dev);
};
/* Calibration data for playstation motion sensors. */
@ -53,6 +57,13 @@ struct ps_calibration_data {
int sens_denom;
};
struct ps_led_info {
const char *name;
const char *color;
enum led_brightness (*brightness_get)(struct led_classdev *cdev);
int (*brightness_set)(struct led_classdev *cdev, enum led_brightness);
};
/* Seed values for DualShock4 / DualSense CRC32 for different report types. */
#define PS_INPUT_CRC32_SEED 0xA1
#define PS_OUTPUT_CRC32_SEED 0xA2
@ -97,6 +108,9 @@ struct ps_calibration_data {
#define DS_STATUS_CHARGING GENMASK(7, 4)
#define DS_STATUS_CHARGING_SHIFT 4
/* Feature version from DualSense Firmware Info report. */
#define DS_FEATURE_VERSION(major, minor) ((major & 0xff) << 8 | (minor & 0xff))
/*
* Status of a DualSense touch point contact.
* Contact IDs, with highest bit set are 'inactive'
@ -115,6 +129,7 @@ struct ps_calibration_data {
#define DS_OUTPUT_VALID_FLAG1_RELEASE_LEDS BIT(3)
#define DS_OUTPUT_VALID_FLAG1_PLAYER_INDICATOR_CONTROL_ENABLE BIT(4)
#define DS_OUTPUT_VALID_FLAG2_LIGHTBAR_SETUP_CONTROL_ENABLE BIT(1)
#define DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2 BIT(2)
#define DS_OUTPUT_POWER_SAVE_CONTROL_MIC_MUTE BIT(4)
#define DS_OUTPUT_LIGHTBAR_SETUP_LIGHT_OUT BIT(1)
@ -132,6 +147,9 @@ struct dualsense {
struct input_dev *sensors;
struct input_dev *touchpad;
/* Update version is used as a feature/capability version. */
uint16_t update_version;
/* Calibration data for accelerometer and gyroscope. */
struct ps_calibration_data accel_calib_data[3];
struct ps_calibration_data gyro_calib_data[3];
@ -142,11 +160,13 @@ struct dualsense {
uint32_t sensor_timestamp_us;
/* Compatible rumble state */
bool use_vibration_v2;
bool update_rumble;
uint8_t motor_left;
uint8_t motor_right;
/* RGB lightbar */
struct led_classdev_mc lightbar;
bool update_lightbar;
uint8_t lightbar_red;
uint8_t lightbar_green;
@ -163,6 +183,7 @@ struct dualsense {
struct led_classdev player_leds[5];
struct work_struct output_worker;
bool output_worker_initialized;
void *output_report_dmabuf;
uint8_t output_seq; /* Sequence number for output report. */
};
@ -288,6 +309,9 @@ static const struct {int x; int y; } ps_gamepad_hat_mapping[] = {
{0, 0},
};
static inline void dualsense_schedule_work(struct dualsense *ds);
static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue);
/*
* Add a new ps_device to ps_devices if it doesn't exist.
* Return error on duplicate device, which can happen if the same
@ -525,6 +549,71 @@ static int ps_get_report(struct hid_device *hdev, uint8_t report_id, uint8_t *bu
return 0;
}
static int ps_led_register(struct ps_device *ps_dev, struct led_classdev *led,
const struct ps_led_info *led_info)
{
int ret;
led->name = devm_kasprintf(&ps_dev->hdev->dev, GFP_KERNEL,
"%s:%s:%s", ps_dev->input_dev_name, led_info->color, led_info->name);
if (!led->name)
return -ENOMEM;
led->brightness = 0;
led->max_brightness = 1;
led->flags = LED_CORE_SUSPENDRESUME;
led->brightness_get = led_info->brightness_get;
led->brightness_set_blocking = led_info->brightness_set;
ret = devm_led_classdev_register(&ps_dev->hdev->dev, led);
if (ret) {
hid_err(ps_dev->hdev, "Failed to register LED %s: %d\n", led_info->name, ret);
return ret;
}
return 0;
}
/* Register a DualSense/DualShock4 RGB lightbar represented by a multicolor LED. */
static int ps_lightbar_register(struct ps_device *ps_dev, struct led_classdev_mc *lightbar_mc_dev,
int (*brightness_set)(struct led_classdev *, enum led_brightness))
{
struct hid_device *hdev = ps_dev->hdev;
struct mc_subled *mc_led_info;
struct led_classdev *led_cdev;
int ret;
mc_led_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_led_info),
GFP_KERNEL | __GFP_ZERO);
if (!mc_led_info)
return -ENOMEM;
mc_led_info[0].color_index = LED_COLOR_ID_RED;
mc_led_info[1].color_index = LED_COLOR_ID_GREEN;
mc_led_info[2].color_index = LED_COLOR_ID_BLUE;
lightbar_mc_dev->subled_info = mc_led_info;
lightbar_mc_dev->num_colors = 3;
led_cdev = &lightbar_mc_dev->led_cdev;
led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s:rgb:indicator",
ps_dev->input_dev_name);
if (!led_cdev->name)
return -ENOMEM;
led_cdev->brightness = 255;
led_cdev->max_brightness = 255;
led_cdev->brightness_set_blocking = brightness_set;
ret = devm_led_classdev_multicolor_register(&hdev->dev, lightbar_mc_dev);
if (ret < 0) {
hid_err(hdev, "Cannot register multicolor LED device\n");
return ret;
}
return 0;
}
static struct input_dev *ps_sensors_create(struct hid_device *hdev, int accel_range, int accel_res,
int gyro_range, int gyro_res)
{
@ -614,15 +703,12 @@ static ssize_t hardware_version_show(struct device *dev,
static DEVICE_ATTR_RO(hardware_version);
static struct attribute *ps_device_attributes[] = {
static struct attribute *ps_device_attrs[] = {
&dev_attr_firmware_version.attr,
&dev_attr_hardware_version.attr,
NULL
};
static const struct attribute_group ps_device_attribute_group = {
.attrs = ps_device_attributes,
};
ATTRIBUTE_GROUPS(ps_device);
static int dualsense_get_calibration_data(struct dualsense *ds)
{
@ -714,6 +800,7 @@ static int dualsense_get_calibration_data(struct dualsense *ds)
return ret;
}
static int dualsense_get_firmware_info(struct dualsense *ds)
{
uint8_t *buf;
@ -733,6 +820,15 @@ static int dualsense_get_firmware_info(struct dualsense *ds)
ds->base.hw_version = get_unaligned_le32(&buf[24]);
ds->base.fw_version = get_unaligned_le32(&buf[28]);
/* Update version is some kind of feature version. It is distinct from
* the firmware version as there can be many different variations of a
* controller over time with the same physical shell, but with different
* PCBs and other internal changes. The update version (internal name) is
* used as a means to detect what features are available and change behavior.
* Note: the version is different between DualSense and DualSense Edge.
*/
ds->update_version = get_unaligned_le16(&buf[44]);
err_free:
kfree(buf);
return ret;
@ -761,6 +857,53 @@ static int dualsense_get_mac_address(struct dualsense *ds)
return ret;
}
static int dualsense_lightbar_set_brightness(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev);
struct dualsense *ds = container_of(mc_cdev, struct dualsense, lightbar);
uint8_t red, green, blue;
led_mc_calc_color_components(mc_cdev, brightness);
red = mc_cdev->subled_info[0].brightness;
green = mc_cdev->subled_info[1].brightness;
blue = mc_cdev->subled_info[2].brightness;
dualsense_set_lightbar(ds, red, green, blue);
return 0;
}
static enum led_brightness dualsense_player_led_get_brightness(struct led_classdev *led)
{
struct hid_device *hdev = to_hid_device(led->dev->parent);
struct dualsense *ds = hid_get_drvdata(hdev);
return !!(ds->player_leds_state & BIT(led - ds->player_leds));
}
static int dualsense_player_led_set_brightness(struct led_classdev *led, enum led_brightness value)
{
struct hid_device *hdev = to_hid_device(led->dev->parent);
struct dualsense *ds = hid_get_drvdata(hdev);
unsigned long flags;
unsigned int led_index;
spin_lock_irqsave(&ds->base.lock, flags);
led_index = led - ds->player_leds;
if (value == LED_OFF)
ds->player_leds_state &= ~BIT(led_index);
else
ds->player_leds_state |= BIT(led_index);
ds->update_player_leds = true;
spin_unlock_irqrestore(&ds->base.lock, flags);
dualsense_schedule_work(ds);
return 0;
}
static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_output_report *rp,
void *buf)
{
@ -800,6 +943,16 @@ static void dualsense_init_output_report(struct dualsense *ds, struct dualsense_
}
}
static inline void dualsense_schedule_work(struct dualsense *ds)
{
unsigned long flags;
spin_lock_irqsave(&ds->base.lock, flags);
if (ds->output_worker_initialized)
schedule_work(&ds->output_worker);
spin_unlock_irqrestore(&ds->base.lock, flags);
}
/*
* Helper function to send DualSense output reports. Applies a CRC at the end of a report
* for Bluetooth reports.
@ -838,7 +991,10 @@ static void dualsense_output_worker(struct work_struct *work)
if (ds->update_rumble) {
/* Select classic rumble style haptics and enable it. */
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_HAPTICS_SELECT;
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION;
if (ds->use_vibration_v2)
common->valid_flag2 |= DS_OUTPUT_VALID_FLAG2_COMPATIBLE_VIBRATION2;
else
common->valid_flag0 |= DS_OUTPUT_VALID_FLAG0_COMPATIBLE_VIBRATION;
common->motor_left = ds->motor_left;
common->motor_right = ds->motor_right;
ds->update_rumble = false;
@ -960,7 +1116,7 @@ static int dualsense_parse_report(struct ps_device *ps_dev, struct hid_report *r
spin_unlock_irqrestore(&ps_dev->lock, flags);
/* Schedule updating of microphone state at hardware level. */
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
ds->last_btn_mic_state = btn_mic_state;
@ -1075,10 +1231,22 @@ static int dualsense_play_effect(struct input_dev *dev, void *data, struct ff_ef
ds->motor_right = effect->u.rumble.weak_magnitude / 256;
spin_unlock_irqrestore(&ds->base.lock, flags);
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
return 0;
}
static void dualsense_remove(struct ps_device *ps_dev)
{
struct dualsense *ds = container_of(ps_dev, struct dualsense, base);
unsigned long flags;
spin_lock_irqsave(&ds->base.lock, flags);
ds->output_worker_initialized = false;
spin_unlock_irqrestore(&ds->base.lock, flags);
cancel_work_sync(&ds->output_worker);
}
static int dualsense_reset_leds(struct dualsense *ds)
{
struct dualsense_output_report report;
@ -1106,12 +1274,16 @@ static int dualsense_reset_leds(struct dualsense *ds)
static void dualsense_set_lightbar(struct dualsense *ds, uint8_t red, uint8_t green, uint8_t blue)
{
unsigned long flags;
spin_lock_irqsave(&ds->base.lock, flags);
ds->update_lightbar = true;
ds->lightbar_red = red;
ds->lightbar_green = green;
ds->lightbar_blue = blue;
spin_unlock_irqrestore(&ds->base.lock, flags);
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
static void dualsense_set_player_leds(struct dualsense *ds)
@ -1134,7 +1306,7 @@ static void dualsense_set_player_leds(struct dualsense *ds)
ds->update_player_leds = true;
ds->player_leds_state = player_ids[player_id];
schedule_work(&ds->output_worker);
dualsense_schedule_work(ds);
}
static struct ps_device *dualsense_create(struct hid_device *hdev)
@ -1142,7 +1314,20 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
struct dualsense *ds;
struct ps_device *ps_dev;
uint8_t max_output_report_size;
int ret;
int i, ret;
static const struct ps_led_info player_leds_info[] = {
{ LED_FUNCTION_PLAYER1, "white", dualsense_player_led_get_brightness,
dualsense_player_led_set_brightness },
{ LED_FUNCTION_PLAYER2, "white", dualsense_player_led_get_brightness,
dualsense_player_led_set_brightness },
{ LED_FUNCTION_PLAYER3, "white", dualsense_player_led_get_brightness,
dualsense_player_led_set_brightness },
{ LED_FUNCTION_PLAYER4, "white", dualsense_player_led_get_brightness,
dualsense_player_led_set_brightness },
{ LED_FUNCTION_PLAYER5, "white", dualsense_player_led_get_brightness,
dualsense_player_led_set_brightness }
};
ds = devm_kzalloc(&hdev->dev, sizeof(*ds), GFP_KERNEL);
if (!ds)
@ -1160,7 +1345,9 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
ps_dev->battery_capacity = 100; /* initial value until parse_report. */
ps_dev->battery_status = POWER_SUPPLY_STATUS_UNKNOWN;
ps_dev->parse_report = dualsense_parse_report;
ps_dev->remove = dualsense_remove;
INIT_WORK(&ds->output_worker, dualsense_output_worker);
ds->output_worker_initialized = true;
hid_set_drvdata(hdev, ds);
max_output_report_size = sizeof(struct dualsense_output_report_bt);
@ -1181,6 +1368,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
return ERR_PTR(ret);
}
/* Original DualSense firmware simulated classic controller rumble through
* its new haptics hardware. It felt different from classic rumble users
* were used to. Since then new firmwares were introduced to change behavior
* and make this new 'v2' behavior default on PlayStation and other platforms.
* The original DualSense requires a new enough firmware as bundled with PS5
* software released in 2021. DualSense edge supports it out of the box.
* Both devices also support the old mode, but it is not really used.
*/
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
/* Feature version 2.21 introduced new vibration method. */
ds->use_vibration_v2 = ds->update_version >= DS_FEATURE_VERSION(2, 21);
} else if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
ds->use_vibration_v2 = true;
}
ret = ps_devices_list_add(ps_dev);
if (ret)
return ERR_PTR(ret);
@ -1196,6 +1398,8 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
ret = PTR_ERR(ds->gamepad);
goto err;
}
/* Use gamepad input device name as primary device name for e.g. LEDs */
ps_dev->input_dev_name = dev_name(&ds->gamepad->dev);
ds->sensors = ps_sensors_create(hdev, DS_ACC_RANGE, DS_ACC_RES_PER_G,
DS_GYRO_RANGE, DS_GYRO_RES_PER_DEG_S);
@ -1223,8 +1427,21 @@ static struct ps_device *dualsense_create(struct hid_device *hdev)
if (ret)
goto err;
ret = ps_lightbar_register(ps_dev, &ds->lightbar, dualsense_lightbar_set_brightness);
if (ret)
goto err;
/* Set default lightbar color. */
dualsense_set_lightbar(ds, 0, 0, 128); /* blue */
for (i = 0; i < ARRAY_SIZE(player_leds_info); i++) {
const struct ps_led_info *led_info = &player_leds_info[i];
ret = ps_led_register(ps_dev, &ds->player_leds[i], led_info);
if (ret < 0)
goto err;
}
ret = ps_device_set_player_id(ps_dev);
if (ret) {
hid_err(hdev, "Failed to assign player id for DualSense: %d\n", ret);
@ -1282,7 +1499,8 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
}
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER) {
if (hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER ||
hdev->product == USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) {
dev = dualsense_create(hdev);
if (IS_ERR(dev)) {
hid_err(hdev, "Failed to create dualsense.\n");
@ -1291,12 +1509,6 @@ static int ps_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
ret = devm_device_add_group(&hdev->dev, &ps_device_attribute_group);
if (ret) {
hid_err(hdev, "Failed to register sysfs nodes.\n");
goto err_close;
}
return ret;
err_close:
@ -1313,6 +1525,9 @@ static void ps_remove(struct hid_device *hdev)
ps_devices_list_remove(dev);
ps_device_release_player_id(dev);
if (dev->remove)
dev->remove(dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
@ -1320,6 +1535,8 @@ static void ps_remove(struct hid_device *hdev)
static const struct hid_device_id ps_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS5_CONTROLLER_2) },
{ }
};
MODULE_DEVICE_TABLE(hid, ps_devices);
@ -1330,6 +1547,9 @@ static struct hid_driver ps_driver = {
.probe = ps_probe,
.remove = ps_remove,
.raw_event = ps_raw_event,
.driver = {
.dev_groups = ps_device_groups,
},
};
static int __init ps_init(void)

View File

@ -30,6 +30,16 @@ config LEDS_CLASS_FLASH
for the flash related features of a LED device. It can be built
as a module.
config LEDS_CLASS_MULTICOLOR
tristate "LED Multicolor Class Support"
depends on LEDS_CLASS
help
This option enables the multicolor LED sysfs class in /sys/class/leds.
It wraps LED class and adds multicolor LED specific sysfs attributes
and kernel internal API to it. You'll need this to provide support
for multicolor LEDs that are grouped together. This class is not
intended for single color LEDs. It can be built as a module.
config LEDS_BRIGHTNESS_HW_CHANGED
bool "LED Class brightness_hw_changed attribute support"
depends on LEDS_CLASS

View File

@ -4,6 +4,7 @@
obj-$(CONFIG_NEW_LEDS) += led-core.o
obj-$(CONFIG_LEDS_CLASS) += led-class.o
obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o
obj-$(CONFIG_LEDS_CLASS_MULTICOLOR) += led-class-multicolor.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers

View File

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0
// LED Multicolor class interface
// Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
// Author: Dan Murphy <dmurphy@ti.com>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/led-class-multicolor.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "leds.h"
int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
enum led_brightness brightness)
{
struct led_classdev *led_cdev = &mcled_cdev->led_cdev;
int i;
for (i = 0; i < mcled_cdev->num_colors; i++)
mcled_cdev->subled_info[i].brightness = brightness *
mcled_cdev->subled_info[i].intensity /
led_cdev->max_brightness;
return 0;
}
EXPORT_SYMBOL_GPL(led_mc_calc_color_components);
static ssize_t multi_intensity_store(struct device *dev,
struct device_attribute *intensity_attr,
const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
int nrchars, offset = 0;
int intensity_value[LED_COLOR_ID_MAX];
int i;
ssize_t ret;
mutex_lock(&led_cdev->led_access);
for (i = 0; i < mcled_cdev->num_colors; i++) {
ret = sscanf(buf + offset, "%i%n",
&intensity_value[i], &nrchars);
if (ret != 1) {
ret = -EINVAL;
goto err_out;
}
offset += nrchars;
}
offset++;
if (offset < size) {
ret = -EINVAL;
goto err_out;
}
for (i = 0; i < mcled_cdev->num_colors; i++)
mcled_cdev->subled_info[i].intensity = intensity_value[i];
led_set_brightness(led_cdev, led_cdev->brightness);
ret = size;
err_out:
mutex_unlock(&led_cdev->led_access);
return ret;
}
static ssize_t multi_intensity_show(struct device *dev,
struct device_attribute *intensity_attr,
char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
int len = 0;
int i;
for (i = 0; i < mcled_cdev->num_colors; i++) {
len += sprintf(buf + len, "%d",
mcled_cdev->subled_info[i].intensity);
if (i < mcled_cdev->num_colors - 1)
len += sprintf(buf + len, " ");
}
buf[len++] = '\n';
return len;
}
static DEVICE_ATTR_RW(multi_intensity);
static ssize_t multi_index_show(struct device *dev,
struct device_attribute *multi_index_attr,
char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
int len = 0;
int index;
int i;
for (i = 0; i < mcled_cdev->num_colors; i++) {
index = mcled_cdev->subled_info[i].color_index;
len += sprintf(buf + len, "%s", led_colors[index]);
if (i < mcled_cdev->num_colors - 1)
len += sprintf(buf + len, " ");
}
buf[len++] = '\n';
return len;
}
static DEVICE_ATTR_RO(multi_index);
static struct attribute *led_multicolor_attrs[] = {
&dev_attr_multi_intensity.attr,
&dev_attr_multi_index.attr,
NULL,
};
ATTRIBUTE_GROUPS(led_multicolor);
int led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data)
{
struct led_classdev *led_cdev;
if (!mcled_cdev)
return -EINVAL;
if (mcled_cdev->num_colors <= 0)
return -EINVAL;
if (mcled_cdev->num_colors > LED_COLOR_ID_MAX)
return -EINVAL;
led_cdev = &mcled_cdev->led_cdev;
mcled_cdev->led_cdev.groups = led_multicolor_groups;
return led_classdev_register_ext(parent, led_cdev, init_data);
}
EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);
void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev)
{
if (!mcled_cdev)
return;
led_classdev_unregister(&mcled_cdev->led_cdev);
}
EXPORT_SYMBOL_GPL(led_classdev_multicolor_unregister);
static void devm_led_classdev_multicolor_release(struct device *dev, void *res)
{
led_classdev_multicolor_unregister(*(struct led_classdev_mc **)res);
}
int devm_led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data)
{
struct led_classdev_mc **dr;
int ret;
dr = devres_alloc(devm_led_classdev_multicolor_release,
sizeof(*dr), GFP_KERNEL);
if (!dr)
return -ENOMEM;
ret = led_classdev_multicolor_register_ext(parent, mcled_cdev,
init_data);
if (ret) {
devres_free(dr);
return ret;
}
*dr = mcled_cdev;
devres_add(parent, dr);
return 0;
}
EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_register_ext);
static int devm_led_classdev_multicolor_match(struct device *dev,
void *res, void *data)
{
struct led_classdev_mc **p = res;
if (WARN_ON(!p || !*p))
return 0;
return *p == data;
}
void devm_led_classdev_multicolor_unregister(struct device *dev,
struct led_classdev_mc *mcled_cdev)
{
WARN_ON(devres_release(dev,
devm_led_classdev_multicolor_release,
devm_led_classdev_multicolor_match, mcled_cdev));
}
EXPORT_SYMBOL_GPL(devm_led_classdev_multicolor_unregister);
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
MODULE_DESCRIPTION("Multicolor LED class interface");
MODULE_LICENSE("GPL v2");

View File

@ -16,7 +16,7 @@
#include <linux/usb/ch9.h>
#ifdef CONFIG_USB_CONFIGFS_F_ACC
extern int acc_ctrlrequest(struct usb_composite_dev *cdev,
extern int acc_ctrlrequest_composite(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl);
void acc_disconnect(void);
#endif
@ -1559,7 +1559,7 @@ static int android_setup(struct usb_gadget *gadget,
#ifdef CONFIG_USB_CONFIGFS_F_ACC
if (value < 0)
value = acc_ctrlrequest(cdev, c);
value = acc_ctrlrequest_composite(cdev, c);
#endif
if (value < 0)

View File

@ -1006,6 +1006,26 @@ int acc_ctrlrequest(struct usb_composite_dev *cdev,
}
EXPORT_SYMBOL_GPL(acc_ctrlrequest);
int acc_ctrlrequest_composite(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
u16 w_length = le16_to_cpu(ctrl->wLength);
if (w_length > USB_COMP_EP0_BUFSIZ) {
if (ctrl->bRequestType & USB_DIR_IN) {
/* Cast away the const, we are going to overwrite on purpose. */
__le16 *temp = (__le16 *)&ctrl->wLength;
*temp = cpu_to_le16(USB_COMP_EP0_BUFSIZ);
w_length = USB_COMP_EP0_BUFSIZ;
} else {
return -EINVAL;
}
}
return acc_ctrlrequest(cdev, ctrl);
}
EXPORT_SYMBOL_GPL(acc_ctrlrequest_composite);
static int
__acc_function_bind(struct usb_configuration *c,
struct usb_function *f, bool configfs)

View File

@ -58,6 +58,11 @@
#define LED_FUNCTION_MUTE "mute"
#define LED_FUNCTION_NUMLOCK "numlock"
#define LED_FUNCTION_PANIC "panic"
#define LED_FUNCTION_PLAYER1 "player-1"
#define LED_FUNCTION_PLAYER2 "player-2"
#define LED_FUNCTION_PLAYER3 "player-3"
#define LED_FUNCTION_PLAYER4 "player-4"
#define LED_FUNCTION_PLAYER5 "player-5"
#define LED_FUNCTION_PROGRAMMING "programming"
#define LED_FUNCTION_POWER "power"
#define LED_FUNCTION_RX "rx"

View File

@ -554,6 +554,11 @@ static inline void i_mmap_unlock_write(struct address_space *mapping)
up_write(&mapping->i_mmap_rwsem);
}
static inline int i_mmap_trylock_read(struct address_space *mapping)
{
return down_read_trylock(&mapping->i_mmap_rwsem);
}
static inline void i_mmap_lock_read(struct address_space *mapping)
{
down_read(&mapping->i_mmap_rwsem);

View File

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* LED Multicolor class interface
* Copyright (C) 2019-20 Texas Instruments Incorporated - http://www.ti.com/
*/
#ifndef _LINUX_MULTICOLOR_LEDS_H_INCLUDED
#define _LINUX_MULTICOLOR_LEDS_H_INCLUDED
#include <linux/leds.h>
#include <dt-bindings/leds/common.h>
struct mc_subled {
unsigned int color_index;
unsigned int brightness;
unsigned int intensity;
unsigned int channel;
};
struct led_classdev_mc {
/* led class device */
struct led_classdev led_cdev;
unsigned int num_colors;
struct mc_subled *subled_info;
};
static inline struct led_classdev_mc *lcdev_to_mccdev(
struct led_classdev *led_cdev)
{
return container_of(led_cdev, struct led_classdev_mc, led_cdev);
}
#if IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR)
/**
* led_classdev_multicolor_register_ext - register a new object of led_classdev
* class with support for multicolor LEDs
* @parent: the multicolor LED to register
* @mcled_cdev: the led_classdev_mc structure for this device
* @init_data: the LED class multicolor device initialization data
*
* Returns: 0 on success or negative error value on failure
*/
int led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data);
/**
* led_classdev_multicolor_unregister - unregisters an object of led_classdev
* class with support for multicolor LEDs
* @mcled_cdev: the multicolor LED to unregister
*
* Unregister a previously registered via led_classdev_multicolor_register
* object
*/
void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev);
/* Calculate brightness for the monochrome LED cluster */
int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
enum led_brightness brightness);
int devm_led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data);
void devm_led_classdev_multicolor_unregister(struct device *parent,
struct led_classdev_mc *mcled_cdev);
#else
static inline int led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data)
{
return 0;
}
static inline void led_classdev_multicolor_unregister(struct led_classdev_mc *mcled_cdev) {};
static inline int led_mc_calc_color_components(struct led_classdev_mc *mcled_cdev,
enum led_brightness brightness)
{
return 0;
}
static inline int devm_led_classdev_multicolor_register_ext(struct device *parent,
struct led_classdev_mc *mcled_cdev,
struct led_init_data *init_data)
{
return 0;
}
static inline void devm_led_classdev_multicolor_unregister(struct device *parent,
struct led_classdev_mc *mcled_cdev)
{};
#endif /* IS_ENABLED(CONFIG_LEDS_CLASS_MULTICOLOR) */
static inline int led_classdev_multicolor_register(struct device *parent,
struct led_classdev_mc *mcled_cdev)
{
return led_classdev_multicolor_register_ext(parent, mcled_cdev, NULL);
}
static inline int devm_led_classdev_multicolor_register(struct device *parent,
struct led_classdev_mc *mcled_cdev)
{
return devm_led_classdev_multicolor_register_ext(parent, mcled_cdev,
NULL);
}
#endif /* _LINUX_MULTICOLOR_LEDS_H_INCLUDED */

View File

@ -131,6 +131,11 @@ static inline void anon_vma_lock_read(struct anon_vma *anon_vma)
down_read(&anon_vma->root->rwsem);
}
static inline int anon_vma_trylock_read(struct anon_vma *anon_vma)
{
return down_read_trylock(&anon_vma->root->rwsem);
}
static inline void anon_vma_unlock_read(struct anon_vma *anon_vma)
{
up_read(&anon_vma->root->rwsem);
@ -245,17 +250,14 @@ void try_to_munlock(struct page *);
void remove_migration_ptes(struct page *old, struct page *new, bool locked);
/*
* Called by memory-failure.c to kill processes.
*/
struct anon_vma *page_lock_anon_vma_read(struct page *page);
void page_unlock_anon_vma_read(struct anon_vma *anon_vma);
int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
/*
* rmap_walk_control: To control rmap traversing for specific needs
*
* arg: passed to rmap_one() and invalid_vma()
* try_lock: bail out if the rmap lock is contended
* contended: indicate the rmap traversal bailed out due to lock contention
* rmap_one: executed on each vma where page is mapped
* done: for checking traversing termination condition
* anon_lock: for getting anon_lock by optimized way rather than default
@ -263,6 +265,8 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma);
*/
struct rmap_walk_control {
void *arg;
bool try_lock;
bool contended;
/*
* Return false if page table scanning in rmap_walk should be stopped.
* Otherwise, return true.
@ -270,13 +274,21 @@ struct rmap_walk_control {
bool (*rmap_one)(struct page *page, struct vm_area_struct *vma,
unsigned long addr, void *arg);
int (*done)(struct page *page);
struct anon_vma *(*anon_lock)(struct page *page);
struct anon_vma *(*anon_lock)(struct page *page,
struct rmap_walk_control *rwc);
bool (*invalid_vma)(struct vm_area_struct *vma, void *arg);
};
void rmap_walk(struct page *page, struct rmap_walk_control *rwc);
void rmap_walk_locked(struct page *page, struct rmap_walk_control *rwc);
/*
* Called by memory-failure.c to kill processes.
*/
struct anon_vma *page_lock_anon_vma_read(struct page *page,
struct rmap_walk_control *rwc);
void page_unlock_anon_vma_read(struct anon_vma *anon_vma);
#else /* !CONFIG_MMU */
#define anon_vma_init() do {} while (0)

7
include/net/TEST_MAPPING Normal file
View File

@ -0,0 +1,7 @@
{
"presubmit": [
{
"name": "CtsNetTestCases"
}
]
}

View File

@ -1606,7 +1606,7 @@ vm_fault_t do_huge_pmd_numa_page(struct vm_fault *vmf, pmd_t pmd)
*/
get_page(page);
spin_unlock(vmf->ptl);
anon_vma = page_lock_anon_vma_read(page);
anon_vma = page_lock_anon_vma_read(page, NULL);
/* Confirm the PMD did not change while page_table_lock was released */
spin_lock(vmf->ptl);

View File

@ -2620,7 +2620,13 @@ void rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc)
struct vm_area_struct *vma;
cond_resched();
anon_vma_lock_read(anon_vma);
if (!anon_vma_trylock_read(anon_vma)) {
if (rwc->try_lock) {
rwc->contended = true;
return;
}
anon_vma_lock_read(anon_vma);
}
anon_vma_interval_tree_foreach(vmac, &anon_vma->rb_root,
0, ULONG_MAX) {
unsigned long addr;

View File

@ -443,7 +443,7 @@ static void collect_procs_anon(struct page *page, struct list_head *to_kill,
struct anon_vma *av;
pgoff_t pgoff;
av = page_lock_anon_vma_read(page);
av = page_lock_anon_vma_read(page, NULL);
if (av == NULL) /* Not actually mapped anymore */
return;

View File

@ -95,10 +95,10 @@ static bool page_idle_clear_pte_refs_one(struct page *page,
static void page_idle_clear_pte_refs(struct page *page)
{
/*
* Since rwc.arg is unused, rwc is effectively immutable, so we
* can make it static const to save some cycles and stack.
* Since rwc.try_lock is unused, rwc is effectively immutable, so we
* can make it static to save some cycles and stack.
*/
static const struct rmap_walk_control rwc = {
static struct rmap_walk_control rwc = {
.rmap_one = page_idle_clear_pte_refs_one,
.anon_lock = page_lock_anon_vma_read,
};

View File

@ -503,9 +503,11 @@ struct anon_vma *page_get_anon_vma(struct page *page)
*
* Its a little more complex as it tries to keep the fast path to a single
* atomic op -- the trylock. If we fail the trylock, we fall back to getting a
* reference like with page_get_anon_vma() and then block on the mutex.
* reference like with page_get_anon_vma() and then block on the mutex
* on !rwc->try_lock case.
*/
struct anon_vma *page_lock_anon_vma_read(struct page *page)
struct anon_vma *page_lock_anon_vma_read(struct page *page,
struct rmap_walk_control *rwc)
{
struct anon_vma *anon_vma = NULL;
struct anon_vma *root_anon_vma;
@ -533,6 +535,12 @@ struct anon_vma *page_lock_anon_vma_read(struct page *page)
goto out;
}
if (rwc && rwc->try_lock) {
anon_vma = NULL;
rwc->contended = true;
goto out;
}
/* trylock failed, we got to sleep */
if (!atomic_inc_not_zero(&anon_vma->refcount)) {
anon_vma = NULL;
@ -828,8 +836,10 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)
* @memcg: target memory cgroup
* @vm_flags: collect encountered vma->vm_flags who actually referenced the page
*
* Quick test_and_clear_referenced for all mappings to a page,
* returns the number of ptes which referenced the page.
* Quick test_and_clear_referenced for all mappings of a page,
*
* Return: The number of mappings which referenced the page. Return -1 if
* the function bailed out due to rmap lock contention.
*/
int page_referenced(struct page *page,
int is_locked,
@ -845,6 +855,7 @@ int page_referenced(struct page *page,
.rmap_one = page_referenced_one,
.arg = (void *)&pra,
.anon_lock = page_lock_anon_vma_read,
.try_lock = true,
};
*vm_flags = 0;
@ -875,7 +886,7 @@ int page_referenced(struct page *page,
if (we_locked)
unlock_page(page);
return pra.referenced;
return rwc.contended ? -1 : pra.referenced;
}
static bool page_mkclean_one(struct page *page, struct vm_area_struct *vma,
@ -1810,7 +1821,7 @@ static struct anon_vma *rmap_walk_anon_lock(struct page *page,
struct anon_vma *anon_vma;
if (rwc->anon_lock)
return rwc->anon_lock(page);
return rwc->anon_lock(page, rwc);
/*
* Note: remove_migration_ptes() cannot use page_lock_anon_vma_read()
@ -1822,7 +1833,17 @@ static struct anon_vma *rmap_walk_anon_lock(struct page *page,
if (!anon_vma)
return NULL;
if (anon_vma_trylock_read(anon_vma))
goto out;
if (rwc->try_lock) {
anon_vma = NULL;
rwc->contended = true;
goto out;
}
anon_vma_lock_read(anon_vma);
out:
return anon_vma;
}
@ -1913,8 +1934,18 @@ static void rmap_walk_file(struct page *page, struct rmap_walk_control *rwc,
pgoff_start = page_to_pgoff(page);
pgoff_end = pgoff_start + hpage_nr_pages(page) - 1;
if (!locked)
if (!locked) {
if (i_mmap_trylock_read(mapping))
goto lookup;
if (rwc->try_lock) {
rwc->contended = true;
return;
}
i_mmap_lock_read(mapping);
}
lookup:
vma_interval_tree_foreach(vma, &mapping->i_mmap,
pgoff_start, pgoff_end) {
unsigned long address = vma_address(page, vma);

View File

@ -1048,6 +1048,10 @@ static enum page_references page_check_references(struct page *page,
if (vm_flags & VM_LOCKED)
return PAGEREF_RECLAIM;
/* rmap lock contention: rotate */
if (referenced_ptes == -1)
return PAGEREF_KEEP;
if (referenced_ptes) {
if (PageSwapBacked(page))
return PAGEREF_ACTIVATE;
@ -2094,9 +2098,9 @@ static void shrink_active_list(unsigned long nr_to_scan,
}
}
/* Referenced or rmap lock contention: rotate */
if (page_referenced(page, 0, sc->target_mem_cgroup,
&vm_flags)) {
nr_rotated += hpage_nr_pages(page);
&vm_flags) != 0) {
/*
* Identify referenced, file-backed active pages and
* give them one more trip around the active list. So
@ -2107,6 +2111,7 @@ static void shrink_active_list(unsigned long nr_to_scan,
* so we ignore them here.
*/
if ((vm_flags & VM_EXEC) && page_is_file_cache(page)) {
nr_rotated += hpage_nr_pages(page);
list_add(&page->lru, &l_active);
continue;
}

7
net/TEST_MAPPING Normal file
View File

@ -0,0 +1,7 @@
{
"presubmit": [
{
"name": "CtsNetTestCases"
}
]
}