1 |
/* |
2 |
* Cisco C7200 (Predator) Simulation Platform. |
3 |
* Copyright (C) 2005-2006 Christophe Fillot. All rights reserved. |
4 |
* |
5 |
* EEPROM types: |
6 |
* - 0x3d: PA-4B |
7 |
* - 0x3e: PA-8B |
8 |
* |
9 |
* Vernon Missouri offered a PA-4B. |
10 |
* |
11 |
* It is based on the Munich32 chip: |
12 |
* http://www.infineon.com//upload/Document/cmc_upload/migrated_files/document_files/Datasheet/m32_34m.pdf |
13 |
* |
14 |
* There is also one TP3420A per BRI port. |
15 |
*/ |
16 |
|
17 |
#include <stdio.h> |
18 |
#include <stdlib.h> |
19 |
#include <string.h> |
20 |
#include <unistd.h> |
21 |
#include <errno.h> |
22 |
#include <pthread.h> |
23 |
#include <assert.h> |
24 |
|
25 |
#include "mips64.h" |
26 |
#include "dynamips.h" |
27 |
#include "memory.h" |
28 |
#include "device.h" |
29 |
#include "net.h" |
30 |
#include "net_io.h" |
31 |
#include "ptask.h" |
32 |
#include "dev_c7200.h" |
33 |
|
34 |
/* Debugging flags */ |
35 |
#define DEBUG_ACCESS 1 |
36 |
#define DEBUG_TRANSMIT 0 |
37 |
#define DEBUG_RECEIVE 0 |
38 |
|
39 |
/* PCI vendor/product codes */ |
40 |
#define BRI_PCI_VENDOR_ID 0x10ee |
41 |
#define BRI_PCI_PRODUCT_ID 0x4013 |
42 |
|
43 |
/* Memory used by the munich32 chip */ |
44 |
#define MUNICH32_MEM_SIZE 0x40000 |
45 |
|
46 |
/* Maximum packet size */ |
47 |
#define M32_MAX_PKT_SIZE 8192 |
48 |
|
49 |
/* 32 timeslots and 32 channels for a Munich32 chip */ |
50 |
#define M32_NR_TIMESLOTS 32 |
51 |
#define M32_NR_CHANNELS 32 |
52 |
|
53 |
/* Offsets */ |
54 |
#define M32_OFFSET_TS 0x0c /* Timeslots */ |
55 |
#define M32_OFFSET_CHAN 0x8c /* Channel specification */ |
56 |
#define M32_OFFSET_CRDA 0x28c /* Current RX descriptor address */ |
57 |
#define M32_OFFSET_CTDA 0x30c /* Current TX descriptor address */ |
58 |
|
59 |
/* Action Specification */ |
60 |
#define M32_AS_PCM_MASK 0xE0000000 /* PCM Highway Format */ |
61 |
#define M32_AS_PCM_SHIFT 29 |
62 |
#define M32_AS_MFL_MASK 0x1FFF0000 /* Maximum Frame Length */ |
63 |
#define M32_AS_MFL_SHIFT 16 |
64 |
#define M32_AS_IN 0x00008000 /* Initialization Procedure */ |
65 |
#define M32_AS_ICO 0x00004000 /* Initialize Channel Only */ |
66 |
#define M32_AS_CHAN_MASK 0x00001F00 /* Channel Number */ |
67 |
#define M32_AS_CHAN_SHIFT 8 |
68 |
#define M32_AS_IM 0x00000080 /* Interrupt Mask */ |
69 |
#define M32_AS_RES 0x00000040 /* Reset */ |
70 |
#define M32_AS_LOOPS_MASK 0x00000038 /* Loops (LOC,LOOP,LOOPI) */ |
71 |
#define M32_AS_LOOPS_SHIFT 3 |
72 |
#define M32_AS_IA 0x00000004 /* Interrupt Attention */ |
73 |
|
74 |
/* Interrupt Information */ |
75 |
#define M32_II_INT 0x80000000 /* Interrupt */ |
76 |
#define M32_II_VN3 0x20000000 /* Silicon version number */ |
77 |
#define M32_II_VN2 0x10000000 |
78 |
#define M32_II_VN1 0x08000000 |
79 |
#define M32_II_FRC 0x04000000 /* Framing bits changed */ |
80 |
#define M32_II_ARACK 0x00008000 /* Action Request Acknowledge */ |
81 |
#define M32_II_ARF 0x00004000 /* Action Request Failed */ |
82 |
#define M32_II_HI 0x00002000 /* Host Initiated Interrupt */ |
83 |
#define M32_II_FI 0x00001000 /* Frame Indication */ |
84 |
#define M32_II_IFC 0x00000800 /* Idle Flag Change */ |
85 |
#define M32_II_SF 0x00000400 /* Short Frame */ |
86 |
#define M32_II_ERR 0x00000200 /* Error condition */ |
87 |
#define M32_II_FO 0x00000100 /* Overflow/Underflow */ |
88 |
#define M32_II_RT 0x00000020 /* Direction (Transmit/Receive Int) */ |
89 |
|
90 |
/* Timeslot Assignment */ |
91 |
#define M32_TS_TTI 0x20000000 /* Transmit Timeslot Inhibit */ |
92 |
#define M32_TS_TCN_MASK 0x1F000000 /* Transmit Channel Number Mask */ |
93 |
#define M32_TS_TCN_SHIFT 24 |
94 |
#define M32_TS_TFM_MASK 0x00FF0000 /* Transmit Fill Mask */ |
95 |
#define M32_TS_TFM_SHIFT 16 |
96 |
#define M32_TS_RTI 0x00002000 /* Receive Timeslot Inhibit */ |
97 |
#define M32_TS_RCN_MASK 0x00001F00 /* Receive Channel Number Mask */ |
98 |
#define M32_TS_RCN_SHIFT 8 |
99 |
#define M32_TS_RFM_MASK 0x000000FF /* Receive Fill Mask */ |
100 |
#define M32_TS_RFM_SHIFT 0 |
101 |
|
102 |
/* Transmit Descriptor */ |
103 |
#define M32_TXDESC_FE 0x80000000 /* Frame End */ |
104 |
#define M32_TXDESC_HOLD 0x40000000 /* Hold=0: usable by Munich */ |
105 |
#define M32_TXDESC_HI 0x20000000 /* Host Initiated Interrupt */ |
106 |
#define M32_TXDESC_NO_MASK 0x1FFF0000 /* Number of bytes */ |
107 |
#define M32_TXDESC_NO_SHIFT 16 |
108 |
#define M32_TXDESC_V110 0x00008000 /* V.110/X.30 frame */ |
109 |
#define M32_TXDESC_CSM 0x00000800 /* CRC Select per Message */ |
110 |
#define M32_TXDESC_FNUM 0x000001FF /* Inter-Frame Time-Fill chars */ |
111 |
|
112 |
/* Munich32 TX descriptor */ |
113 |
struct m32_tx_desc { |
114 |
m_uint32_t params; /* Size + Flags */ |
115 |
m_uint32_t tdp; /* Transmit Data Pointer */ |
116 |
m_uint32_t ntdp; /* Next Transmit Descriptor Pointer */ |
117 |
}; |
118 |
|
119 |
/* Receive Descriptor (parameters) */ |
120 |
#define M32_RXDESC_HOLD 0x40000000 /* Hold */ |
121 |
#define M32_RXDESC_HI 0x20000000 /* Host Initiated Interrupt */ |
122 |
#define M32_RXDESC_NO_MASK 0x1FFF0000 /* Size of receive data section */ |
123 |
#define M32_RXDESC_NO_SHIFT 16 |
124 |
|
125 |
/* Receive Descriptor (status) */ |
126 |
#define M32_RXDESC_FE 0x80000000 /* Frame End */ |
127 |
#define M32_RXDESC_C 0x40000000 |
128 |
#define M32_RXDESC_BNO_MASK 0x1FFF0000 /* Bytes stored in data section */ |
129 |
#define M32_RXDESC_BNO_SHIFT 16 |
130 |
#define M32_RXDESC_SF 0x00004000 |
131 |
#define M32_RXDESC_LOSS 0x00002000 /* Error in sync pattern */ |
132 |
#define M32_RXDESC_CRCO 0x00001000 /* CRC error */ |
133 |
#define M32_RXDESC_NOB 0x00000800 /* Bit content not divisible by 8 */ |
134 |
#define M32_RXDESC_LFD 0x00000400 /* Long Frame Detected */ |
135 |
#define M32_RXDESC_RA 0x00000200 /* Receive Abort */ |
136 |
#define M32_RXDESC_ROF 0x00000100 /* Overflow of internal buffer */ |
137 |
|
138 |
/* Munich32 RX descriptor */ |
139 |
struct m32_rx_desc { |
140 |
m_uint32_t params; /* RX parameters (hold, hi, ...) */ |
141 |
m_uint32_t status; /* Status */ |
142 |
m_uint32_t rdp; /* Receive Data Pointer */ |
143 |
m_uint32_t nrdp; /* Next Receive Descriptor Pointer */ |
144 |
}; |
145 |
|
146 |
/* Munich32 channel */ |
147 |
struct m32_channel { |
148 |
m_uint32_t status; |
149 |
m_uint32_t frda; |
150 |
m_uint32_t ftda; |
151 |
m_uint32_t itbs; |
152 |
|
153 |
/* Physical addresses of current RX and TX descriptors */ |
154 |
m_uint32_t rx_current,tx_current; |
155 |
|
156 |
/* Poll mode */ |
157 |
u_int poll_mode; |
158 |
}; |
159 |
|
160 |
/* Munich32 chip data */ |
161 |
struct m32_data { |
162 |
/* Virtual machine */ |
163 |
vm_instance_t *vm; |
164 |
|
165 |
/* TX ring scanner task id */ |
166 |
ptask_id_t tx_tid; |
167 |
|
168 |
/* Interrupt Queue */ |
169 |
m_uint32_t iq_base_addr; |
170 |
m_uint32_t iq_cur_addr; |
171 |
u_int iq_size; |
172 |
|
173 |
/* Timeslots */ |
174 |
m_uint32_t timeslots[M32_NR_TIMESLOTS]; |
175 |
|
176 |
/* Channels */ |
177 |
struct m32_channel channels[M32_NR_CHANNELS]; |
178 |
|
179 |
/* Embedded config memory */ |
180 |
m_uint32_t cfg_mem[MUNICH32_MEM_SIZE/4]; |
181 |
}; |
182 |
|
183 |
/* === TP3420 SID === */ |
184 |
|
185 |
/* Activation / Desactivation */ |
186 |
#define TP3420_SID_NOP 0xFF /* No Operation */ |
187 |
#define TP3420_SID_PDN 0x00 /* Power Down */ |
188 |
#define TP3420_SID_PUP 0x20 /* Power Up */ |
189 |
#define TP3420_SID_DR 0x01 /* Deactivation Request */ |
190 |
#define TP3420_SID_FI2 0x02 /* Force Info 2 (NT Only) */ |
191 |
#define TP3420_SID_MMA 0x1F /* Monitor Mode Activation */ |
192 |
|
193 |
/* Device Modes */ |
194 |
#define TP3420_SID_NTA 0x04 /* NT Mode, Adaptive Sampling */ |
195 |
#define TP3420_SID_NTF 0x05 /* NT Mode, Fixed Sampling */ |
196 |
#define TP3420_SID_TES 0x06 /* TE Mode, Digital System Interface Slave */ |
197 |
#define TP3420_SID_TEM 0x07 /* TE Mode, Digital System Interface Master */ |
198 |
|
199 |
/* Digital Interface Formats */ |
200 |
#define TP3420_SID_DIF1 0x08 /* Digital System Interface Format 1 */ |
201 |
#define TP3420_SID_DIF2 0x09 /* Digital System Interface Format 2 */ |
202 |
#define TP3420_SID_DIF3 0x0A /* Digital System Interface Format 3 */ |
203 |
#define TP3420_SID_DIF4 0x0B /* Digital System Interface Format 4 */ |
204 |
|
205 |
/* BCLK Frequency Settings */ |
206 |
#define TP3420_SID_BCLK1 0x98 /* Set BCLK to 2.048 Mhz */ |
207 |
#define TP3420_SID_BCLK2 0x99 /* Set BCLK to 256 Khz */ |
208 |
#define TP3420_SID_BCLK3 0x9A /* Set BCLK to 512 Khz */ |
209 |
#define TP3420_SID_BCLK4 0x9B /* Set BCLK to 2.56 Mhz */ |
210 |
|
211 |
/* B Channel Exchange */ |
212 |
#define TP3420_SID_BDIR 0x0C /* B Channels Mapped Direct (B1->B1,B2->B2) */ |
213 |
#define TP3420_SID_BEX 0x0D /* B Channels Exchanged (B1->B2,B2->B1) */ |
214 |
|
215 |
/* D Channel Access */ |
216 |
#define TP3420_SID_DREQ1 0x0E /* D Channel Request, Class 1 Message */ |
217 |
#define TP3420_SID_DREQ2 0x0F /* D Channel Request, Class 2 Message */ |
218 |
|
219 |
/* D Channel Access Control */ |
220 |
#define TP3420_SID_DACCE 0x90 /* Enable D-Channel Access Mechanism */ |
221 |
#define TP3420_SID_DACCD 0x91 /* Disable D-Channel Access Mechanism */ |
222 |
#define TP3420_SID_EBIT0 0x96 /* Force Echo Bit to 0 */ |
223 |
#define TP3420_SID_EBITI 0x97 /* Force Echo Bit to Inverted Received D bit */ |
224 |
#define TP3420_SID_EBITN 0x9C /* Reset EBITI and EBIT0 to Normal Condition */ |
225 |
#define TP3420_SID_DCKE 0xF1 /* D Channel Clock Enable */ |
226 |
|
227 |
/* End Of Message (EOM) Interrupt */ |
228 |
#define TP3420_SID_EIE 0x10 /* EOM Interrupt Enabled */ |
229 |
#define TP3420_SID_EID 0x11 /* EOM Interrupt Disabled */ |
230 |
|
231 |
/* B1 Channel Enable/Disable */ |
232 |
#define TP3420_SID_B1E 0x14 /* B1 Channel Enabled */ |
233 |
#define TP3420_SID_B1D 0x15 /* B1 Channel Disabled */ |
234 |
|
235 |
/* B2 Channel Enable/Disable */ |
236 |
#define TP3420_SID_B2E 0x16 /* B2 Channel Enabled */ |
237 |
#define TP3420_SID_B2D 0x17 /* B2 Channel Disabled */ |
238 |
|
239 |
/* Loopback Tests Modes */ |
240 |
#define TP3420_SID_CAL 0x1B /* Clear All Loopbacks */ |
241 |
|
242 |
/* Control Device State Reading */ |
243 |
#define TP3420_SID_ENST 0x92 /* Enable the Device State Output on NOCST */ |
244 |
#define TP3420_SID_DISST 0x93 /* Disable the Device State Output on NOCST */ |
245 |
|
246 |
/* PIN Signal Selection */ |
247 |
#define TP3420_SID_PINDEF 0xE0 /* Redefine PIN signals */ |
248 |
|
249 |
/* TP3420 Status Register */ |
250 |
#define TP3420_SR_LSD 0x02 /* Line Signal Detected Far-End */ |
251 |
#define TP3420_SR_AP 0x03 /* Activation Pending */ |
252 |
#define TP3420_SR_AI 0x0C /* Activation Indication */ |
253 |
#define TP3420_SR_EI 0x0E /* Error Indication */ |
254 |
#define TP3420_SR_DI 0x0F /* Deactivation Indication */ |
255 |
#define TP3420_SR_EOM 0x06 /* End of D-channel TX message */ |
256 |
#define TP3420_SR_CON 0x07 /* Lost Contention for D channel */ |
257 |
|
258 |
/* NO Change Return status */ |
259 |
#define TP3420_SR_NOC 0x00 /* NOC Status after DISST command */ |
260 |
#define TP3420_SR_NOCST 0x80 /* NOC Status after ENST command */ |
261 |
|
262 |
/* BRI Channel Index */ |
263 |
#define BRI_CHAN_INDEX_B1 0 |
264 |
#define BRI_CHAN_INDEX_B2 1 |
265 |
#define BRI_CHAN_INDEX_D 2 |
266 |
|
267 |
/* PA-4B Data */ |
268 |
struct pa_4b_data { |
269 |
char *name; |
270 |
|
271 |
/* Virtual machine */ |
272 |
vm_instance_t *vm; |
273 |
|
274 |
/* Virtual device */ |
275 |
struct vdevice *dev; |
276 |
|
277 |
/* PCI device information */ |
278 |
struct pci_device *pci_dev; |
279 |
|
280 |
/* NetIO descriptor */ |
281 |
netio_desc_t *nio; |
282 |
|
283 |
/* Munich32 data and base offset */ |
284 |
struct m32_data m32_data; |
285 |
u_int m32_offset; |
286 |
}; |
287 |
|
288 |
/* Log a PA-4B/PA-8B message */ |
289 |
#define BRI_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
290 |
|
291 |
/* Read a configuration word */ |
292 |
static inline m_uint32_t m32_get_cfgw(struct m32_data *d,m_uint32_t offset) |
293 |
{ |
294 |
return(d->cfg_mem[offset >> 2]); |
295 |
} |
296 |
|
297 |
/* Write a configuration word */ |
298 |
static inline void m32_set_cfgw(struct m32_data *d,m_uint32_t offset, |
299 |
m_uint32_t val) |
300 |
{ |
301 |
d->cfg_mem[offset >> 2] = val; |
302 |
} |
303 |
|
304 |
/* Post an interrupt into the interrupt queue */ |
305 |
static int m32_post_interrupt(struct m32_data *d,m_uint32_t iq_value) |
306 |
{ |
307 |
if (!d->iq_base_addr) |
308 |
return(-1); |
309 |
|
310 |
/* The INT bit is mandatory */ |
311 |
iq_value |= M32_II_INT; |
312 |
|
313 |
#if 0 |
314 |
printf("M32: Posting interrupt iq_val=0x%8.8x at 0x%8.8x\n", |
315 |
iq_value,d->iq_cur_addr); |
316 |
#endif |
317 |
|
318 |
physmem_copy_u32_to_vm(d->vm,d->iq_cur_addr,iq_value); |
319 |
d->iq_cur_addr += sizeof(m_uint32_t); |
320 |
|
321 |
if (d->iq_cur_addr >= (d->iq_base_addr + d->iq_size)) |
322 |
d->iq_cur_addr = d->iq_base_addr; |
323 |
|
324 |
return(0); |
325 |
} |
326 |
|
327 |
/* Fetch a timeslot assignment */ |
328 |
static int m32_fetch_ts_assign(struct m32_data *d,u_int ts_id) |
329 |
{ |
330 |
m_uint32_t offset; |
331 |
|
332 |
offset = M32_OFFSET_TS + (ts_id * sizeof(m_uint32_t)); |
333 |
d->timeslots[ts_id] = m32_get_cfgw(d,offset); |
334 |
return(0); |
335 |
} |
336 |
|
337 |
/* Fetch all timeslot assignments */ |
338 |
static int m32_fetch_all_ts(struct m32_data *d) |
339 |
{ |
340 |
m_uint32_t offset = M32_OFFSET_TS; |
341 |
u_int i; |
342 |
|
343 |
for(i=0;i<M32_NR_TIMESLOTS;i++,offset+=sizeof(m_uint32_t)) |
344 |
d->timeslots[i] = m32_get_cfgw(d,offset); |
345 |
|
346 |
return(0); |
347 |
} |
348 |
|
349 |
/* Show timeslots assignments (debugging) */ |
350 |
static void m32_show_ts_assign(struct m32_data *d) |
351 |
{ |
352 |
m_uint32_t ts; |
353 |
u_int i; |
354 |
|
355 |
printf("MUNICH32 timeslots:\n"); |
356 |
|
357 |
for(i=0;i<M32_NR_TIMESLOTS;i++) { |
358 |
ts = d->timeslots[i]; |
359 |
|
360 |
if ((ts & (M32_TS_TTI|M32_TS_RTI)) != (M32_TS_TTI|M32_TS_RTI)) { |
361 |
printf(" Timeslot %2u: ",i); |
362 |
|
363 |
if (!(ts & M32_TS_TTI)) { |
364 |
printf("TCN=%2u TFM=0x%2.2x ", |
365 |
(ts & M32_TS_TCN_MASK) >> M32_TS_TCN_SHIFT, |
366 |
(ts & M32_TS_TFM_MASK) >> M32_TS_TFM_SHIFT); |
367 |
} |
368 |
|
369 |
if (!(ts & M32_TS_RTI)) { |
370 |
printf("RCN=%2u RFM=0x%2.2x", |
371 |
(ts & M32_TS_RCN_MASK) >> M32_TS_RCN_SHIFT, |
372 |
(ts & M32_TS_RFM_MASK) >> M32_TS_RFM_SHIFT); |
373 |
} |
374 |
|
375 |
printf("\n"); |
376 |
} |
377 |
} |
378 |
|
379 |
printf("\n"); |
380 |
} |
381 |
|
382 |
/* Show info about a channels (debugging) */ |
383 |
static void m32_show_channel(struct m32_data *d,u_int chan_id) |
384 |
{ |
385 |
struct m32_channel *chan; |
386 |
|
387 |
chan = &d->channels[chan_id]; |
388 |
printf("M32 Channel %u:\n",chan_id); |
389 |
printf(" Status : 0x%8.8x\n",chan->status); |
390 |
printf(" FRDA : 0x%8.8x\n",chan->frda); |
391 |
printf(" FTDA : 0x%8.8x\n",chan->ftda); |
392 |
printf(" ITBS : 0x%8.8x\n",chan->itbs); |
393 |
} |
394 |
|
395 |
/* Fetch a channel specification */ |
396 |
static int m32_fetch_chan_spec(struct m32_data *d,u_int chan_id) |
397 |
{ |
398 |
struct m32_channel *chan; |
399 |
m_uint32_t offset; |
400 |
|
401 |
offset = M32_OFFSET_CHAN + (chan_id * 4 * sizeof(m_uint32_t)); |
402 |
chan = &d->channels[chan_id]; |
403 |
|
404 |
chan->status = m32_get_cfgw(d,offset); |
405 |
chan->frda = m32_get_cfgw(d,offset+4); |
406 |
chan->ftda = m32_get_cfgw(d,offset+8); |
407 |
chan->itbs = m32_get_cfgw(d,offset+12); |
408 |
|
409 |
chan->poll_mode = 0; |
410 |
chan->rx_current = chan->frda; |
411 |
chan->tx_current = chan->ftda; |
412 |
|
413 |
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); |
414 |
|
415 |
#if 1 |
416 |
if (chan_id == 2) { |
417 |
printf("M32: Fetched channel %u\n",chan_id); |
418 |
//m32_show_ts_assign(d); |
419 |
m32_show_channel(d,chan_id); |
420 |
} |
421 |
#endif |
422 |
return(0); |
423 |
} |
424 |
|
425 |
/* Fetch all channel specifications */ |
426 |
static void m32_fetch_all_chan_spec(struct m32_data *d) |
427 |
{ |
428 |
u_int i; |
429 |
|
430 |
for(i=0;i<M32_NR_CHANNELS;i++) |
431 |
m32_fetch_chan_spec(d,i); |
432 |
} |
433 |
|
434 |
/* Try to acquire the specified TX descriptor */ |
435 |
static int m32_tx_acquire(struct m32_data *d,m_uint32_t txd_addr, |
436 |
struct m32_tx_desc *txd) |
437 |
{ |
438 |
m_uint32_t params; |
439 |
|
440 |
if (!(params = physmem_copy_u32_from_vm(d->vm,txd_addr)) & M32_TXDESC_HOLD) |
441 |
return(FALSE); |
442 |
|
443 |
txd->params = params; |
444 |
txd->tdp = physmem_copy_u32_from_vm(d->vm,txd_addr+4); |
445 |
txd->ntdp = physmem_copy_u32_from_vm(d->vm,txd_addr+8); |
446 |
return(TRUE); |
447 |
} |
448 |
|
449 |
/* Try to acquire the next TX descriptor */ |
450 |
static int m32_tx_acquire_next(struct m32_data *d,m_uint32_t *txd_addr) |
451 |
{ |
452 |
m_uint32_t params; |
453 |
|
454 |
/* HOLD bit must be reset */ |
455 |
if ((params = physmem_copy_u32_from_vm(d->vm,*txd_addr)) & M32_TXDESC_HOLD) |
456 |
return(FALSE); |
457 |
|
458 |
*txd_addr = physmem_copy_u32_from_vm(d->vm,(*txd_addr)+8); |
459 |
return(TRUE); |
460 |
} |
461 |
|
462 |
/* Scan a channel TX ring */ |
463 |
static inline int m32_tx_scan(struct m32_data *d,u_int chan_id) |
464 |
{ |
465 |
struct m32_channel *chan = &d->channels[chan_id]; |
466 |
m_uint8_t pkt[M32_MAX_PKT_SIZE]; |
467 |
struct m32_tx_desc txd; |
468 |
m_uint32_t pkt_len; |
469 |
|
470 |
if (!chan->tx_current) |
471 |
return(FALSE); |
472 |
|
473 |
switch(chan->poll_mode) { |
474 |
case 0: |
475 |
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); |
476 |
|
477 |
/* Try to transmit data */ |
478 |
if (!m32_tx_acquire(d,chan->tx_current,&txd)) |
479 |
return(FALSE); |
480 |
|
481 |
printf("M32: TX scanner for channel %u (tx_current=0x%8.8x)\n", |
482 |
chan_id,chan->tx_current); |
483 |
|
484 |
printf("M32: params=0x%8.8x, next=0x%8.8x.\n",txd.params,txd.ntdp); |
485 |
|
486 |
/* The descriptor has been acquired */ |
487 |
pkt_len = (txd.params & M32_TXDESC_NO_MASK) >> M32_TXDESC_NO_SHIFT; |
488 |
physmem_copy_from_vm(d->vm,pkt,txd.tdp,pkt_len); |
489 |
|
490 |
printf("M32: data_ptr=0x%x, len=%u\n",txd.tdp,pkt_len); |
491 |
mem_dump(stdout,pkt,pkt_len); |
492 |
|
493 |
/* Poll the next descriptor (wait for HOLD bit to be reset */ |
494 |
chan->poll_mode = 1; |
495 |
|
496 |
if (txd.params & M32_TXDESC_FE) { |
497 |
m32_post_interrupt(d,M32_II_FI | chan_id); |
498 |
vm_set_irq(d->vm,2); |
499 |
} |
500 |
|
501 |
break; |
502 |
|
503 |
case 1: |
504 |
if (!m32_tx_acquire_next(d,&chan->tx_current)) |
505 |
return(FALSE); |
506 |
|
507 |
printf("M32: branching on next descriptor 0x%x\n",chan->tx_current); |
508 |
chan->poll_mode = 0; |
509 |
break; |
510 |
} |
511 |
|
512 |
return(TRUE); |
513 |
} |
514 |
|
515 |
/* Scan the all channel TX rings */ |
516 |
static void m32_tx_scan_all_channels(struct m32_data *d) |
517 |
{ |
518 |
u_int i; |
519 |
|
520 |
for(i=0;i<M32_NR_CHANNELS;i++) |
521 |
m32_tx_scan(d,i); |
522 |
} |
523 |
|
524 |
/* |
525 |
* Handle an action request. |
526 |
* |
527 |
* IN, ICO and RES bits are mutually exclusive. |
528 |
*/ |
529 |
static int m32_action_req(struct m32_data *d,m_uint32_t action) |
530 |
{ |
531 |
u_int chan_id; |
532 |
|
533 |
/* Define a new Interrupt Queue */ |
534 |
if (action & M32_AS_IA) { |
535 |
d->iq_base_addr = d->iq_cur_addr = m32_get_cfgw(d,4); |
536 |
d->iq_size = ((m32_get_cfgw(d,8) & 0xFF) + 1) * 16 * sizeof(m_uint32_t); |
537 |
} |
538 |
|
539 |
/* Initialization Procedure */ |
540 |
if (action & M32_AS_IN) { |
541 |
/* Fetch all timeslots assignments */ |
542 |
m32_fetch_all_ts(d); |
543 |
|
544 |
/* Fetch specification of the specified channel */ |
545 |
chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT; |
546 |
m32_fetch_chan_spec(d,chan_id); |
547 |
|
548 |
/* Generate acknowledge */ |
549 |
if (!(action & M32_AS_IM)) |
550 |
m32_post_interrupt(d,M32_II_ARACK); |
551 |
} |
552 |
|
553 |
/* Initialize Channel Only */ |
554 |
if (action & M32_AS_ICO) { |
555 |
/* Fetch specification of the specified channel */ |
556 |
chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT; |
557 |
m32_fetch_chan_spec(d,chan_id); |
558 |
|
559 |
/* Generate acknowledge */ |
560 |
if (!(action & M32_AS_IM)) |
561 |
m32_post_interrupt(d,M32_II_ARACK); |
562 |
} |
563 |
|
564 |
/* Reset */ |
565 |
if (action & M32_AS_RES) { |
566 |
/* Fetch all timeslots assignments */ |
567 |
m32_fetch_all_ts(d); |
568 |
|
569 |
/* Fetch all channel specifications */ |
570 |
m32_fetch_all_chan_spec(d); |
571 |
|
572 |
/* Generate acknowledge */ |
573 |
if (!(action & M32_AS_IM)) |
574 |
m32_post_interrupt(d,M32_II_ARACK); |
575 |
} |
576 |
|
577 |
return(0); |
578 |
} |
579 |
|
580 |
/* Munich32 general access function */ |
581 |
static void *m32_gen_access(struct m32_data *d,cpu_mips_t *cpu, |
582 |
m_uint32_t offset,u_int op_size,u_int op_type, |
583 |
m_uint64_t *data) |
584 |
{ |
585 |
u_int p; |
586 |
|
587 |
switch(offset) { |
588 |
/* Action Specification */ |
589 |
case 0x0: |
590 |
if (op_type == MTS_WRITE) |
591 |
m32_action_req(d,*data); |
592 |
return NULL; |
593 |
|
594 |
/* Configuration memory */ |
595 |
default: |
596 |
switch(op_size) { |
597 |
case 4: |
598 |
if (op_type == MTS_READ) |
599 |
*data = m32_get_cfgw(d,offset); |
600 |
else |
601 |
m32_set_cfgw(d,offset,*data); |
602 |
break; |
603 |
|
604 |
case 1: |
605 |
if (op_type == MTS_READ) { |
606 |
*data = m32_get_cfgw(d,offset & ~0x03); |
607 |
*data >>= (24 - ((offset & 0x03) << 3)); |
608 |
*data &= 0xFF; |
609 |
} else { |
610 |
printf("UNSUPPORTED(1)!!!!\n"); |
611 |
} |
612 |
break; |
613 |
|
614 |
case 2: |
615 |
if (op_type == MTS_READ) { |
616 |
*data = m32_get_cfgw(d,offset & ~0x03); |
617 |
*data >>= (16 - ((offset & 0x03) << 3)); |
618 |
*data &= 0xFFFF; |
619 |
} else { |
620 |
printf("UNSUPPORTED(2)!!!!\n"); |
621 |
} |
622 |
break; |
623 |
|
624 |
case 8: |
625 |
if (op_type == MTS_READ) { |
626 |
*data = (m_uint64_t)m32_get_cfgw(d,offset) << 32; |
627 |
*data |= m32_get_cfgw(d,offset+4); |
628 |
} else { |
629 |
printf("UNSUPPORTED(8)!!!!\n"); |
630 |
} |
631 |
break; |
632 |
|
633 |
default: |
634 |
printf("UNSUPPORTED (size=%u)!!!\n",op_size); |
635 |
} |
636 |
} |
637 |
|
638 |
return NULL; |
639 |
} |
640 |
|
641 |
/* |
642 |
* pa_4b_access() |
643 |
*/ |
644 |
void *pa_4b_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, |
645 |
u_int op_size,u_int op_type,m_uint64_t *data) |
646 |
{ |
647 |
struct pa_4b_data *d = dev->priv_data; |
648 |
static m_uint32_t test1,test2,test3; |
649 |
|
650 |
if (op_type == MTS_READ) |
651 |
*data = 0xFFFFFFFF; |
652 |
|
653 |
#if DEBUG_ACCESS |
654 |
if (offset >= MUNICH32_MEM_SIZE) { |
655 |
if (op_type == MTS_READ) { |
656 |
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx " |
657 |
"(op_size=%u)\n",offset,cpu->pc,op_size); |
658 |
} else { |
659 |
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
660 |
"val = 0x%llx (op_size=%u)\n",offset,cpu->pc,*data,op_size); |
661 |
} |
662 |
} |
663 |
#endif |
664 |
|
665 |
/* Specific cases */ |
666 |
switch(offset) { |
667 |
case 0x40008: |
668 |
if (op_type == MTS_READ) |
669 |
*data = 0xFF; |
670 |
break; |
671 |
|
672 |
case 0x40030: |
673 |
if (op_type == MTS_READ) |
674 |
*data = 0xFF; |
675 |
break; |
676 |
|
677 |
case 0x40000: |
678 |
if (op_type == MTS_READ) |
679 |
*data = 0xFFFF; |
680 |
break; |
681 |
|
682 |
case 0x40020: |
683 |
if (op_type == MTS_READ) |
684 |
*data = 0xFFFFFFFF; //test2; |
685 |
else |
686 |
test2 = *data; |
687 |
break; |
688 |
|
689 |
case 0x40021: |
690 |
if (op_type == MTS_READ) |
691 |
*data = 0xFF; //test3; |
692 |
else |
693 |
test3 = *data; |
694 |
break; |
695 |
|
696 |
case 0x40023: |
697 |
if (op_type == MTS_READ) |
698 |
*data = 0xFF; |
699 |
break; |
700 |
|
701 |
case 0x40040: |
702 |
if (op_type == MTS_READ) |
703 |
*data = 0x04; |
704 |
break; |
705 |
|
706 |
/* Channels enabled ? */ |
707 |
case 0x40044: |
708 |
if (op_type == MTS_READ) |
709 |
*data = 0xFF; /* 0x02 */ |
710 |
break; |
711 |
|
712 |
/* SID */ |
713 |
case 0x40050: |
714 |
if (op_type == MTS_WRITE) { |
715 |
test1 = *data; |
716 |
} else { |
717 |
switch(test1) { |
718 |
case TP3420_SID_PUP: |
719 |
*data = TP3420_SR_AI; |
720 |
vm_set_irq(d->vm,C7200_PA_MGMT_IRQ); |
721 |
break; |
722 |
case TP3420_SID_ENST: |
723 |
*data = 0xB0; |
724 |
break; |
725 |
default: |
726 |
*data = 0x03; |
727 |
break; |
728 |
} |
729 |
} |
730 |
break; |
731 |
|
732 |
default: |
733 |
if (offset < MUNICH32_MEM_SIZE) |
734 |
return(m32_gen_access(&d->m32_data,cpu,offset - d->m32_offset, |
735 |
op_size,op_type,data)); |
736 |
} |
737 |
|
738 |
return NULL; |
739 |
} |
740 |
|
741 |
/* |
742 |
* pci_munich32_read() |
743 |
*/ |
744 |
static m_uint32_t pci_munich32_read(cpu_mips_t *cpu,struct pci_device *dev, |
745 |
int reg) |
746 |
{ |
747 |
struct pa_4b_data *d = dev->priv_data; |
748 |
|
749 |
#if DEBUG_ACCESS |
750 |
BRI_LOG(d,"read PCI register 0x%x\n",reg); |
751 |
#endif |
752 |
switch(reg) { |
753 |
case PCI_REG_BAR0: |
754 |
return(d->dev->phys_addr); |
755 |
default: |
756 |
return(0); |
757 |
} |
758 |
} |
759 |
|
760 |
/* |
761 |
* pci_munich32_write() |
762 |
*/ |
763 |
static void pci_munich32_write(cpu_mips_t *cpu,struct pci_device *dev, |
764 |
int reg,m_uint32_t value) |
765 |
{ |
766 |
struct pa_4b_data *d = dev->priv_data; |
767 |
|
768 |
#if DEBUG_ACCESS |
769 |
BRI_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg); |
770 |
#endif |
771 |
|
772 |
switch(reg) { |
773 |
case PCI_REG_BAR0: |
774 |
vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); |
775 |
BRI_LOG(d,"registers are mapped at 0x%x\n",value); |
776 |
break; |
777 |
} |
778 |
} |
779 |
|
780 |
/* |
781 |
* dev_c7200_bri_init() |
782 |
* |
783 |
* Add a PA-4B/PA-8B port adapter into specified slot. |
784 |
*/ |
785 |
int dev_c7200_pa_bri_init(c7200_t *router,char *name,u_int pa_bay) |
786 |
{ |
787 |
struct pci_device *pci_dev; |
788 |
struct pa_4b_data *d; |
789 |
struct vdevice *dev; |
790 |
|
791 |
/* Allocate the private data structure for PA-4B chip */ |
792 |
if (!(d = malloc(sizeof(*d)))) { |
793 |
fprintf(stderr,"%s (PA-4B): out of memory\n",name); |
794 |
return(-1); |
795 |
} |
796 |
|
797 |
memset(d,0,sizeof(*d)); |
798 |
d->m32_offset = 0x08; |
799 |
d->m32_data.vm = router->vm; |
800 |
|
801 |
/* Set the EEPROM */ |
802 |
c7200_pa_set_eeprom(router,pa_bay,cisco_eeprom_find_pa("PA-4B")); |
803 |
|
804 |
/* Add as PCI device PA-4B */ |
805 |
pci_dev = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, |
806 |
BRI_PCI_VENDOR_ID,BRI_PCI_PRODUCT_ID, |
807 |
0,0,C7200_NETIO_IRQ,d, |
808 |
NULL,pci_munich32_read,pci_munich32_write); |
809 |
|
810 |
if (!pci_dev) { |
811 |
fprintf(stderr,"%s (PA-4B): unable to create PCI device.\n",name); |
812 |
return(-1); |
813 |
} |
814 |
|
815 |
/* Create the PA-4B structure */ |
816 |
d->name = name; |
817 |
d->pci_dev = pci_dev; |
818 |
d->vm = router->vm; |
819 |
|
820 |
/* Create the device itself */ |
821 |
if (!(dev = dev_create(name))) { |
822 |
fprintf(stderr,"%s (PA-4B): unable to create device.\n",name); |
823 |
return(-1); |
824 |
} |
825 |
|
826 |
dev->phys_len = 0x800000; |
827 |
dev->handler = pa_4b_access; |
828 |
|
829 |
/* Store device info */ |
830 |
dev->priv_data = d; |
831 |
d->dev = dev; |
832 |
|
833 |
/* Map this device to the VM */ |
834 |
vm_bind_device(router->vm,dev); |
835 |
|
836 |
/* Store device info into the router structure */ |
837 |
return(c7200_pa_set_drvinfo(router,pa_bay,d)); |
838 |
} |
839 |
|
840 |
/* Remove a PA-4B from the specified slot */ |
841 |
int dev_c7200_pa_bri_shutdown(c7200_t *router,u_int pa_bay) |
842 |
{ |
843 |
struct c7200_pa_bay *bay; |
844 |
struct pa_4b_data *d; |
845 |
|
846 |
if (!(bay = c7200_pa_get_info(router,pa_bay))) |
847 |
return(-1); |
848 |
|
849 |
d = bay->drv_info; |
850 |
|
851 |
/* Remove the PA EEPROM */ |
852 |
c7200_pa_unset_eeprom(router,pa_bay); |
853 |
|
854 |
/* Remove the PCI device */ |
855 |
pci_dev_remove(d->pci_dev); |
856 |
|
857 |
/* Remove the device from the CPU address space */ |
858 |
vm_unbind_device(router->vm,d->dev); |
859 |
cpu_group_rebuild_mts(router->vm->cpu_group); |
860 |
|
861 |
/* Free the device structure itself */ |
862 |
free(d->dev); |
863 |
free(d); |
864 |
return(0); |
865 |
} |
866 |
|
867 |
/* Bind a Network IO descriptor to a specific port */ |
868 |
int dev_c7200_pa_bri_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, |
869 |
netio_desc_t *nio) |
870 |
{ |
871 |
struct pa_4b_data *d; |
872 |
|
873 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
874 |
return(-1); |
875 |
|
876 |
if (d->nio != NULL) |
877 |
return(-1); |
878 |
|
879 |
d->nio = nio; |
880 |
|
881 |
/* TEST */ |
882 |
d->m32_data.tx_tid = ptask_add((ptask_callback)m32_tx_scan_all_channels,&d->m32_data,NULL); |
883 |
|
884 |
//netio_rxl_add(nio,(netio_rx_handler_t)dev_pa_4b_handle_rxring,d,NULL); |
885 |
return(0); |
886 |
} |
887 |
|
888 |
/* Bind a Network IO descriptor to a specific port */ |
889 |
int dev_c7200_pa_bri_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) |
890 |
{ |
891 |
struct pa_4b_data *d; |
892 |
|
893 |
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
894 |
return(-1); |
895 |
|
896 |
if (d->nio) { |
897 |
/* TEST */ |
898 |
ptask_remove(d->m32_data.tx_tid); |
899 |
|
900 |
//netio_rxl_remove(d->nio); |
901 |
d->nio = NULL; |
902 |
} |
903 |
return(0); |
904 |
} |
905 |
|
906 |
/* PA-4B driver */ |
907 |
struct c7200_pa_driver dev_c7200_pa_4b_driver = { |
908 |
"PA-4B", 0, |
909 |
dev_c7200_pa_bri_init, |
910 |
dev_c7200_pa_bri_shutdown, |
911 |
dev_c7200_pa_bri_set_nio, |
912 |
dev_c7200_pa_bri_unset_nio, |
913 |
NULL, |
914 |
}; |