public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Andreas Noever <andreas.noever@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: Andreas Noever <andreas.noever@gmail.com>
Subject: [PATCH 03/12] thunderbolt: Setup configuration channel
Date: Fri, 29 Nov 2013 02:35:40 +0100	[thread overview]
Message-ID: <1385688949-7101-4-git-send-email-andreas.noever@gmail.com> (raw)
In-Reply-To: <1385688949-7101-1-git-send-email-andreas.noever@gmail.com>

Add struct tb which will contain our view of the thunderbolt bus. For
now it just contains a pointer to the configuration channel and a
workqueue for hotplug events.

Add thunderbolt_alloc_and_start() and thunderbolt_shutdown_and_free()
which are responsible for setup and teardown of struct tb.

Signed-off-by: Andreas Noever <andreas.noever@gmail.com>
---
 drivers/thunderbolt/Makefile  |   2 +-
 drivers/thunderbolt/dsl3510.c |  18 +++++-
 drivers/thunderbolt/tb.c      | 124 ++++++++++++++++++++++++++++++++++++++++++
 drivers/thunderbolt/tb.h      |  34 ++++++++++++
 4 files changed, 175 insertions(+), 3 deletions(-)
 create mode 100644 drivers/thunderbolt/tb.c
 create mode 100644 drivers/thunderbolt/tb.h

diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile
index f486295..7c5b811 100644
--- a/drivers/thunderbolt/Makefile
+++ b/drivers/thunderbolt/Makefile
@@ -1,3 +1,3 @@
 obj-${CONFIG_THUNDERBOLT} := thunderbolt.o
-thunderbolt-objs := dsl3510.o tb_cfg.o
+thunderbolt-objs := dsl3510.o tb_cfg.o tb.o
 
diff --git a/drivers/thunderbolt/dsl3510.c b/drivers/thunderbolt/dsl3510.c
index 2a326f6..434812b 100644
--- a/drivers/thunderbolt/dsl3510.c
+++ b/drivers/thunderbolt/dsl3510.c
@@ -12,6 +12,7 @@
 
 #include "dsl3510.h"
 #include "dsl3510_regs.h"
+#include "tb.h"
 
 #define RING_TYPE(ring) ((ring)->is_tx ? "TX ring" : "RX ring")
 
@@ -481,6 +482,7 @@ static void dsl3510_shutdown(struct tb_nhi *nhi)
 static int dsl3510_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct tb_nhi *nhi;
+	struct tb *tb;
 	int res;
 
 	res = pcim_enable_device(pdev);
@@ -543,14 +545,26 @@ static int dsl3510_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* magic value - clock related? */
 	iowrite32(3906250 / 10000, nhi->iobase + 0x38c00);
 
-	pci_set_drvdata(pdev, nhi); /* for dsl3510_remove only */
+	dev_info(&nhi->pdev->dev, "NHI initialized, starting thunderbolt\n");
+	tb = thunderbolt_alloc_and_start(nhi);
+	if (!tb) {
+		/*
+		 * At this point the RX/TX rings might already have been
+		 * activated. Do a proper shutdown.
+		 */
+		dsl3510_shutdown(nhi);
+		return -EIO;
+	}
+	pci_set_drvdata(pdev, tb); /* for dsl3510_remove only */
 
 	return 0;
 }
 
 static void dsl3510_remove(struct pci_dev *pdev)
 {
-	struct tb_nhi *nhi = pci_get_drvdata(pdev);
+	struct tb *tb = pci_get_drvdata(pdev);
+	struct tb_nhi *nhi = tb->nhi;
+	thunderbolt_shutdown_and_free(tb);
 	dsl3510_shutdown(nhi);
 }
 
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
new file mode 100644
index 0000000..64deb7b
--- /dev/null
+++ b/drivers/thunderbolt/tb.c
@@ -0,0 +1,124 @@
+/*
+ * Device independent Thunderbolt bus logic
+ *
+ * Copyright (c) 2013 Andreas Noever <andreas.noever@gmail.com>
+ */
+
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include "tb.h"
+
+struct tb_hotplug_event {
+	struct work_struct work;
+	struct tb *tb;
+	u64 route;
+	u8 port;
+	bool unplug;
+};
+
+/**
+ * tb_handle_hotplug() - handle hotplug event
+ *
+ * Executes on the tb->wq.
+ */
+static void tb_handle_hotplug(struct work_struct *work)
+{
+	struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
+	struct tb *tb = ev->tb;
+	mutex_lock(&tb->lock);
+	if (tb->shutdown)
+		goto out;
+	/* do nothing for now */
+out:
+	mutex_unlock(&tb->lock);
+	kfree(ev);
+}
+
+/**
+ * tb_schedule_hotplug_handler() - callback function for the config channel
+ *
+ * Delegates to tb_handle_hotplug.
+ */
+static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port,
+					bool unplug)
+{
+	struct tb *tb = data;
+	struct tb_hotplug_event *ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return;
+	INIT_WORK(&ev->work, tb_handle_hotplug);
+	ev->tb = tb;
+	ev->route = route;
+	ev->port = port;
+	ev->unplug = unplug;
+	queue_work(tb->wq, &ev->work);
+}
+
+/**
+ * thunderbolt_shutdown_and_free() - shutdown everything
+ *
+ * Free the config channel.
+ */
+void thunderbolt_shutdown_and_free(struct tb *tb)
+{
+	mutex_lock(&tb->lock);
+	tb->shutdown = true; /* signal tb_handle_hotplug to quit */
+
+	if (tb->cfg)
+		tb_cfg_free(tb->cfg);
+	tb->cfg = NULL;
+
+	/* allow tb_handle_hotplug to acquire the lock */
+	mutex_unlock(&tb->lock);
+	if (tb->wq) {
+		flush_workqueue(tb->wq);
+		destroy_workqueue(tb->wq);
+		tb->wq = NULL;
+	}
+	mutex_destroy(&tb->lock);
+	kfree(tb);
+}
+
+/**
+ * thunderbolt_alloc_and_start() - setup the thunderbolt bus
+ *
+ * Allocates a tb_cfg control channel.
+ *
+ * Return: Returns NULL on error.
+ */
+struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi)
+{
+	struct tb *tb;
+
+	tb = kzalloc(sizeof(*tb), GFP_KERNEL);
+	if (!tb)
+		return NULL;
+
+	tb->nhi = nhi;
+	mutex_init(&tb->lock);
+	mutex_lock(&tb->lock);
+
+	tb->wq = alloc_ordered_workqueue("thunderbolt", 0);
+	if (!tb->wq)
+		goto err_locked;
+
+	/*
+	 * tb_schedule_hotplug_handler may be called as soon as the config
+	 * channel is allocated. Thats why we have to hold the lock here.
+	 */
+	tb->cfg = tb_cfg_alloc(tb->nhi, tb_schedule_hotplug_handler, tb);
+	if (!tb->cfg)
+		goto err_locked;
+
+	mutex_unlock(&tb->lock);
+	return tb;
+
+err_locked:
+	/* In case tb_handle_hotplug is already executing. */
+	tb->shutdown = true;
+	mutex_unlock(&tb->lock);
+	thunderbolt_shutdown_and_free(tb);
+	return NULL;
+}
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
new file mode 100644
index 0000000..a3378dc
--- /dev/null
+++ b/drivers/thunderbolt/tb.h
@@ -0,0 +1,34 @@
+/*
+ * Device independent Thunderbolt bus logic
+ *
+ * Copyright (c) 2013 Andreas Noever <andreas.noever@gmail.com>
+ */
+
+#ifndef TB_H_
+#define TB_H_
+
+#include <linux/pci.h>
+
+#include "tb_cfg.h"
+
+/**
+ * struct tb - main thunderbolt bus structure
+ */
+struct tb {
+	struct mutex lock;	/*
+				 * Big lock. Must be held when accessing cfg or
+				 * any struct tb_switch / struct tb_port.
+				 */
+	struct tb_nhi *nhi;
+	struct tb_cfg *cfg;
+	struct workqueue_struct *wq; /* ordered workqueue for plug events */
+	bool shutdown;	/*
+			 * Once this is set tb_handle_hotplug will exit (once it
+			 * can aquire lock at least once). Used to drain wq.
+			 */
+};
+
+struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi);
+void thunderbolt_shutdown_and_free(struct tb *tb);
+
+#endif
-- 
1.8.4.2


  parent reply	other threads:[~2013-11-29  1:41 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-11-29  1:35 [PATCH 00/12] Thunderbolt hotplug support for Apple hardware (testers needed) Andreas Noever
2013-11-29  1:35 ` [PATCH 01/12] thunderbolt: Add initial cactus ridge NHI support Andreas Noever
2013-11-29  1:35 ` [PATCH 02/12] thunderbolt: Add configuration channel interface Andreas Noever
2013-11-29  1:35 ` Andreas Noever [this message]
2013-11-29  1:35 ` [PATCH 04/12] thunderbolt: Add tb_regs.h Andreas Noever
2013-11-29  1:35 ` [PATCH 05/12] thunderbolt: Initialize root switch and ports Andreas Noever
2013-11-29  1:35 ` [PATCH 06/12] thunderbolt: Add thunderbolt capability handling Andreas Noever
2013-11-29  1:35 ` [PATCH 07/12] thunderbolt: Enable plug events Andreas Noever
2013-11-29  1:35 ` [PATCH 08/12] thunderbolt: Scan for downstream switches Andreas Noever
2013-11-29  1:35 ` [PATCH 09/12] thunderbolt: Handle hotplug events Andreas Noever
2013-11-29  1:35 ` [PATCH 10/12] thunderbolt: Add path setup code Andreas Noever
2013-11-29  1:35 ` [PATCH 11/12] thunderbolt: Add support for simple pci tunnels Andreas Noever
2013-11-29  1:35 ` [PATCH 12/12] thunderbolt: Scan and activate one PCI device Andreas Noever
2013-12-02 16:29 ` [PATCH 00/12] Thunderbolt hotplug support for Apple hardware (testers needed) Matthew Garrett
2014-03-04  0:09   ` Matthew Garrett
2014-03-04 23:59     ` Andreas Noever
2014-03-05  0:26       ` Matthew Garrett
2014-03-08  2:40       ` Matthew Garrett
2014-03-11 13:08         ` Andreas Noever
2014-03-11 14:00           ` Matthew Garrett

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1385688949-7101-4-git-send-email-andreas.noever@gmail.com \
    --to=andreas.noever@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox