cmp.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * FireSAT DVB driver
  3. *
  4. * Copyright (c) ?
  5. * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. */
  12. #include "cmp.h"
  13. #include <ieee1394.h>
  14. #include <nodemgr.h>
  15. #include <highlevel.h>
  16. #include <ohci1394.h>
  17. #include <hosts.h>
  18. #include <ieee1394_core.h>
  19. #include <ieee1394_transactions.h>
  20. #include "avc_api.h"
  21. typedef struct _OPCR
  22. {
  23. __u8 PTPConnCount : 6 ; // Point to point connect. counter
  24. __u8 BrConnCount : 1 ; // Broadcast connection counter
  25. __u8 OnLine : 1 ; // On Line
  26. __u8 ChNr : 6 ; // Channel number
  27. __u8 Res : 2 ; // Reserved
  28. __u8 PayloadHi : 2 ; // Payoad high bits
  29. __u8 OvhdID : 4 ; // Overhead ID
  30. __u8 DataRate : 2 ; // Data Rate
  31. __u8 PayloadLo ; // Payoad low byte
  32. } OPCR ;
  33. #define FIRESAT_SPEED IEEE1394_SPEED_400
  34. /* hpsb_lock is being removed from the kernel-source,
  35. * therefor we define our own 'firesat_hpsb_lock'*/
  36. int send_packet_and_wait(struct hpsb_packet *packet);
  37. int firesat_hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
  38. u64 addr, int extcode, quadlet_t * data, quadlet_t arg) {
  39. struct hpsb_packet *packet;
  40. int retval = 0;
  41. BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
  42. packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
  43. if (!packet)
  44. return -ENOMEM;
  45. packet->generation = generation;
  46. retval = send_packet_and_wait(packet);
  47. if (retval < 0)
  48. goto hpsb_lock_fail;
  49. retval = hpsb_packet_success(packet);
  50. if (retval == 0) {
  51. *data = packet->data[0];
  52. }
  53. hpsb_lock_fail:
  54. hpsb_free_tlabel(packet);
  55. hpsb_free_packet(packet);
  56. return retval;
  57. }
  58. static int cmp_read(struct firesat *firesat, void *buffer, u64 addr, size_t length) {
  59. int ret;
  60. if(down_interruptible(&firesat->avc_sem))
  61. return -EINTR;
  62. ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
  63. addr, buffer, length);
  64. up(&firesat->avc_sem);
  65. return ret;
  66. }
  67. static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, quadlet_t arg, int ext_tcode) {
  68. int ret;
  69. if(down_interruptible(&firesat->avc_sem))
  70. return -EINTR;
  71. ret = firesat_hpsb_lock(firesat->host, firesat->nodeentry->nodeid, firesat->nodeentry->generation,
  72. addr, ext_tcode, data, arg);
  73. up(&firesat->avc_sem);
  74. return ret;
  75. }
  76. //try establishing a point-to-point connection (may be interrupted by a busreset
  77. int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) {
  78. unsigned int BWU; //bandwidth to allocate
  79. quadlet_t old_oPCR,test_oPCR = 0x0;
  80. u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
  81. int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
  82. /* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
  83. if (result < 0) {
  84. printk("%s: cannot read oPCR\n", __func__);
  85. return result;
  86. } else {
  87. /* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
  88. do {
  89. OPCR *hilf= (OPCR*) &test_oPCR;
  90. if (!hilf->OnLine) {
  91. printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR);
  92. return -EBUSY;
  93. } else {
  94. quadlet_t new_oPCR;
  95. old_oPCR=test_oPCR;
  96. if (hilf->PTPConnCount) {
  97. if (hilf->ChNr != iso_channel) {
  98. printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel);
  99. return -EBUSY;
  100. } else
  101. printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount);
  102. BWU=0; //we allocate no bandwidth (is this necessary?)
  103. } else {
  104. hilf->ChNr=iso_channel;
  105. hilf->DataRate=FIRESAT_SPEED;
  106. hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
  107. BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  108. BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
  109. /* if (allocate_1394_resources(iso_channel,BWU))
  110. {
  111. cout << "Allocation of resources failed\n";
  112. return -2;
  113. }*/
  114. }
  115. hilf->PTPConnCount++;
  116. new_oPCR=test_oPCR;
  117. /* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
  118. /* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
  119. result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
  120. if (result < 0) {
  121. printk("%s: cannot compare_swap oPCR\n",__func__);
  122. return result;
  123. }
  124. if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
  125. {
  126. printk("%s: change of oPCR failed -> freeing resources\n",__func__);
  127. // hilf= (OPCR*) &new_oPCR;
  128. // unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  129. // BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
  130. /* if (deallocate_1394_resources(iso_channel,BWU))
  131. {
  132. cout << "Deallocation of resources failed\n";
  133. return -3;
  134. }*/
  135. }
  136. }
  137. }
  138. while (old_oPCR != test_oPCR);
  139. }
  140. return 0;
  141. }
  142. //try breaking a point-to-point connection (may be interrupted by a busreset
  143. int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) {
  144. quadlet_t old_oPCR,test_oPCR;
  145. u64 oPCR_address=0xfffff0000904ull+(output_plug << 2);
  146. int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4);
  147. /* printk(KERN_INFO "%s\n",__func__); */
  148. if (result < 0) {
  149. printk("%s: cannot read oPCR\n", __func__);
  150. return result;
  151. } else {
  152. do {
  153. OPCR *hilf= (OPCR*) &test_oPCR;
  154. if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
  155. printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
  156. return -EINVAL;
  157. } else {
  158. quadlet_t new_oPCR;
  159. old_oPCR=test_oPCR;
  160. hilf->PTPConnCount--;
  161. new_oPCR=test_oPCR;
  162. // printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
  163. result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
  164. if (result < 0) {
  165. printk("%s: cannot compare_swap oPCR\n",__func__);
  166. return result;
  167. }
  168. }
  169. } while (old_oPCR != test_oPCR);
  170. /* hilf = (OPCR*) &old_oPCR;
  171. if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
  172. cout << "deallocating 1394 resources\n";
  173. unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
  174. BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
  175. if (deallocate_1394_resources(iso_channel,BWU))
  176. {
  177. cout << "Deallocation of resources failed\n";
  178. return -3;
  179. }
  180. }*/
  181. }
  182. return 0;
  183. }
  184. static void complete_packet(void *data) {
  185. complete((struct completion *) data);
  186. }
  187. int send_packet_and_wait(struct hpsb_packet *packet) {
  188. struct completion done;
  189. int retval;
  190. init_completion(&done);
  191. hpsb_set_packet_complete_task(packet, complete_packet, &done);
  192. retval = hpsb_send_packet(packet);
  193. if (retval == 0)
  194. wait_for_completion(&done);
  195. return retval;
  196. }