diff options
author | Olivier Guiter <olivier.guiter@linux.intel.com> | 2013-06-13 09:43:28 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-08-13 18:35:18 -0400 |
commit | 963a82e07d4e1f95fc423d53912ac0a7fe643b1c (patch) | |
tree | 07cb5859c86cc34c86cefc4e4a0233aac7947bfd /drivers/nfc | |
parent | 1575b9d8668f4ecf2648a08751313c826fb6a6e9 (diff) |
NFC: pn533: Split large Tx frames in chunks
On sending large frames (size > 262), we split it in multiple chunks and
send them asynchronously with MI bit.
Signed-off-by: Olivier Guiter <olivier.guiter@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/nfc')
-rw-r--r-- | drivers/nfc/pn533.c | 144 |
1 files changed, 130 insertions, 14 deletions
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index ae0fa9ee169d..f06ef7c49f84 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c | |||
@@ -363,12 +363,14 @@ struct pn533 { | |||
363 | struct urb *in_urb; | 363 | struct urb *in_urb; |
364 | 364 | ||
365 | struct sk_buff_head resp_q; | 365 | struct sk_buff_head resp_q; |
366 | struct sk_buff_head fragment_skb; | ||
366 | 367 | ||
367 | struct workqueue_struct *wq; | 368 | struct workqueue_struct *wq; |
368 | struct work_struct cmd_work; | 369 | struct work_struct cmd_work; |
369 | struct work_struct cmd_complete_work; | 370 | struct work_struct cmd_complete_work; |
370 | struct work_struct poll_work; | 371 | struct work_struct poll_work; |
371 | struct work_struct mi_work; | 372 | struct work_struct mi_rx_work; |
373 | struct work_struct mi_tx_work; | ||
372 | struct work_struct tg_work; | 374 | struct work_struct tg_work; |
373 | struct work_struct rf_work; | 375 | struct work_struct rf_work; |
374 | 376 | ||
@@ -378,6 +380,7 @@ struct pn533 { | |||
378 | struct mutex cmd_lock; /* protects cmd queue */ | 380 | struct mutex cmd_lock; /* protects cmd queue */ |
379 | 381 | ||
380 | void *cmd_complete_mi_arg; | 382 | void *cmd_complete_mi_arg; |
383 | void *cmd_complete_dep_arg; | ||
381 | 384 | ||
382 | struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; | 385 | struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1]; |
383 | u8 poll_mod_count; | 386 | u8 poll_mod_count; |
@@ -2328,7 +2331,15 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg, | |||
2328 | 2331 | ||
2329 | if (mi) { | 2332 | if (mi) { |
2330 | dev->cmd_complete_mi_arg = arg; | 2333 | dev->cmd_complete_mi_arg = arg; |
2331 | queue_work(dev->wq, &dev->mi_work); | 2334 | queue_work(dev->wq, &dev->mi_rx_work); |
2335 | return -EINPROGRESS; | ||
2336 | } | ||
2337 | |||
2338 | /* Prepare for the next round */ | ||
2339 | if (skb_queue_len(&dev->fragment_skb) > 0) { | ||
2340 | dev->cmd_complete_dep_arg = arg; | ||
2341 | queue_work(dev->wq, &dev->mi_tx_work); | ||
2342 | |||
2332 | return -EINPROGRESS; | 2343 | return -EINPROGRESS; |
2333 | } | 2344 | } |
2334 | 2345 | ||
@@ -2349,6 +2360,50 @@ _error: | |||
2349 | return rc; | 2360 | return rc; |
2350 | } | 2361 | } |
2351 | 2362 | ||
2363 | /* Split the Tx skb into small chunks */ | ||
2364 | static int pn533_fill_fragment_skbs(struct pn533 *dev, struct sk_buff *skb) | ||
2365 | { | ||
2366 | struct sk_buff *frag; | ||
2367 | int frag_size; | ||
2368 | |||
2369 | do { | ||
2370 | /* Remaining size */ | ||
2371 | if (skb->len > PN533_CMD_DATAFRAME_MAXLEN) | ||
2372 | frag_size = PN533_CMD_DATAFRAME_MAXLEN; | ||
2373 | else | ||
2374 | frag_size = skb->len; | ||
2375 | |||
2376 | /* Allocate and reserve */ | ||
2377 | frag = pn533_alloc_skb(dev, frag_size); | ||
2378 | if (!frag) { | ||
2379 | skb_queue_purge(&dev->fragment_skb); | ||
2380 | break; | ||
2381 | } | ||
2382 | |||
2383 | /* Reserve the TG/MI byte */ | ||
2384 | skb_reserve(frag, 1); | ||
2385 | |||
2386 | /* MI + TG */ | ||
2387 | if (frag_size == PN533_CMD_DATAFRAME_MAXLEN) | ||
2388 | *skb_push(frag, sizeof(u8)) = (PN533_CMD_MI_MASK | 1); | ||
2389 | else | ||
2390 | *skb_push(frag, sizeof(u8)) = 1; /* TG */ | ||
2391 | |||
2392 | memcpy(skb_put(frag, frag_size), skb->data, frag_size); | ||
2393 | |||
2394 | /* Reduce the size of incoming buffer */ | ||
2395 | skb_pull(skb, frag_size); | ||
2396 | |||
2397 | /* Add this to skb_queue */ | ||
2398 | skb_queue_tail(&dev->fragment_skb, frag); | ||
2399 | |||
2400 | } while (skb->len > 0); | ||
2401 | |||
2402 | dev_kfree_skb(skb); | ||
2403 | |||
2404 | return skb_queue_len(&dev->fragment_skb); | ||
2405 | } | ||
2406 | |||
2352 | static int pn533_transceive(struct nfc_dev *nfc_dev, | 2407 | static int pn533_transceive(struct nfc_dev *nfc_dev, |
2353 | struct nfc_target *target, struct sk_buff *skb, | 2408 | struct nfc_target *target, struct sk_buff *skb, |
2354 | data_exchange_cb_t cb, void *cb_context) | 2409 | data_exchange_cb_t cb, void *cb_context) |
@@ -2359,15 +2414,6 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, | |||
2359 | 2414 | ||
2360 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | 2415 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); |
2361 | 2416 | ||
2362 | if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { | ||
2363 | /* TODO: Implement support to multi-part data exchange */ | ||
2364 | nfc_dev_err(&dev->interface->dev, | ||
2365 | "Data length greater than the max allowed: %d", | ||
2366 | PN533_CMD_DATAEXCH_DATA_MAXLEN); | ||
2367 | rc = -ENOSYS; | ||
2368 | goto error; | ||
2369 | } | ||
2370 | |||
2371 | if (!dev->tgt_active_prot) { | 2417 | if (!dev->tgt_active_prot) { |
2372 | nfc_dev_err(&dev->interface->dev, | 2418 | nfc_dev_err(&dev->interface->dev, |
2373 | "Can't exchange data if there is no active target"); | 2419 | "Can't exchange data if there is no active target"); |
@@ -2395,7 +2441,20 @@ static int pn533_transceive(struct nfc_dev *nfc_dev, | |||
2395 | break; | 2441 | break; |
2396 | } | 2442 | } |
2397 | default: | 2443 | default: |
2398 | *skb_push(skb, sizeof(u8)) = 1; /*TG*/ | 2444 | /* jumbo frame ? */ |
2445 | if (skb->len > PN533_CMD_DATAEXCH_DATA_MAXLEN) { | ||
2446 | rc = pn533_fill_fragment_skbs(dev, skb); | ||
2447 | if (rc <= 0) | ||
2448 | goto error; | ||
2449 | |||
2450 | skb = skb_dequeue(&dev->fragment_skb); | ||
2451 | if (!skb) { | ||
2452 | rc = -EIO; | ||
2453 | goto error; | ||
2454 | } | ||
2455 | } else { | ||
2456 | *skb_push(skb, sizeof(u8)) = 1; /* TG */ | ||
2457 | } | ||
2399 | 2458 | ||
2400 | rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, | 2459 | rc = pn533_send_data_async(dev, PN533_CMD_IN_DATA_EXCHANGE, |
2401 | skb, pn533_data_exchange_complete, | 2460 | skb, pn533_data_exchange_complete, |
@@ -2466,7 +2525,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) | |||
2466 | 2525 | ||
2467 | static void pn533_wq_mi_recv(struct work_struct *work) | 2526 | static void pn533_wq_mi_recv(struct work_struct *work) |
2468 | { | 2527 | { |
2469 | struct pn533 *dev = container_of(work, struct pn533, mi_work); | 2528 | struct pn533 *dev = container_of(work, struct pn533, mi_rx_work); |
2470 | 2529 | ||
2471 | struct sk_buff *skb; | 2530 | struct sk_buff *skb; |
2472 | int rc; | 2531 | int rc; |
@@ -2514,6 +2573,61 @@ error: | |||
2514 | queue_work(dev->wq, &dev->cmd_work); | 2573 | queue_work(dev->wq, &dev->cmd_work); |
2515 | } | 2574 | } |
2516 | 2575 | ||
2576 | static void pn533_wq_mi_send(struct work_struct *work) | ||
2577 | { | ||
2578 | struct pn533 *dev = container_of(work, struct pn533, mi_tx_work); | ||
2579 | struct sk_buff *skb; | ||
2580 | int rc; | ||
2581 | |||
2582 | nfc_dev_dbg(&dev->interface->dev, "%s", __func__); | ||
2583 | |||
2584 | /* Grab the first skb in the queue */ | ||
2585 | skb = skb_dequeue(&dev->fragment_skb); | ||
2586 | |||
2587 | if (skb == NULL) { /* No more data */ | ||
2588 | /* Reset the queue for future use */ | ||
2589 | skb_queue_head_init(&dev->fragment_skb); | ||
2590 | goto error; | ||
2591 | } | ||
2592 | |||
2593 | switch (dev->device_type) { | ||
2594 | case PN533_DEVICE_PASORI: | ||
2595 | if (dev->tgt_active_prot != NFC_PROTO_FELICA) { | ||
2596 | rc = -EIO; | ||
2597 | break; | ||
2598 | } | ||
2599 | |||
2600 | rc = pn533_send_cmd_direct_async(dev, PN533_CMD_IN_COMM_THRU, | ||
2601 | skb, | ||
2602 | pn533_data_exchange_complete, | ||
2603 | dev->cmd_complete_dep_arg); | ||
2604 | |||
2605 | break; | ||
2606 | |||
2607 | default: | ||
2608 | /* Still some fragments? */ | ||
2609 | rc = pn533_send_cmd_direct_async(dev,PN533_CMD_IN_DATA_EXCHANGE, | ||
2610 | skb, | ||
2611 | pn533_data_exchange_complete, | ||
2612 | dev->cmd_complete_dep_arg); | ||
2613 | |||
2614 | break; | ||
2615 | } | ||
2616 | |||
2617 | if (rc == 0) /* success */ | ||
2618 | return; | ||
2619 | |||
2620 | nfc_dev_err(&dev->interface->dev, | ||
2621 | "Error %d when trying to perform data_exchange", rc); | ||
2622 | |||
2623 | dev_kfree_skb(skb); | ||
2624 | kfree(dev->cmd_complete_dep_arg); | ||
2625 | |||
2626 | error: | ||
2627 | pn533_send_ack(dev, GFP_KERNEL); | ||
2628 | queue_work(dev->wq, &dev->cmd_work); | ||
2629 | } | ||
2630 | |||
2517 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, | 2631 | static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, |
2518 | u8 cfgdata_len) | 2632 | u8 cfgdata_len) |
2519 | { | 2633 | { |
@@ -2816,7 +2930,8 @@ static int pn533_probe(struct usb_interface *interface, | |||
2816 | 2930 | ||
2817 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd); | 2931 | INIT_WORK(&dev->cmd_work, pn533_wq_cmd); |
2818 | INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); | 2932 | INIT_WORK(&dev->cmd_complete_work, pn533_wq_cmd_complete); |
2819 | INIT_WORK(&dev->mi_work, pn533_wq_mi_recv); | 2933 | INIT_WORK(&dev->mi_rx_work, pn533_wq_mi_recv); |
2934 | INIT_WORK(&dev->mi_tx_work, pn533_wq_mi_send); | ||
2820 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); | 2935 | INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data); |
2821 | INIT_WORK(&dev->poll_work, pn533_wq_poll); | 2936 | INIT_WORK(&dev->poll_work, pn533_wq_poll); |
2822 | INIT_WORK(&dev->rf_work, pn533_wq_rf); | 2937 | INIT_WORK(&dev->rf_work, pn533_wq_rf); |
@@ -2829,6 +2944,7 @@ static int pn533_probe(struct usb_interface *interface, | |||
2829 | dev->listen_timer.function = pn533_listen_mode_timer; | 2944 | dev->listen_timer.function = pn533_listen_mode_timer; |
2830 | 2945 | ||
2831 | skb_queue_head_init(&dev->resp_q); | 2946 | skb_queue_head_init(&dev->resp_q); |
2947 | skb_queue_head_init(&dev->fragment_skb); | ||
2832 | 2948 | ||
2833 | INIT_LIST_HEAD(&dev->cmd_queue); | 2949 | INIT_LIST_HEAD(&dev->cmd_queue); |
2834 | 2950 | ||