Эх сурвалжийг харах

mmc: core: convert slot functions to managed allocation

This prepares for the addition of further slot functions.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Guennadi Liakhovetski 13 жил өмнө
parent
commit
a7d1a1ebd8

+ 2 - 0
drivers/mmc/core/host.c

@@ -32,6 +32,7 @@
 static void mmc_host_classdev_release(struct device *dev)
 static void mmc_host_classdev_release(struct device *dev)
 {
 {
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
 	struct mmc_host *host = cls_dev_to_mmc_host(dev);
+	mutex_destroy(&host->slot.lock);
 	kfree(host);
 	kfree(host);
 }
 }
 
 
@@ -327,6 +328,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 
 
 	mmc_host_clk_init(host);
 	mmc_host_clk_init(host);
 
 
+	mutex_init(&host->slot.lock);
 	host->slot.cd_irq = -EINVAL;
 	host->slot.cd_irq = -EINVAL;
 
 
 	spin_lock_init(&host->lock);
 	spin_lock_init(&host->lock);

+ 38 - 13
drivers/mmc/core/slot-gpio.c

@@ -29,6 +29,34 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
+static int mmc_gpio_alloc(struct mmc_host *host)
+{
+	size_t len = strlen(dev_name(host->parent)) + 4;
+	struct mmc_gpio *ctx;
+
+	mutex_lock(&host->slot.lock);
+
+	ctx = host->slot.handler_priv;
+	if (!ctx) {
+		/*
+		 * devm_kzalloc() can be called after device_initialize(), even
+		 * before device_add(), i.e., between mmc_alloc_host() and
+		 * mmc_add_host()
+		 */
+		ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + len,
+				   GFP_KERNEL);
+		if (ctx) {
+			snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
+			ctx->cd_gpio = -EINVAL;
+			host->slot.handler_priv = ctx;
+		}
+	}
+
+	mutex_unlock(&host->slot.lock);
+
+	return ctx ? 0 : -ENOMEM;
+}
+
 int mmc_gpio_get_cd(struct mmc_host *host)
 int mmc_gpio_get_cd(struct mmc_host *host)
 {
 {
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 	struct mmc_gpio *ctx = host->slot.handler_priv;
@@ -43,20 +71,24 @@ EXPORT_SYMBOL(mmc_gpio_get_cd);
 
 
 int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
 int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
 {
 {
-	size_t len = strlen(dev_name(host->parent)) + 4;
 	struct mmc_gpio *ctx;
 	struct mmc_gpio *ctx;
 	int irq = gpio_to_irq(gpio);
 	int irq = gpio_to_irq(gpio);
 	int ret;
 	int ret;
 
 
-	ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
+	ret = mmc_gpio_alloc(host);
+	if (ret < 0)
+		return ret;
 
 
-	snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
+	ctx = host->slot.handler_priv;
 
 
 	ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
 	ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
 	if (ret < 0)
 	if (ret < 0)
-		goto egpioreq;
+		/*
+		 * don't bother freeing memory. It might still get used by other
+		 * slot functions, in any case it will be freed, when the device
+		 * is destroyed.
+		 */
+		return ret;
 
 
 	/*
 	/*
 	 * Even if gpio_to_irq() returns a valid IRQ number, the platform might
 	 * Even if gpio_to_irq() returns a valid IRQ number, the platform might
@@ -80,13 +112,8 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
 		host->caps |= MMC_CAP_NEEDS_POLL;
 		host->caps |= MMC_CAP_NEEDS_POLL;
 
 
 	ctx->cd_gpio = gpio;
 	ctx->cd_gpio = gpio;
-	host->slot.handler_priv = ctx;
 
 
 	return 0;
 	return 0;
-
-egpioreq:
-	kfree(ctx);
-	return ret;
 }
 }
 EXPORT_SYMBOL(mmc_gpio_request_cd);
 EXPORT_SYMBOL(mmc_gpio_request_cd);
 
 
@@ -107,7 +134,5 @@ void mmc_gpio_free_cd(struct mmc_host *host)
 	ctx->cd_gpio = -EINVAL;
 	ctx->cd_gpio = -EINVAL;
 
 
 	gpio_free(gpio);
 	gpio_free(gpio);
-	host->slot.handler_priv = NULL;
-	kfree(ctx);
 }
 }
 EXPORT_SYMBOL(mmc_gpio_free_cd);
 EXPORT_SYMBOL(mmc_gpio_free_cd);

+ 3 - 0
include/linux/mmc/host.h

@@ -11,6 +11,7 @@
 #define LINUX_MMC_HOST_H
 #define LINUX_MMC_HOST_H
 
 
 #include <linux/leds.h>
 #include <linux/leds.h>
+#include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/fault-inject.h>
 #include <linux/fault-inject.h>
@@ -154,6 +155,7 @@ struct mmc_async_req {
  * struct mmc_slot - MMC slot functions
  * struct mmc_slot - MMC slot functions
  *
  *
  * @cd_irq:		MMC/SD-card slot hotplug detection IRQ or -EINVAL
  * @cd_irq:		MMC/SD-card slot hotplug detection IRQ or -EINVAL
+ * @lock:		protect the @handler_priv pointer
  * @handler_priv:	MMC/SD-card slot context
  * @handler_priv:	MMC/SD-card slot context
  *
  *
  * Some MMC/SD host controllers implement slot-functions like card and
  * Some MMC/SD host controllers implement slot-functions like card and
@@ -163,6 +165,7 @@ struct mmc_async_req {
  */
  */
 struct mmc_slot {
 struct mmc_slot {
 	int cd_irq;
 	int cd_irq;
+	struct mutex lock;
 	void *handler_priv;
 	void *handler_priv;
 };
 };