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 | } |
