diff options
Diffstat (limited to 'drivers/media/dvb/firesat/cmp.c')
-rw-r--r-- | drivers/media/dvb/firesat/cmp.c | 252 |
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 | ||
27 | typedef 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 | ||
45 | static int cmp_read(struct firesat *firesat, void *buf, u64 addr, size_t len) | 29 | static 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 | ||
59 | static int cmp_lock(struct firesat *firesat, quadlet_t *data, u64 addr, | 44 | static 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 | 61 | static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift) |
76 | int 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 | |||
66 | static 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) { | 81 | int 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 { | 92 | repeat: |
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 | 140 | void cmp_break_pp_connection(struct firesat *firesat, int plug, int channel) |
152 | int 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 | |||
149 | repeat: | ||
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 | } |