5 * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
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.
16 #include <highlevel.h>
19 #include <ieee1394_core.h>
20 #include <ieee1394_transactions.h>
25 __u8 PTPConnCount
: 6 ; // Point to point connect. counter
26 __u8 BrConnCount
: 1 ; // Broadcast connection counter
27 __u8 OnLine
: 1 ; // On Line
29 __u8 ChNr
: 6 ; // Channel number
30 __u8 Res
: 2 ; // Reserved
32 __u8 PayloadHi
: 2 ; // Payoad high bits
33 __u8 OvhdID
: 4 ; // Overhead ID
34 __u8 DataRate
: 2 ; // Data Rate
36 __u8 PayloadLo
; // Payoad low byte
39 #define FIRESAT_SPEED IEEE1394_SPEED_400
41 /* hpsb_lock is being removed from the kernel-source,
42 * therefor we define our own 'firesat_hpsb_lock'*/
44 int send_packet_and_wait(struct hpsb_packet
*packet
);
46 int firesat_hpsb_lock(struct hpsb_host
*host
, nodeid_t node
, unsigned int generation
,
47 u64 addr
, int extcode
, quadlet_t
* data
, quadlet_t arg
) {
49 struct hpsb_packet
*packet
;
52 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
54 packet
= hpsb_make_lockpacket(host
, node
, addr
, extcode
, data
, arg
);
58 packet
->generation
= generation
;
59 retval
= send_packet_and_wait(packet
);
63 retval
= hpsb_packet_success(packet
);
66 *data
= packet
->data
[0];
70 hpsb_free_tlabel(packet
);
71 hpsb_free_packet(packet
);
77 static int cmp_read(struct firesat
*firesat
, void *buffer
, u64 addr
, size_t length
) {
79 if(down_interruptible(&firesat
->avc_sem
))
82 ret
= hpsb_read(firesat
->host
, firesat
->nodeentry
->nodeid
, firesat
->nodeentry
->generation
,
83 addr
, buffer
, length
);
85 up(&firesat
->avc_sem
);
89 static int cmp_lock(struct firesat
*firesat
, quadlet_t
*data
, u64 addr
, quadlet_t arg
, int ext_tcode
) {
91 if(down_interruptible(&firesat
->avc_sem
))
94 ret
= firesat_hpsb_lock(firesat
->host
, firesat
->nodeentry
->nodeid
, firesat
->nodeentry
->generation
,
95 addr
, ext_tcode
, data
, arg
);
97 up(&firesat
->avc_sem
);
101 //try establishing a point-to-point connection (may be interrupted by a busreset
102 int try_CMPEstablishPPconnection(struct firesat
*firesat
, int output_plug
, int iso_channel
) {
103 unsigned int BWU
; //bandwidth to allocate
105 quadlet_t old_oPCR
,test_oPCR
= 0x0;
106 u64 oPCR_address
=0xfffff0000904ull
+(output_plug
<< 2);
107 int result
=cmp_read(firesat
, &test_oPCR
, oPCR_address
, 4);
109 /* printk(KERN_INFO "%s: nodeid = %d\n",__func__,firesat->nodeentry->nodeid); */
112 printk("%s: cannot read oPCR\n", __func__
);
115 /* printk(KERN_INFO "%s: oPCR = %08x\n",__func__,test_oPCR); */
117 OPCR
*hilf
= (OPCR
*) &test_oPCR
;
120 printk("%s: Output offline; oPCR: %08x\n", __func__
, test_oPCR
);
126 if (hilf
->PTPConnCount
) {
127 if (hilf
->ChNr
!= iso_channel
) {
128 printk("%s: Output plug has already connection on channel %u; cannot change it to channel %u\n",__func__
,hilf
->ChNr
,iso_channel
);
131 printk(KERN_INFO
"%s: Overlaying existing connection; connection counter was: %u\n",__func__
, hilf
->PTPConnCount
);
132 BWU
=0; //we allocate no bandwidth (is this necessary?)
134 hilf
->ChNr
=iso_channel
;
135 hilf
->DataRate
=FIRESAT_SPEED
;
137 hilf
->OvhdID
=0; //FIXME: that is for worst case -> optimize
138 BWU
=hilf
->OvhdID
?hilf
->OvhdID
*32:512;
139 BWU
+= (hilf
->PayloadLo
+ (hilf
->PayloadHi
<< 8) +3) * (2 << (3-hilf
->DataRate
));
140 /* if (allocate_1394_resources(iso_channel,BWU))
142 cout << "Allocation of resources failed\n";
147 hilf
->PTPConnCount
++;
149 /* printk(KERN_INFO "%s: trying compare_swap...\n",__func__); */
150 /* printk(KERN_INFO "%s: oPCR_old: %08x, oPCR_new: %08x\n",__func__, old_oPCR, new_oPCR); */
151 result
=cmp_lock(firesat
, &test_oPCR
, oPCR_address
, old_oPCR
, 2);
154 printk("%s: cannot compare_swap oPCR\n",__func__
);
157 if ((old_oPCR
!= test_oPCR
) && (!((OPCR
*) &old_oPCR
)->PTPConnCount
))
159 printk("%s: change of oPCR failed -> freeing resources\n",__func__
);
160 // hilf= (OPCR*) &new_oPCR;
161 // unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
162 // BWU += (hilf->Payload+3) * (2 << (3-hilf->DataRate));
163 /* if (deallocate_1394_resources(iso_channel,BWU))
166 cout << "Deallocation of resources failed\n";
172 while (old_oPCR
!= test_oPCR
);
177 //try breaking a point-to-point connection (may be interrupted by a busreset
178 int try_CMPBreakPPconnection(struct firesat
*firesat
, int output_plug
,int iso_channel
) {
179 quadlet_t old_oPCR
,test_oPCR
;
181 u64 oPCR_address
=0xfffff0000904ull
+(output_plug
<< 2);
182 int result
=cmp_read(firesat
, &test_oPCR
, oPCR_address
, 4);
184 /* printk(KERN_INFO "%s\n",__func__); */
187 printk("%s: cannot read oPCR\n", __func__
);
191 OPCR
*hilf
= (OPCR
*) &test_oPCR
;
193 if (!hilf
->OnLine
|| !hilf
->PTPConnCount
|| hilf
->ChNr
!= iso_channel
) {
194 printk("%s: Output plug does not have PtP-connection on that channel; oPCR: %08x\n", __func__
, test_oPCR
);
199 hilf
->PTPConnCount
--;
202 // printk(KERN_INFO "%s: trying compare_swap...\n", __func__);
203 result
=cmp_lock(firesat
, &test_oPCR
, oPCR_address
, old_oPCR
, 2);
205 printk("%s: cannot compare_swap oPCR\n",__func__
);
210 } while (old_oPCR
!= test_oPCR
);
212 /* hilf = (OPCR*) &old_oPCR;
213 if (hilf->PTPConnCount == 1) { // if we were the last owner of this connection
214 cout << "deallocating 1394 resources\n";
215 unsigned int BWU=hilf->OvhdID?hilf->OvhdID*32:512;
216 BWU += (hilf->PayloadLo + (hilf->PayloadHi << 8) +3) * (2 << (3-hilf->DataRate));
217 if (deallocate_1394_resources(iso_channel,BWU))
219 cout << "Deallocation of resources failed\n";
227 static void complete_packet(void *data
) {
228 complete((struct completion
*) data
);
231 int send_packet_and_wait(struct hpsb_packet
*packet
) {
232 struct completion done
;
235 init_completion(&done
);
236 hpsb_set_packet_complete_task(packet
, complete_packet
, &done
);
237 retval
= hpsb_send_packet(packet
);
239 wait_for_completion(&done
);