diff options
author | Jiri Benc <jbenc@redhat.com> | 2013-04-11 20:56:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-12 18:22:45 -0400 |
commit | 7356a764cd76e155014c226ccb157219be918891 (patch) | |
tree | 3cdc441f494782192ebdc2a23d5930224ca3743c /drivers/ptp | |
parent | d6a4a10411764cf1c3a5dad4f06c5ebe5194488b (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.c | 38 |
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 @@ | |||
42 | static dev_t ptp_devt; | 41 | static dev_t ptp_devt; |
43 | static struct class *ptp_class; | 42 | static struct class *ptp_class; |
44 | 43 | ||
45 | static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS); | 44 | static DEFINE_IDA(ptp_clocks_map); |
46 | static 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 | ||
254 | no_clock: | 243 | no_clock: |
@@ -260,11 +249,9 @@ no_sysfs: | |||
260 | device_destroy(ptp_class, ptp->devid); | 249 | device_destroy(ptp_class, ptp->devid); |
261 | no_device: | 250 | no_device: |
262 | mutex_destroy(&ptp->tsevq_mux); | 251 | mutex_destroy(&ptp->tsevq_mux); |
252 | no_slot: | ||
263 | kfree(ptp); | 253 | kfree(ptp); |
264 | no_memory: | 254 | no_memory: |
265 | clear_bit(index, ptp_clocks_map); | ||
266 | no_slot: | ||
267 | mutex_unlock(&ptp_clocks_mutex); | ||
268 | return ERR_PTR(err); | 255 | return ERR_PTR(err); |
269 | } | 256 | } |
270 | EXPORT_SYMBOL(ptp_clock_register); | 257 | EXPORT_SYMBOL(ptp_clock_register); |
@@ -323,7 +310,8 @@ EXPORT_SYMBOL(ptp_clock_index); | |||
323 | static void __exit ptp_exit(void) | 310 | static 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 | ||
329 | static int __init ptp_init(void) | 317 | static 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; |