aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/firesat/cmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/firesat/cmp.c')
-rw-r--r--drivers/media/dvb/firesat/cmp.c252
1 files changed, 112 insertions, 140 deletions
diff --git a/drivers/media/dvb/firesat/cmp.c b/drivers/media/dvb/firesat/cmp.c
index d1bafba615e4..8e98b814e430 100644
--- a/drivers/media/dvb/firesat/cmp.c
+++ b/drivers/media/dvb/firesat/cmp.c
@@ -10,37 +10,21 @@
10 * the License, or (at your option) any later version. 10 * the License, or (at your option) any later version.
11 */ 11 */
12 12
13#include <linux/device.h>
13#include <linux/kernel.h> 14#include <linux/kernel.h>
14#include <linux/mutex.h> 15#include <linux/mutex.h>
15#include <linux/types.h> 16#include <linux/types.h>
16 17
17#include <hosts.h> 18#include <asm/byteorder.h>
19
18#include <ieee1394.h> 20#include <ieee1394.h>
19#include <ieee1394_core.h>
20#include <ieee1394_transactions.h>
21#include <nodemgr.h> 21#include <nodemgr.h>
22 22
23#include "avc_api.h" 23#include "avc_api.h"
24#include "cmp.h" 24#include "cmp.h"
25#include "firesat.h" 25#include "firesat.h"
26 26
27typedef struct _OPCR 27#define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
28{
29 __u8 PTPConnCount : 6 ; // Point to point connect. counter
30 __u8 BrConnCount : 1 ; // Broadcast connection counter
31 __u8 OnLine : 1 ; // On Line
32
33 __u8 ChNr : 6 ; // Channel number
34 __u8 Res : 2 ; // Reserved
35
36 __u8 PayloadHi : 2 ; // Payoad high bits
37 __u8 OvhdID : 4 ; // Overhead ID
38 __u8 DataRate : 2 ; // Data Rate
39
40 __u8 PayloadLo ; // Payoad low byte
41} OPCR ;
42
43#define FIRESAT_SPEED IEEE1394_SPEED_400
44 28
45static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) 29static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
46{ 30{
@@ -49,151 +33,139 @@ static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len)
49 if (mutex_lock_interruptible(&firesat->avc_mutex)) 33 if (mutex_lock_interruptible(&firesat->avc_mutex))
50 return -EINTR; 34 return -EINTR;
51 35
52 ret = hpsb_read(firesat->host, firesat->nodeentry->nodeid, 36 ret = hpsb_node_read(firesat->ud->ne, addr, buf, len);
53 firesat->nodeentry->generation, addr, buf, len); 37 if (ret < 0)
38 dev_err(&firesat->ud->device, "CMP: read I/O error\n");
54 39
55 mutex_unlock(&firesat->avc_mutex); 40 mutex_unlock(&firesat->avc_mutex);
56 return ret; 41 return ret;
57} 42}
58 43
59static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, 44static int cmp_lock(struct firesat *firesat, void *data, u64 addr, __be32 arg,
60 quadlet_t arg, int ext_tcode) 45 int ext_tcode)
61{ 46{
62 int ret; 47 int ret;
63 48
64 if (mutex_lock_interruptible(&firesat->avc_mutex)) 49 if (mutex_lock_interruptible(&firesat->avc_mutex))
65 return -EINTR; 50 return -EINTR;
66 51
67 ret = hpsb_lock(firesat->host, firesat->nodeentry->nodeid, 52 ret = hpsb_node_lock(firesat->ud->ne, addr, ext_tcode, data,
68 firesat->nodeentry->generation, 53 (__force quadlet_t)arg);
69 addr, ext_tcode, data, arg); 54 if (ret < 0)
55 dev_err(&firesat->ud->device, "CMP: lock I/O error\n");
70 56
71 mutex_unlock(&firesat->avc_mutex); 57 mutex_unlock(&firesat->avc_mutex);
72 return ret; 58 return ret;
73} 59}
74 60
75//try establishing a point-to-point connection (may be interrupted by a busreset 61static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
76int try_CMPEstablishPPconnection(struct firesat *firesat, int output_plug, int iso_channel) { 62{
77 unsigned int BWU; //bandwidth to allocate 63 return (be32_to_cpu(opcr) >> shift) & mask;
64}
65
66static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
67{
68 *opcr &= ~cpu_to_be32(mask << shift);
69 *opcr |= cpu_to_be32((value & mask) << shift);
70}
78 71
79 quadlet_t old_oPCR,test_oPCR = 0x0; 72#define get_opcr_online(v) get_opcr((v), 0x1, 31)
80 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); 73#define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
81 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); 74#define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
82 75
83/* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */ 76#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
77#define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
78#define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
79#define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
84 80
85 if (result < 0) { 81int cmp_establish_pp_connection(struct firesat *firesat, int plug, int channel)
86 printk("%s: cannot read oPCR\n", __func__); 82{
87 return result; 83 __be32 old_opcr, opcr;
88 } else { 84 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
89/* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */ 85 int attempts = 0;
90 do { 86 int ret;
91 OPCR *hilf= (OPCR*) &test_oPCR; 87
92 88 ret = cmp_read(firesat, &opcr, opcr_address, 4);
93 if (!hilf->OnLine) { 89 if (ret < 0)
94 printk("%s: Output offline; oPCR: %08x\n", __func__, test_oPCR); 90 return ret;
95 return -EBUSY; 91
96 } else { 92repeat:
97 quadlet_t new_oPCR; 93 if (!get_opcr_online(opcr)) {
98 94 dev_err(&firesat->ud->device, "CMP: output offline\n");
99 old_oPCR=test_oPCR; 95 return -EBUSY;
100 if (hilf->PTPConnCount) { 96 }
101 if (hilf->ChNr != iso_channel) { 97
102 printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__,hilf->ChNr,iso_channel); 98 old_opcr = opcr;
103 return -EBUSY; 99
104 } else 100 if (get_opcr_p2p_connections(opcr)) {
105 printk(KERN_INFO "%s: Overlaying existing connection; connection counter was: %u\n",__func__, hilf->PTPConnCount); 101 if (get_opcr_channel(opcr) != channel) {
106 BWU=0; //we allocate no bandwidth (is this necessary?) 102 dev_err(&firesat->ud->device,
107 } else { 103 "CMP: cannot change channel\n");
108 hilf->ChNr=iso_channel; 104 return -EBUSY;
109 hilf->DataRate=FIRESAT_SPEED;
110
111 hilf->OvhdID=0; //FIXME: that is for worst case -> optimize
112 BWU=hilf->OvhdID?hilf->OvhdID*32:512;
113 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
114/* if (allocate_1394_resources(iso_channel,BWU))
115 {
116 cout << "Allocation of resources failed\n";
117 return -2;
118 }*/
119 }
120
121 hilf->PTPConnCount++;
122 new_oPCR=test_oPCR;
123/* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
124/* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
125 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
126
127 if (result < 0) {
128 printk("%s: cannot compare_swap oPCR\n",__func__);
129 return result;
130 }
131 if ((old_oPCR != test_oPCR) && (!((OPCR*) &old_oPCR)->PTPConnCount))
132 {
133 printk("%s: change of oPCR failed -> freeing resources\n",__func__);
134// hilf= (OPCR*) &new_oPCR;
135// unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
136// BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
137/* if (deallocate_1394_resources(iso_channel,BWU))
138 {
139
140 cout << "Deallocation of resources failed\n";
141 return -3;
142 }*/
143 }
144 }
145 } 105 }
146 while (old_oPCR != test_oPCR); 106 dev_info(&firesat->ud->device,
107 "CMP: overlaying existing connection\n");
108
109 /* We don't allocate isochronous resources. */
110 } else {
111 set_opcr_channel(&opcr, channel);
112 set_opcr_data_rate(&opcr, IEEE1394_SPEED_400);
113
114 /* FIXME: this is for the worst case - optimize */
115 set_opcr_overhead_id(&opcr, 0);
116
117 /* FIXME: allocate isochronous channel and bandwidth at IRM */
147 } 118 }
119
120 set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
121
122 ret = cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2);
123 if (ret < 0)
124 return ret;
125
126 if (old_opcr != opcr) {
127 /*
128 * FIXME: if old_opcr.P2P_Connections > 0,
129 * deallocate isochronous channel and bandwidth at IRM
130 */
131
132 if (++attempts < 6) /* arbitrary limit */
133 goto repeat;
134 return -EBUSY;
135 }
136
148 return 0; 137 return 0;
149} 138}
150 139
151//try breaking a point-to-point connection (may be interrupted by a busreset 140void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel)
152int try_CMPBreakPPconnection(struct firesat *firesat, int output_plug,int iso_channel) { 141{
153 quadlet_t old_oPCR,test_oPCR; 142 __be32 old_opcr, opcr;
143 u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
144 int attempts = 0;
145
146 if (cmp_read(firesat, &opcr, opcr_address, 4) < 0)
147 return;
148
149repeat:
150 if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
151 get_opcr_channel(opcr) != channel) {
152 dev_err(&firesat->ud->device, "CMP: no connection to break\n");
153 return;
154 }
155
156 old_opcr = opcr;
157 set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
154 158
155 u64 oPCR_address=0xfffff0000904ull+(output_plug << 2); 159 if (cmp_lock(firesat, &opcr, opcr_address, old_opcr, 2) < 0)
156 int result=cmp_read(firesat, &test_oPCR, oPCR_address, 4); 160 return;
157 161
158/* printk(KERN_INFO "%s\n",__func__); */ 162 if (old_opcr != opcr) {
163 /*
164 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
165 * owner, deallocate isochronous channel and bandwidth at IRM
166 */
159 167
160 if (result < 0) { 168 if (++attempts < 6) /* arbitrary limit */
161 printk("%s: cannot read oPCR\n", __func__); 169 goto repeat;
162 return result; 170 }
163 } else {
164 do {
165 OPCR *hilf= (OPCR*) &test_oPCR;
166
167 if (!hilf->OnLine || !hilf->PTPConnCount || hilf->ChNr != iso_channel) {
168 printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__, test_oPCR);
169 return -EINVAL;
170 } else {
171 quadlet_t new_oPCR;
172 old_oPCR=test_oPCR;
173 hilf->PTPConnCount--;
174 new_oPCR=test_oPCR;
175
176// printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
177 result=cmp_lock(firesat, &test_oPCR, oPCR_address, old_oPCR, 2);
178 if (result < 0) {
179 printk("%s: cannot compare_swap oPCR\n",__func__);
180 return result;
181 }
182 }
183
184 } while (old_oPCR != test_oPCR);
185
186/* hilf = (OPCR*) &old_oPCR;
187 if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
188 cout << "deallocating 1394 resources\n";
189 unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
190 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
191 if (deallocate_1394_resources(iso_channel,BWU))
192 {
193 cout << "Deallocation of resources failed\n";
194 return -3;
195 }
196 }*/
197 }
198 return 0;
199} 171}