1 /* 2 * Thunderbolt Cactus Ridge driver - bus logic (NHI independent) 3 * 4 * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> 5 */ 6 7 #include <linux/slab.h> 8 #include <linux/errno.h> 9 #include <linux/delay.h> 10 11 #include "tb.h" 12 #include "tb_regs.h" 13 14 /* hotplug handling */ 15 16 struct tb_hotplug_event { 17 struct work_struct work; 18 struct tb *tb; 19 u64 route; 20 u8 port; 21 bool unplug; 22 }; 23 24 /** 25 * tb_handle_hotplug() - handle hotplug event 26 * 27 * Executes on tb->wq. 28 */ 29 static void tb_handle_hotplug(struct work_struct *work) 30 { 31 struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work); 32 struct tb *tb = ev->tb; 33 mutex_lock(&tb->lock); 34 if (!tb->hotplug_active) 35 goto out; /* during init, suspend or shutdown */ 36 37 /* do nothing for now */ 38 out: 39 mutex_unlock(&tb->lock); 40 kfree(ev); 41 } 42 43 /** 44 * tb_schedule_hotplug_handler() - callback function for the control channel 45 * 46 * Delegates to tb_handle_hotplug. 47 */ 48 static void tb_schedule_hotplug_handler(void *data, u64 route, u8 port, 49 bool unplug) 50 { 51 struct tb *tb = data; 52 struct tb_hotplug_event *ev = kmalloc(sizeof(*ev), GFP_KERNEL); 53 if (!ev) 54 return; 55 INIT_WORK(&ev->work, tb_handle_hotplug); 56 ev->tb = tb; 57 ev->route = route; 58 ev->port = port; 59 ev->unplug = unplug; 60 queue_work(tb->wq, &ev->work); 61 } 62 63 /** 64 * thunderbolt_shutdown_and_free() - shutdown everything 65 * 66 * Free all switches and the config channel. 67 * 68 * Used in the error path of thunderbolt_alloc_and_start. 69 */ 70 void thunderbolt_shutdown_and_free(struct tb *tb) 71 { 72 mutex_lock(&tb->lock); 73 74 if (tb->ctl) { 75 tb_ctl_stop(tb->ctl); 76 tb_ctl_free(tb->ctl); 77 } 78 tb->ctl = NULL; 79 tb->hotplug_active = false; /* signal tb_handle_hotplug to quit */ 80 81 /* allow tb_handle_hotplug to acquire the lock */ 82 mutex_unlock(&tb->lock); 83 if (tb->wq) { 84 flush_workqueue(tb->wq); 85 destroy_workqueue(tb->wq); 86 tb->wq = NULL; 87 } 88 mutex_destroy(&tb->lock); 89 kfree(tb); 90 } 91 92 /** 93 * thunderbolt_alloc_and_start() - setup the thunderbolt bus 94 * 95 * Allocates a tb_cfg control channel, initializes the root switch, enables 96 * plug events and activates pci devices. 97 * 98 * Return: Returns NULL on error. 99 */ 100 struct tb *thunderbolt_alloc_and_start(struct tb_nhi *nhi) 101 { 102 struct tb *tb; 103 104 BUILD_BUG_ON(sizeof(struct tb_regs_switch_header) != 5 * 4); 105 BUILD_BUG_ON(sizeof(struct tb_regs_port_header) != 8 * 4); 106 BUILD_BUG_ON(sizeof(struct tb_regs_hop) != 2 * 4); 107 108 tb = kzalloc(sizeof(*tb), GFP_KERNEL); 109 if (!tb) 110 return NULL; 111 112 tb->nhi = nhi; 113 mutex_init(&tb->lock); 114 mutex_lock(&tb->lock); 115 116 tb->wq = alloc_ordered_workqueue("thunderbolt", 0); 117 if (!tb->wq) 118 goto err_locked; 119 120 tb->ctl = tb_ctl_alloc(tb->nhi, tb_schedule_hotplug_handler, tb); 121 if (!tb->ctl) 122 goto err_locked; 123 /* 124 * tb_schedule_hotplug_handler may be called as soon as the config 125 * channel is started. Thats why we have to hold the lock here. 126 */ 127 tb_ctl_start(tb->ctl); 128 129 /* Allow tb_handle_hotplug to progress events */ 130 tb->hotplug_active = true; 131 mutex_unlock(&tb->lock); 132 return tb; 133 134 err_locked: 135 mutex_unlock(&tb->lock); 136 thunderbolt_shutdown_and_free(tb); 137 return NULL; 138 } 139 140