aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2020-10-08 04:21:11 -0700
committerLinux Build Service Account <lnxbuild@localhost>2020-10-08 04:21:11 -0700
commit69c4fe62aaa30faf615733708e40178be50fec48 (patch)
treed68628a18d5ac90475207e891bba3bf0aa14a748
parent0a7732be5c7cbd80c9f9fe45582e1c01d05d3b16 (diff)
parenta0f5b3e5ccde8ab41509e82687aa7898c240d859 (diff)
Merge a0f5b3e5ccde8ab41509e82687aa7898c240d859 on remote branchLA.UM.8.15.r1-06900-KAMORTA.0
Change-Id: If4da805a96fdb859b6a3b5b85644ada2b4bdc41a
-rw-r--r--arch/arm/mm/dma-mapping.c18
-rw-r--r--drivers/gpu/msm/kgsl_pwrctrl.c6
-rw-r--r--drivers/power/supply/qcom/smb5-lib.c21
-rw-r--r--drivers/power/supply/qcom/smblite-lib.c67
-rw-r--r--drivers/power/supply/qcom/smblite-lib.h1
-rw-r--r--drivers/usb/phy/phy-msm-qusb.c126
-rw-r--r--mm/slub.c99
7 files changed, 294 insertions, 44 deletions
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 98503d534d4e..f4ae01f453df 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -130,6 +130,10 @@ static void *arm_dma_remap(struct device *dev, void *cpu_addr,
static void arm_dma_unremap(struct device *dev, void *remapped_addr,
size_t size);
+static void arm_iommu_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nents, enum dma_data_direction dir);
+static void arm_iommu_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sg, int nents, enum dma_data_direction dir);
static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
bool coherent)
@@ -1976,6 +1980,9 @@ int arm_iommu_map_sg(struct device *dev, struct scatterlist *sg,
current_offset += s->length;
}
+ if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
+ arm_iommu_sync_sg_for_device(dev, sg, nents, dir);
+
return nents;
}
@@ -2031,6 +2038,9 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
unsigned int total_length = sg_dma_len(sg);
dma_addr_t iova = sg_dma_address(sg);
+ if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
+ arm_iommu_sync_sg_for_cpu(dev, sg, nents, dir);
+
total_length = PAGE_ALIGN((iova & ~PAGE_MASK) + total_length);
iova &= PAGE_MASK;
@@ -2045,8 +2055,8 @@ void arm_iommu_unmap_sg(struct device *dev, struct scatterlist *sg, int nents,
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
+static void arm_iommu_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sg, int nents, enum dma_data_direction dir)
{
struct scatterlist *s;
int i;
@@ -2069,8 +2079,8 @@ void arm_iommu_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
* @nents: number of buffers to map (returned from dma_map_sg)
* @dir: DMA transfer direction (same as was passed to dma_map_sg)
*/
-void arm_iommu_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction dir)
+static void arm_iommu_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nents, enum dma_data_direction dir)
{
struct scatterlist *s;
int i;
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 606c8b63b0a4..8db173a049f0 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -669,12 +669,12 @@ void kgsl_pwrctrl_pwrlevel_change(struct kgsl_device *device,
if (pwr->gpu_bimc_int_clk) {
if (pwr->active_pwrlevel == 0 &&
!pwr->gpu_bimc_interface_enabled) {
- kgsl_pwrctrl_clk_set_rate(pwr->gpu_bimc_int_clk,
- pwr->gpu_bimc_int_clk_freq,
- "bimc_gpu_clk");
_bimc_clk_prepare_enable(device,
pwr->gpu_bimc_int_clk,
"bimc_gpu_clk");
+ kgsl_pwrctrl_clk_set_rate(pwr->gpu_bimc_int_clk,
+ pwr->gpu_bimc_int_clk_freq,
+ "bimc_gpu_clk");
pwr->gpu_bimc_interface_enabled = true;
} else if (pwr->previous_pwrlevel == 0
&& pwr->gpu_bimc_interface_enabled) {
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 65bbb08936ce..5895445bc6d4 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -7176,10 +7176,27 @@ static void smblib_uusb_otg_work(struct work_struct *work)
goto out;
}
otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
- if (chg->otg_present != otg)
+ if (chg->otg_present != otg) {
+ if (otg) {
+ /* otg cable inserted */
+ if (chg->typec_port) {
+ typec_partner_register(chg);
+ typec_set_data_role(chg->typec_port,
+ TYPEC_HOST);
+ typec_set_pwr_role(chg->typec_port,
+ TYPEC_SOURCE);
+ }
+ } else if (chg->typec_port) {
+ /* otg cable removed */
+ typec_set_data_role(chg->typec_port, TYPEC_DEVICE);
+ typec_set_pwr_role(chg->typec_port, TYPEC_SINK);
+ typec_partner_unregister(chg);
+ }
+
smblib_notify_usb_host(chg, otg);
- else
+ } else {
goto out;
+ }
chg->otg_present = otg;
if (!otg)
diff --git a/drivers/power/supply/qcom/smblite-lib.c b/drivers/power/supply/qcom/smblite-lib.c
index d6cd0fed005d..c747f958dce8 100644
--- a/drivers/power/supply/qcom/smblite-lib.c
+++ b/drivers/power/supply/qcom/smblite-lib.c
@@ -440,7 +440,7 @@ static void smblite_lib_uusb_removal(struct smb_charger *chg)
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
- is_flashlite_active(chg) ? USBIN_500UA : USBIN_100UA);
+ is_flashlite_active(chg) ? USBIN_200UA : USBIN_100UA);
vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, false, 0);
/* Remove SW thermal regulation votes */
@@ -1627,6 +1627,14 @@ int smblite_lib_set_prop_current_max(struct smb_charger *chg,
if (chg->real_charger_type != POWER_SUPPLY_TYPE_USB)
return 0;
+ if (is_flashlite_active(chg) && (val->intval >= USBIN_400UA)) {
+ /* For Uusb based SDP port */
+ vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, true,
+ val->intval - USBIN_300UA);
+ smblite_lib_dbg(chg, PR_MISC, "flash_active = 1, ICL set to %d\n",
+ val->intval - USBIN_300UA);
+ }
+
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, true, val->intval);
if (rc < 0) {
pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n", rc);
@@ -1642,12 +1650,6 @@ int smblite_lib_set_prop_current_max(struct smb_charger *chg,
/* Update TypeC Rp based current */
if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
update_sw_icl_max(chg, chg->real_charger_type);
- } else if (is_flashlite_active(chg) && (val->intval >= USBIN_400UA)) {
- /* For Uusb based SDP port */
- vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, true,
- val->intval - USBIN_300UA);
- smblite_lib_dbg(chg, PR_MISC, "flash_active = 1, ICL set to %d\n",
- val->intval - USBIN_300UA);
}
return 0;
@@ -2346,43 +2348,28 @@ static void update_sw_icl_max(struct smb_charger *chg,
/* rp-std or legacy, USB BC 1.2 */
switch (type) {
case POWER_SUPPLY_TYPE_USB:
- /*
- * USB_PSY will vote to increase the current to 500/900mA once
- * enumeration is done.
- */
- if (!is_client_vote_enabled(chg->usb_icl_votable,
- USB_PSY_VOTER)) {
- /* if flash is active force 500mA */
- vote(chg->usb_icl_votable, USB_PSY_VOTER, true,
- is_flashlite_active(chg) ?
- USBIN_500UA : USBIN_100UA);
- }
vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
break;
case POWER_SUPPLY_TYPE_USB_CDP:
- vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
- CDP_CURRENT_UA);
+ icl_ua = CDP_CURRENT_UA;
break;
case POWER_SUPPLY_TYPE_USB_DCP:
- rp_ua = get_rp_based_dcp_current(chg, typec_mode);
- vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua);
+ icl_ua = get_rp_based_dcp_current(chg, typec_mode);
break;
case POWER_SUPPLY_TYPE_UNKNOWN:
default:
- vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
- USBIN_100UA);
+ icl_ua = USBIN_100UA;
break;
}
- if (is_flashlite_active(chg)) {
- icl_ua = get_effective_result(chg->usb_icl_votable);
- if (icl_ua >= USBIN_400UA) {
- vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, true,
+ if (is_flashlite_active(chg) && type != POWER_SUPPLY_TYPE_USB) {
+ vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, true,
icl_ua - USBIN_300UA);
- smblite_lib_dbg(chg, PR_MISC, "flash_active = 1 ICL is set to %d\n",
- icl_ua - USBIN_300UA);
- }
+ smblite_lib_dbg(chg, PR_MISC, "flash_active = 1 ICL is set to %d\n",
+ icl_ua - USBIN_300UA);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, icl_ua);
}
+
}
static void typec_sink_insertion(struct smb_charger *chg)
@@ -2595,7 +2582,7 @@ static void typec_src_removal(struct smb_charger *chg)
/* reset input current limit voters */
vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
- is_flashlite_active(chg) ? USBIN_500UA : USBIN_100UA);
+ is_flashlite_active(chg) ? USBIN_200UA : USBIN_100UA);
vote(chg->usb_icl_votable, FLASH_ACTIVE_VOTER, false, 0);
vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
@@ -2907,6 +2894,22 @@ irqreturn_t smblite_usb_id_irq_handler(int irq, void *data)
smblite_lib_dbg(chg, PR_INTERRUPT, "IRQ: %s, id_state=%d\n",
"usb-id-irq", id_state);
+ if (id_state) {
+ /*otg cable removed */
+ if (chg->otg_present) {
+ if (chg->typec_port) {
+ typec_set_data_role(chg->typec_port,
+ TYPEC_DEVICE);
+ typec_set_pwr_role(chg->typec_port, TYPEC_SINK);
+ typec_partner_unregister(chg);
+ }
+ }
+ } else if (chg->typec_port) {
+ /*otg cable inserted */
+ typec_partner_register(chg);
+ typec_set_data_role(chg->typec_port, TYPEC_HOST);
+ typec_set_pwr_role(chg->typec_port, TYPEC_SOURCE);
+ }
smblite_lib_notify_usb_host(chg, !id_state);
diff --git a/drivers/power/supply/qcom/smblite-lib.h b/drivers/power/supply/qcom/smblite-lib.h
index 9bfb9c97eb8a..374c8ffba8bc 100644
--- a/drivers/power/supply/qcom/smblite-lib.h
+++ b/drivers/power/supply/qcom/smblite-lib.h
@@ -61,6 +61,7 @@ enum print_reason {
#define USBIN_25UA 25000
#define USBIN_100UA 100000
#define USBIN_150UA 150000
+#define USBIN_200UA 200000
#define USBIN_300UA 300000
#define USBIN_400UA 400000
#define USBIN_500UA 500000
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index c1e978b2fc43..aaab20dfb419 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -24,6 +24,7 @@
#include <linux/regulator/machine.h>
#include <linux/usb/phy.h>
#include <linux/reset.h>
+#include <linux/power_supply.h>
#define QUSB2PHY_PLL_PWR_CTL 0x18
#define REF_BUF_EN BIT(0)
@@ -111,6 +112,7 @@
#define QUSB2PHY_3P3_VOL_MAX 3200000 /* uV */
#define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */
+#define SOC_THRESHOLD_LEVEL 45
#define QUSB2PHY_REFCLK_ENABLE BIT(0)
#define HSTX_TRIMSIZE 4
@@ -153,6 +155,7 @@ struct qusb_phy {
struct regulator *vdda33;
struct regulator *vdda18;
int vdd_levels[3]; /* none, low, high */
+ int vdda33_levels[3]; /* low, min, max */
int init_seq_len;
int *qusb_phy_init_seq;
u32 major_rev;
@@ -169,7 +172,10 @@ struct qusb_phy {
bool ulpi_mode;
bool dpdm_enable;
bool is_se_clk;
+ bool low_soc;
+ struct notifier_block psy_nb;
+ struct work_struct soc_eval_work;
struct regulator_desc dpdm_rdesc;
struct regulator_dev *dpdm_rdev;
@@ -180,6 +186,7 @@ struct qusb_phy {
bool vbus_active;
bool id_state;
struct power_supply *usb_psy;
+ struct power_supply *batt_psy;
struct delayed_work port_det_w;
enum port_state port_state;
unsigned int dcd_timeout;
@@ -265,6 +272,34 @@ static int qusb_phy_config_vdd(struct qusb_phy *qphy, int high)
return ret;
}
+static int qusb_read_battery_soc(struct qusb_phy *qphy, int *soc_val)
+{
+ union power_supply_propval val = {0,};
+ int ret = 0;
+
+ if (!qphy->batt_psy) {
+ qphy->batt_psy = power_supply_get_by_name("battery");
+ if (!qphy->batt_psy) {
+ dev_err(qphy->phy.dev, "Could not get battery psy\n");
+ return -ENODEV;
+ }
+ }
+
+ if (qphy->batt_psy) {
+ ret = power_supply_get_property(qphy->batt_psy,
+ POWER_SUPPLY_PROP_CAPACITY, &val);
+ if (ret) {
+ dev_err(qphy->phy.dev,
+ "battery SoC read error\n");
+ return ret;
+ }
+ *soc_val = val.intval;
+ }
+
+ dev_dbg(qphy->phy.dev, "soc:%d\n", *soc_val);
+ return ret;
+}
+
static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
{
int ret = 0;
@@ -314,8 +349,9 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
goto disable_vdda18;
}
- ret = regulator_set_voltage(qphy->vdda33, QUSB2PHY_3P3_VOL_MIN,
- QUSB2PHY_3P3_VOL_MAX);
+ ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1],
+ qphy->vdda33_levels[2]);
+
if (ret) {
dev_err(qphy->phy.dev,
"Unable to set voltage for vdda33:%d\n", ret);
@@ -628,6 +664,57 @@ static int qusb_phy_init(struct usb_phy *phy)
return 0;
}
+static int qusb_phy_battery_supply_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct qusb_phy *qphy = container_of(nb, struct qusb_phy, psy_nb);
+ int soc_val = 0;
+
+ if (event != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if (qusb_read_battery_soc(qphy, &soc_val) < 0) {
+ dev_err(qphy->phy.dev, "%s unable to read battery SoC\n",
+ __func__);
+ return NOTIFY_OK;
+ }
+
+ if (soc_val < SOC_THRESHOLD_LEVEL && !qphy->low_soc) {
+ /* Reduce voltage to be set to 2.9V for low SoC */
+ qphy->vdda33_levels[1] = qphy->vdda33_levels[0];
+ qphy->vdda33_levels[2] = qphy->vdda33_levels[0];
+ qphy->low_soc = true;
+ queue_work(system_freezable_wq, &qphy->soc_eval_work);
+ return NOTIFY_OK;
+ }
+
+ if (soc_val > SOC_THRESHOLD_LEVEL && qphy->low_soc) {
+ /* Reset voltage to be set to default for normal SoC */
+ qphy->vdda33_levels[1] = QUSB2PHY_3P3_VOL_MIN;
+ qphy->vdda33_levels[2] = QUSB2PHY_3P3_VOL_MAX;
+ qphy->low_soc = false;
+ queue_work(system_freezable_wq, &qphy->soc_eval_work);
+ }
+ return NOTIFY_OK;
+}
+
+static void qusb_phy_evaluate_soc(struct work_struct *work)
+{
+ struct qusb_phy *qphy =
+ container_of(work, struct qusb_phy, soc_eval_work);
+ int ret = 0;
+
+ dev_dbg(qphy->phy.dev, "%s setting min voltage for vdda33 as %d\n",
+ __func__, qphy->vdda33_levels[1]);
+ ret = regulator_set_voltage(qphy->vdda33, qphy->vdda33_levels[1],
+ qphy->vdda33_levels[2]);
+ if (ret) {
+ dev_err(qphy->phy.dev,
+ "%s unable to set voltage for vdda33, ret = %d\n",
+ __func__, ret);
+ }
+}
+
static void qusb_phy_shutdown(struct usb_phy *phy)
{
struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -1796,9 +1883,30 @@ static int qusb_phy_probe(struct platform_device *pdev)
if (ret)
return ret;
+ qphy->vdda33_levels[1] = QUSB2PHY_3P3_VOL_MIN;
+ qphy->vdda33_levels[2] = QUSB2PHY_3P3_VOL_MAX;
+ ret = of_property_read_u32(dev->of_node,
+ "qcom,vdda33-voltage-level",
+ (u32 *)&qphy->vdda33_levels[0]);
+ if (!ret) {
+ INIT_WORK(&qphy->soc_eval_work, qusb_phy_evaluate_soc);
+ /* Register notifier to change gain based on state of charge */
+ qphy->psy_nb.notifier_call = qusb_phy_battery_supply_cb;
+ ret = power_supply_reg_notifier(&qphy->psy_nb);
+ if (ret) {
+ dev_dbg(qphy->phy.dev,
+ "%s: could not register pwr supply notifier\n",
+ __func__);
+ goto remove_phy;
+ }
+ qphy->low_soc = false;
+ qusb_phy_battery_supply_cb(&qphy->psy_nb,
+ PSY_EVENT_PROP_CHANGED, NULL);
+ }
+
ret = qusb_phy_regulator_init(qphy);
if (ret)
- usb_remove_phy(&qphy->phy);
+ goto unreg_notifier_and_put_batt_psy;
/* de-assert clamp dig n to reduce leakage on 1p8 upon boot up */
qusb_phy_clear_tcsr_clamp(qphy, true);
@@ -1838,7 +1946,14 @@ static int qusb_phy_probe(struct platform_device *pdev)
}
qusb_phy_create_debugfs(qphy);
+ return 0;
+unreg_notifier_and_put_batt_psy:
+ power_supply_unreg_notifier(&qphy->psy_nb);
+ if (qphy->batt_psy)
+ power_supply_put(qphy->batt_psy);
+remove_phy:
+ usb_remove_phy(&qphy->phy);
return ret;
}
@@ -1846,6 +1961,11 @@ static int qusb_phy_remove(struct platform_device *pdev)
{
struct qusb_phy *qphy = platform_get_drvdata(pdev);
+ power_supply_unreg_notifier(&qphy->psy_nb);
+ if (qphy->batt_psy)
+ power_supply_put(qphy->batt_psy);
+ if (qphy->usb_psy)
+ power_supply_put(qphy->usb_psy);
debugfs_remove_recursive(qphy->root);
usb_remove_phy(&qphy->phy);
qphy->cable_connected = false;
diff --git a/mm/slub.c b/mm/slub.c
index d5f745f6dc31..e3f1fc740977 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -37,6 +37,10 @@
#include <trace/events/kmem.h>
+#ifdef CONFIG_SLUB_DEBUG
+#include <linux/debugfs.h>
+#endif
+
#include "internal.h"
/*
@@ -5828,6 +5832,85 @@ struct saved_alias {
static struct saved_alias *alias_list;
+#ifdef CONFIG_SLUB_DEBUG
+static struct dentry *slab_debugfs_top;
+
+static int alloc_trace_locations(struct seq_file *seq, struct kmem_cache *s,
+ enum track_item alloc)
+{
+ unsigned long i;
+ struct loc_track t = { 0, 0, NULL };
+ int node;
+ unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) *
+ sizeof(unsigned long), GFP_KERNEL);
+ struct kmem_cache_node *n;
+
+ if (!map || !alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
+ GFP_KERNEL)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ /* Push back cpu slabs */
+ flush_all(s);
+
+ for_each_kmem_cache_node(s, node, n) {
+ unsigned long flags;
+ struct page *page;
+
+ if (!atomic_long_read(&n->nr_slabs))
+ continue;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+ list_for_each_entry(page, &n->partial, lru)
+ process_slab(&t, s, page, alloc, map);
+ list_for_each_entry(page, &n->full, lru)
+ process_slab(&t, s, page, alloc, map);
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ }
+
+ for (i = 0; i < t.count; i++) {
+ struct location *l = &t.loc[i];
+
+ seq_printf(seq,
+ "alloc_list: call_site=%pS count=%zu object_size=%zu slab_size=%zu slab_name=%s\n",
+ l->addr, l->count, s->object_size, s->size, s->name);
+ }
+
+ free_loc_track(&t);
+ kfree(map);
+ return 0;
+}
+
+static int slab_debug_alloc_trace(struct seq_file *seq,
+ void *ignored)
+{
+
+ struct kmem_cache *slab;
+
+ list_for_each_entry(slab, &slab_caches, list) {
+ if (!(slab->flags & SLAB_STORE_USER))
+ continue;
+ alloc_trace_locations(seq, slab, TRACK_ALLOC);
+ }
+
+ return 0;
+}
+
+static int slab_debug_alloc_trace_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, slab_debug_alloc_trace,
+ inode->i_private);
+}
+
+static const struct file_operations slab_debug_alloc_fops = {
+ .open = slab_debug_alloc_trace_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
{
struct saved_alias *al;
@@ -5874,6 +5957,22 @@ static int __init slab_sysfs_init(void)
s->name);
}
+#ifdef CONFIG_SLUB_DEBUG
+ if (slub_debug) {
+ slab_debugfs_top = debugfs_create_dir("slab", NULL);
+ if (!slab_debugfs_top) {
+ pr_err("Couldn't create slab debugfs directory\n");
+ return -ENODEV;
+ }
+
+ if (!debugfs_create_file("alloc_trace", 0400, slab_debugfs_top,
+ NULL, &slab_debug_alloc_fops)) {
+ pr_err("Couldn't create slab/tests debugfs directory\n");
+ return -ENODEV;
+ }
+ }
+#endif
+
while (alias_list) {
struct saved_alias *al = alias_list;