aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ptp
diff options
context:
space:
mode:
authorJiri Benc <jbenc@redhat.com>2013-04-11 20:56:15 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-12 18:22:45 -0400
commit7356a764cd76e155014c226ccb157219be918891 (patch)
tree3cdc441f494782192ebdc2a23d5930224ca3743c /drivers/ptp
parentd6a4a10411764cf1c3a5dad4f06c5ebe5194488b (diff)
ptp: dynamic allocation of PHC char devices
As network adapters supporting PTP are becoming more common, machines with many NICs suddenly have many PHCs, too. The current limit of eight /dev/ptp* char devices (and thus, 8 network interfaces with PHC) is insufficient. Let the ptp driver allocate the char devices dynamically. Tested with 28 PHCs, removing and re-adding some of them. Thanks to Ben Hutchings for advice leading to simpler and cleaner patch. Signed-off-by: Jiri Benc <jbenc@redhat.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/ptp')
-rw-r--r--drivers/ptp/ptp_clock.c38
1 files changed, 13 insertions, 25 deletions
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 79f4bce061bd..4a8c388364ca 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -17,7 +17,7 @@
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */ 19 */
20#include <linux/bitops.h> 20#include <linux/idr.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <linux/err.h> 22#include <linux/err.h>
23#include <linux/init.h> 23#include <linux/init.h>
@@ -32,7 +32,6 @@
32#include "ptp_private.h" 32#include "ptp_private.h"
33 33
34#define PTP_MAX_ALARMS 4 34#define PTP_MAX_ALARMS 4
35#define PTP_MAX_CLOCKS 8
36#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT) 35#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
37#define PTP_PPS_EVENT PPS_CAPTUREASSERT 36#define PTP_PPS_EVENT PPS_CAPTUREASSERT
38#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC) 37#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
@@ -42,8 +41,7 @@
42static dev_t ptp_devt; 41static dev_t ptp_devt;
43static struct class *ptp_class; 42static struct class *ptp_class;
44 43
45static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS); 44static DEFINE_IDA(ptp_clocks_map);
46static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
47 45
48/* time stamp event queue operations */ 46/* time stamp event queue operations */
49 47
@@ -171,12 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc)
171 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); 169 struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
172 170
173 mutex_destroy(&ptp->tsevq_mux); 171 mutex_destroy(&ptp->tsevq_mux);
174 172 ida_simple_remove(&ptp_clocks_map, ptp->index);
175 /* Remove the clock from the bit map. */
176 mutex_lock(&ptp_clocks_mutex);
177 clear_bit(ptp->index, ptp_clocks_map);
178 mutex_unlock(&ptp_clocks_mutex);
179
180 kfree(ptp); 173 kfree(ptp);
181} 174}
182 175
@@ -191,21 +184,18 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
191 if (info->n_alarm > PTP_MAX_ALARMS) 184 if (info->n_alarm > PTP_MAX_ALARMS)
192 return ERR_PTR(-EINVAL); 185 return ERR_PTR(-EINVAL);
193 186
194 /* Find a free clock slot and reserve it. */
195 err = -EBUSY;
196 mutex_lock(&ptp_clocks_mutex);
197 index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
198 if (index < PTP_MAX_CLOCKS)
199 set_bit(index, ptp_clocks_map);
200 else
201 goto no_slot;
202
203 /* Initialize a clock structure. */ 187 /* Initialize a clock structure. */
204 err = -ENOMEM; 188 err = -ENOMEM;
205 ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL); 189 ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
206 if (ptp == NULL) 190 if (ptp == NULL)
207 goto no_memory; 191 goto no_memory;
208 192
193 index = ida_simple_get(&ptp_clocks_map, 0, MINORMASK + 1, GFP_KERNEL);
194 if (index < 0) {
195 err = index;
196 goto no_slot;
197 }
198
209 ptp->clock.ops = ptp_clock_ops; 199 ptp->clock.ops = ptp_clock_ops;
210 ptp->clock.release = delete_ptp_clock; 200 ptp->clock.release = delete_ptp_clock;
211 ptp->info = info; 201 ptp->info = info;
@@ -248,7 +238,6 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
248 goto no_clock; 238 goto no_clock;
249 } 239 }
250 240
251 mutex_unlock(&ptp_clocks_mutex);
252 return ptp; 241 return ptp;
253 242
254no_clock: 243no_clock:
@@ -260,11 +249,9 @@ no_sysfs:
260 device_destroy(ptp_class, ptp->devid); 249 device_destroy(ptp_class, ptp->devid);
261no_device: 250no_device:
262 mutex_destroy(&ptp->tsevq_mux); 251 mutex_destroy(&ptp->tsevq_mux);
252no_slot:
263 kfree(ptp); 253 kfree(ptp);
264no_memory: 254no_memory:
265 clear_bit(index, ptp_clocks_map);
266no_slot:
267 mutex_unlock(&ptp_clocks_mutex);
268 return ERR_PTR(err); 255 return ERR_PTR(err);
269} 256}
270EXPORT_SYMBOL(ptp_clock_register); 257EXPORT_SYMBOL(ptp_clock_register);
@@ -323,7 +310,8 @@ EXPORT_SYMBOL(ptp_clock_index);
323static void __exit ptp_exit(void) 310static void __exit ptp_exit(void)
324{ 311{
325 class_destroy(ptp_class); 312 class_destroy(ptp_class);
326 unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS); 313 unregister_chrdev_region(ptp_devt, MINORMASK + 1);
314 ida_destroy(&ptp_clocks_map);
327} 315}
328 316
329static int __init ptp_init(void) 317static int __init ptp_init(void)
@@ -336,7 +324,7 @@ static int __init ptp_init(void)
336 return PTR_ERR(ptp_class); 324 return PTR_ERR(ptp_class);
337 } 325 }
338 326
339 err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp"); 327 err = alloc_chrdev_region(&ptp_devt, 0, MINORMASK + 1, "ptp");
340 if (err < 0) { 328 if (err < 0) {
341 pr_err("ptp: failed to allocate device region\n"); 329 pr_err("ptp: failed to allocate device region\n");
342 goto no_region; 330 goto no_region;