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