1 |
dpavlin |
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 |
|
|
/* EEPROM definition (3D = PA-4B, 3E = PA-8B) */ |
289 |
|
|
static const m_uint16_t eeprom_pa_4b_data[64] = { |
290 |
|
|
0x013D, 0x0202, 0xffff, 0xffff, 0x490C, 0x7806, 0x0000, 0x0000, |
291 |
|
|
0x5000, 0x0000, 0x0208, 0x1900, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, |
292 |
|
|
}; |
293 |
|
|
|
294 |
|
|
static const struct c7200_eeprom eeprom_pa_4b = { |
295 |
|
|
"PA-4B", (m_uint16_t *)eeprom_pa_4b_data, |
296 |
|
|
sizeof(eeprom_pa_4b_data)/2, |
297 |
|
|
}; |
298 |
|
|
|
299 |
|
|
/* Log a PA-4B/PA-8B message */ |
300 |
|
|
#define BRI_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
301 |
|
|
|
302 |
|
|
/* Read a configuration word */ |
303 |
|
|
static inline m_uint32_t m32_get_cfgw(struct m32_data *d,m_uint32_t offset) |
304 |
|
|
{ |
305 |
|
|
return(d->cfg_mem[offset >> 2]); |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
/* Write a configuration word */ |
309 |
|
|
static inline void m32_set_cfgw(struct m32_data *d,m_uint32_t offset, |
310 |
|
|
m_uint32_t val) |
311 |
|
|
{ |
312 |
|
|
d->cfg_mem[offset >> 2] = val; |
313 |
|
|
} |
314 |
|
|
|
315 |
|
|
/* Post an interrupt into the interrupt queue */ |
316 |
|
|
static int m32_post_interrupt(struct m32_data *d,m_uint32_t iq_value) |
317 |
|
|
{ |
318 |
|
|
if (!d->iq_base_addr) |
319 |
|
|
return(-1); |
320 |
|
|
|
321 |
|
|
/* The INT bit is mandatory */ |
322 |
|
|
iq_value |= M32_II_INT; |
323 |
|
|
|
324 |
|
|
#if 0 |
325 |
|
|
printf("M32: Posting interrupt iq_val=0x%8.8x at 0x%8.8x\n", |
326 |
|
|
iq_value,d->iq_cur_addr); |
327 |
|
|
#endif |
328 |
|
|
|
329 |
|
|
physmem_copy_u32_to_vm(d->vm,d->iq_cur_addr,iq_value); |
330 |
|
|
d->iq_cur_addr += sizeof(m_uint32_t); |
331 |
|
|
|
332 |
|
|
if (d->iq_cur_addr >= (d->iq_base_addr + d->iq_size)) |
333 |
|
|
d->iq_cur_addr = d->iq_base_addr; |
334 |
|
|
|
335 |
|
|
return(0); |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
/* Fetch a timeslot assignment */ |
339 |
|
|
static int m32_fetch_ts_assign(struct m32_data *d,u_int ts_id) |
340 |
|
|
{ |
341 |
|
|
m_uint32_t offset; |
342 |
|
|
|
343 |
|
|
offset = M32_OFFSET_TS + (ts_id * sizeof(m_uint32_t)); |
344 |
|
|
d->timeslots[ts_id] = m32_get_cfgw(d,offset); |
345 |
|
|
return(0); |
346 |
|
|
} |
347 |
|
|
|
348 |
|
|
/* Fetch all timeslot assignments */ |
349 |
|
|
static int m32_fetch_all_ts(struct m32_data *d) |
350 |
|
|
{ |
351 |
|
|
m_uint32_t offset = M32_OFFSET_TS; |
352 |
|
|
u_int i; |
353 |
|
|
|
354 |
|
|
for(i=0;i<M32_NR_TIMESLOTS;i++,offset+=sizeof(m_uint32_t)) |
355 |
|
|
d->timeslots[i] = m32_get_cfgw(d,offset); |
356 |
|
|
|
357 |
|
|
return(0); |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
/* Show timeslots assignments (debugging) */ |
361 |
|
|
static void m32_show_ts_assign(struct m32_data *d) |
362 |
|
|
{ |
363 |
|
|
m_uint32_t ts; |
364 |
|
|
u_int i; |
365 |
|
|
|
366 |
|
|
printf("MUNICH32 timeslots:\n"); |
367 |
|
|
|
368 |
|
|
for(i=0;i<M32_NR_TIMESLOTS;i++) { |
369 |
|
|
ts = d->timeslots[i]; |
370 |
|
|
|
371 |
|
|
if ((ts & (M32_TS_TTI|M32_TS_RTI)) != (M32_TS_TTI|M32_TS_RTI)) { |
372 |
|
|
printf(" Timeslot %2u: ",i); |
373 |
|
|
|
374 |
|
|
if (!(ts & M32_TS_TTI)) { |
375 |
|
|
printf("TCN=%2u TFM=0x%2.2x ", |
376 |
|
|
(ts & M32_TS_TCN_MASK) >> M32_TS_TCN_SHIFT, |
377 |
|
|
(ts & M32_TS_TFM_MASK) >> M32_TS_TFM_SHIFT); |
378 |
|
|
} |
379 |
|
|
|
380 |
|
|
if (!(ts & M32_TS_RTI)) { |
381 |
|
|
printf("RCN=%2u RFM=0x%2.2x", |
382 |
|
|
(ts & M32_TS_RCN_MASK) >> M32_TS_RCN_SHIFT, |
383 |
|
|
(ts & M32_TS_RFM_MASK) >> M32_TS_RFM_SHIFT); |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
printf("\n"); |
387 |
|
|
} |
388 |
|
|
} |
389 |
|
|
|
390 |
|
|
printf("\n"); |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
/* Show info about a channels (debugging) */ |
394 |
|
|
static void m32_show_channel(struct m32_data *d,u_int chan_id) |
395 |
|
|
{ |
396 |
|
|
struct m32_channel *chan; |
397 |
|
|
|
398 |
|
|
chan = &d->channels[chan_id]; |
399 |
|
|
printf("M32 Channel %u:\n",chan_id); |
400 |
|
|
printf(" Status : 0x%8.8x\n",chan->status); |
401 |
|
|
printf(" FRDA : 0x%8.8x\n",chan->frda); |
402 |
|
|
printf(" FTDA : 0x%8.8x\n",chan->ftda); |
403 |
|
|
printf(" ITBS : 0x%8.8x\n",chan->itbs); |
404 |
|
|
} |
405 |
|
|
|
406 |
|
|
/* Fetch a channel specification */ |
407 |
|
|
static int m32_fetch_chan_spec(struct m32_data *d,u_int chan_id) |
408 |
|
|
{ |
409 |
|
|
struct m32_channel *chan; |
410 |
|
|
m_uint32_t offset; |
411 |
|
|
|
412 |
|
|
offset = M32_OFFSET_CHAN + (chan_id * 4 * sizeof(m_uint32_t)); |
413 |
|
|
chan = &d->channels[chan_id]; |
414 |
|
|
|
415 |
|
|
chan->status = m32_get_cfgw(d,offset); |
416 |
|
|
chan->frda = m32_get_cfgw(d,offset+4); |
417 |
|
|
chan->ftda = m32_get_cfgw(d,offset+8); |
418 |
|
|
chan->itbs = m32_get_cfgw(d,offset+12); |
419 |
|
|
|
420 |
|
|
chan->poll_mode = 0; |
421 |
|
|
chan->rx_current = chan->frda; |
422 |
|
|
chan->tx_current = chan->ftda; |
423 |
|
|
|
424 |
|
|
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); |
425 |
|
|
|
426 |
|
|
#if 1 |
427 |
|
|
if (chan_id == 2) { |
428 |
|
|
printf("M32: Fetched channel %u\n",chan_id); |
429 |
|
|
//m32_show_ts_assign(d); |
430 |
|
|
m32_show_channel(d,chan_id); |
431 |
|
|
} |
432 |
|
|
#endif |
433 |
|
|
return(0); |
434 |
|
|
} |
435 |
|
|
|
436 |
|
|
/* Fetch all channel specifications */ |
437 |
|
|
static void m32_fetch_all_chan_spec(struct m32_data *d) |
438 |
|
|
{ |
439 |
|
|
u_int i; |
440 |
|
|
|
441 |
|
|
for(i=0;i<M32_NR_CHANNELS;i++) |
442 |
|
|
m32_fetch_chan_spec(d,i); |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
/* Try to acquire the specified TX descriptor */ |
446 |
|
|
static int m32_tx_acquire(struct m32_data *d,m_uint32_t txd_addr, |
447 |
|
|
struct m32_tx_desc *txd) |
448 |
|
|
{ |
449 |
|
|
m_uint32_t params; |
450 |
|
|
|
451 |
|
|
if (!(params = physmem_copy_u32_from_vm(d->vm,txd_addr)) & M32_TXDESC_HOLD) |
452 |
|
|
return(FALSE); |
453 |
|
|
|
454 |
|
|
txd->params = params; |
455 |
|
|
txd->tdp = physmem_copy_u32_from_vm(d->vm,txd_addr+4); |
456 |
|
|
txd->ntdp = physmem_copy_u32_from_vm(d->vm,txd_addr+8); |
457 |
|
|
return(TRUE); |
458 |
|
|
} |
459 |
|
|
|
460 |
|
|
/* Try to acquire the next TX descriptor */ |
461 |
|
|
static int m32_tx_acquire_next(struct m32_data *d,m_uint32_t *txd_addr) |
462 |
|
|
{ |
463 |
|
|
m_uint32_t params; |
464 |
|
|
|
465 |
|
|
/* HOLD bit must be reset */ |
466 |
|
|
if ((params = physmem_copy_u32_from_vm(d->vm,*txd_addr)) & M32_TXDESC_HOLD) |
467 |
|
|
return(FALSE); |
468 |
|
|
|
469 |
|
|
*txd_addr = physmem_copy_u32_from_vm(d->vm,(*txd_addr)+8); |
470 |
|
|
return(TRUE); |
471 |
|
|
} |
472 |
|
|
|
473 |
|
|
/* Scan a channel TX ring */ |
474 |
|
|
static inline int m32_tx_scan(struct m32_data *d,u_int chan_id) |
475 |
|
|
{ |
476 |
|
|
struct m32_channel *chan = &d->channels[chan_id]; |
477 |
|
|
m_uint8_t pkt[M32_MAX_PKT_SIZE]; |
478 |
|
|
struct m32_tx_desc txd; |
479 |
|
|
m_uint32_t pkt_len; |
480 |
|
|
|
481 |
|
|
if (!chan->tx_current) |
482 |
|
|
return(FALSE); |
483 |
|
|
|
484 |
|
|
switch(chan->poll_mode) { |
485 |
|
|
case 0: |
486 |
|
|
m32_set_cfgw(d,M32_OFFSET_CTDA+(chan_id*4),chan->tx_current); |
487 |
|
|
|
488 |
|
|
/* Try to transmit data */ |
489 |
|
|
if (!m32_tx_acquire(d,chan->tx_current,&txd)) |
490 |
|
|
return(FALSE); |
491 |
|
|
|
492 |
|
|
printf("M32: TX scanner for channel %u (tx_current=0x%8.8x)\n", |
493 |
|
|
chan_id,chan->tx_current); |
494 |
|
|
|
495 |
|
|
printf("M32: params=0x%8.8x, next=0x%8.8x.\n",txd.params,txd.ntdp); |
496 |
|
|
|
497 |
|
|
/* The descriptor has been acquired */ |
498 |
|
|
pkt_len = (txd.params & M32_TXDESC_NO_MASK) >> M32_TXDESC_NO_SHIFT; |
499 |
|
|
physmem_copy_from_vm(d->vm,pkt,txd.tdp,pkt_len); |
500 |
|
|
|
501 |
|
|
printf("M32: data_ptr=0x%x, len=%u\n",txd.tdp,pkt_len); |
502 |
|
|
mem_dump(stdout,pkt,pkt_len); |
503 |
|
|
|
504 |
|
|
/* Poll the next descriptor (wait for HOLD bit to be reset */ |
505 |
|
|
chan->poll_mode = 1; |
506 |
|
|
|
507 |
|
|
if (txd.params & M32_TXDESC_FE) { |
508 |
|
|
m32_post_interrupt(d,M32_II_FI | chan_id); |
509 |
|
|
vm_set_irq(d->vm,2); |
510 |
|
|
} |
511 |
|
|
|
512 |
|
|
break; |
513 |
|
|
|
514 |
|
|
case 1: |
515 |
|
|
if (!m32_tx_acquire_next(d,&chan->tx_current)) |
516 |
|
|
return(FALSE); |
517 |
|
|
|
518 |
|
|
printf("M32: branching on next descriptor 0x%x\n",chan->tx_current); |
519 |
|
|
chan->poll_mode = 0; |
520 |
|
|
break; |
521 |
|
|
} |
522 |
|
|
|
523 |
|
|
return(TRUE); |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
/* Scan the all channel TX rings */ |
527 |
|
|
static void m32_tx_scan_all_channels(struct m32_data *d) |
528 |
|
|
{ |
529 |
|
|
u_int i; |
530 |
|
|
|
531 |
|
|
for(i=0;i<M32_NR_CHANNELS;i++) |
532 |
|
|
m32_tx_scan(d,i); |
533 |
|
|
} |
534 |
|
|
|
535 |
|
|
/* |
536 |
|
|
* Handle an action request. |
537 |
|
|
* |
538 |
|
|
* IN, ICO and RES bits are mutually exclusive. |
539 |
|
|
*/ |
540 |
|
|
static int m32_action_req(struct m32_data *d,m_uint32_t action) |
541 |
|
|
{ |
542 |
|
|
u_int chan_id; |
543 |
|
|
|
544 |
|
|
/* Define a new Interrupt Queue */ |
545 |
|
|
if (action & M32_AS_IA) { |
546 |
|
|
d->iq_base_addr = d->iq_cur_addr = m32_get_cfgw(d,4); |
547 |
|
|
d->iq_size = ((m32_get_cfgw(d,8) & 0xFF) + 1) * 16 * sizeof(m_uint32_t); |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
/* Initialization Procedure */ |
551 |
|
|
if (action & M32_AS_IN) { |
552 |
|
|
/* Fetch all timeslots assignments */ |
553 |
|
|
m32_fetch_all_ts(d); |
554 |
|
|
|
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 |
|
|
/* Initialize Channel Only */ |
565 |
|
|
if (action & M32_AS_ICO) { |
566 |
|
|
/* Fetch specification of the specified channel */ |
567 |
|
|
chan_id = (action & M32_AS_CHAN_MASK) >> M32_AS_CHAN_SHIFT; |
568 |
|
|
m32_fetch_chan_spec(d,chan_id); |
569 |
|
|
|
570 |
|
|
/* Generate acknowledge */ |
571 |
|
|
if (!(action & M32_AS_IM)) |
572 |
|
|
m32_post_interrupt(d,M32_II_ARACK); |
573 |
|
|
} |
574 |
|
|
|
575 |
|
|
/* Reset */ |
576 |
|
|
if (action & M32_AS_RES) { |
577 |
|
|
/* Fetch all timeslots assignments */ |
578 |
|
|
m32_fetch_all_ts(d); |
579 |
|
|
|
580 |
|
|
/* Fetch all channel specifications */ |
581 |
|
|
m32_fetch_all_chan_spec(d); |
582 |
|
|
|
583 |
|
|
/* Generate acknowledge */ |
584 |
|
|
if (!(action & M32_AS_IM)) |
585 |
|
|
m32_post_interrupt(d,M32_II_ARACK); |
586 |
|
|
} |
587 |
|
|
|
588 |
|
|
return(0); |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
/* Munich32 general access function */ |
592 |
|
|
static void *m32_gen_access(struct m32_data *d,cpu_mips_t *cpu, |
593 |
|
|
m_uint32_t offset,u_int op_size,u_int op_type, |
594 |
|
|
m_uint64_t *data) |
595 |
|
|
{ |
596 |
|
|
u_int p; |
597 |
|
|
|
598 |
|
|
switch(offset) { |
599 |
|
|
/* Action Specification */ |
600 |
|
|
case 0x0: |
601 |
|
|
if (op_type == MTS_WRITE) |
602 |
|
|
m32_action_req(d,*data); |
603 |
|
|
return NULL; |
604 |
|
|
|
605 |
|
|
/* Configuration memory */ |
606 |
|
|
default: |
607 |
|
|
switch(op_size) { |
608 |
|
|
case 4: |
609 |
|
|
if (op_type == MTS_READ) |
610 |
|
|
*data = m32_get_cfgw(d,offset); |
611 |
|
|
else |
612 |
|
|
m32_set_cfgw(d,offset,*data); |
613 |
|
|
break; |
614 |
|
|
|
615 |
|
|
case 1: |
616 |
|
|
if (op_type == MTS_READ) { |
617 |
|
|
*data = m32_get_cfgw(d,offset & ~0x03); |
618 |
|
|
*data >>= (24 - ((offset & 0x03) << 3)); |
619 |
|
|
*data &= 0xFF; |
620 |
|
|
} else { |
621 |
|
|
printf("UNSUPPORTED(1)!!!!\n"); |
622 |
|
|
} |
623 |
|
|
break; |
624 |
|
|
|
625 |
|
|
case 2: |
626 |
|
|
if (op_type == MTS_READ) { |
627 |
|
|
*data = m32_get_cfgw(d,offset & ~0x03); |
628 |
|
|
*data >>= (16 - ((offset & 0x03) << 3)); |
629 |
|
|
*data &= 0xFFFF; |
630 |
|
|
} else { |
631 |
|
|
printf("UNSUPPORTED(2)!!!!\n"); |
632 |
|
|
} |
633 |
|
|
break; |
634 |
|
|
|
635 |
|
|
case 8: |
636 |
|
|
if (op_type == MTS_READ) { |
637 |
|
|
*data = (m_uint64_t)m32_get_cfgw(d,offset) << 32; |
638 |
|
|
*data |= m32_get_cfgw(d,offset+4); |
639 |
|
|
} else { |
640 |
|
|
printf("UNSUPPORTED(8)!!!!\n"); |
641 |
|
|
} |
642 |
|
|
break; |
643 |
|
|
|
644 |
|
|
default: |
645 |
|
|
printf("UNSUPPORTED (size=%u)!!!\n",op_size); |
646 |
|
|
} |
647 |
|
|
} |
648 |
|
|
|
649 |
|
|
return NULL; |
650 |
|
|
} |
651 |
|
|
|
652 |
|
|
/* |
653 |
|
|
* pa_4b_access() |
654 |
|
|
*/ |
655 |
|
|
void *pa_4b_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, |
656 |
|
|
u_int op_size,u_int op_type,m_uint64_t *data) |
657 |
|
|
{ |
658 |
|
|
struct pa_4b_data *d = dev->priv_data; |
659 |
|
|
static m_uint32_t test1,test2,test3; |
660 |
|
|
|
661 |
|
|
if (op_type == MTS_READ) |
662 |
|
|
*data = 0xFFFFFFFF; |
663 |
|
|
|
664 |
|
|
#if DEBUG_ACCESS |
665 |
|
|
if (offset >= MUNICH32_MEM_SIZE) { |
666 |
|
|
if (op_type == MTS_READ) { |
667 |
|
|
cpu_log(cpu,d->name,"read access to offset = 0x%x, pc = 0x%llx " |
668 |
|
|
"(op_size=%u)\n",offset,cpu->pc,op_size); |
669 |
|
|
} else { |
670 |
|
|
cpu_log(cpu,d->name,"write access to vaddr = 0x%x, pc = 0x%llx, " |
671 |
|
|
"val = 0x%llx (op_size=%u)\n",offset,cpu->pc,*data,op_size); |
672 |
|
|
} |
673 |
|
|
} |
674 |
|
|
#endif |
675 |
|
|
|
676 |
|
|
/* Specific cases */ |
677 |
|
|
switch(offset) { |
678 |
|
|
case 0x40008: |
679 |
|
|
if (op_type == MTS_READ) |
680 |
|
|
*data = 0xFF; |
681 |
|
|
break; |
682 |
|
|
|
683 |
|
|
case 0x40030: |
684 |
|
|
if (op_type == MTS_READ) |
685 |
|
|
*data = 0xFF; |
686 |
|
|
break; |
687 |
|
|
|
688 |
|
|
case 0x40000: |
689 |
|
|
if (op_type == MTS_READ) |
690 |
|
|
*data = 0xFFFF; |
691 |
|
|
break; |
692 |
|
|
|
693 |
|
|
case 0x40020: |
694 |
|
|
if (op_type == MTS_READ) |
695 |
|
|
*data = 0xFFFFFFFF; //test2; |
696 |
|
|
else |
697 |
|
|
test2 = *data; |
698 |
|
|
break; |
699 |
|
|
|
700 |
|
|
case 0x40021: |
701 |
|
|
if (op_type == MTS_READ) |
702 |
|
|
*data = 0xFF; //test3; |
703 |
|
|
else |
704 |
|
|
test3 = *data; |
705 |
|
|
break; |
706 |
|
|
|
707 |
|
|
case 0x40023: |
708 |
|
|
if (op_type == MTS_READ) |
709 |
|
|
*data = 0xFF; |
710 |
|
|
break; |
711 |
|
|
|
712 |
|
|
case 0x40040: |
713 |
|
|
if (op_type == MTS_READ) |
714 |
|
|
*data = 0x04; |
715 |
|
|
break; |
716 |
|
|
|
717 |
|
|
/* Channels enabled ? */ |
718 |
|
|
case 0x40044: |
719 |
|
|
if (op_type == MTS_READ) |
720 |
|
|
*data = 0xFF; /* 0x02 */ |
721 |
|
|
break; |
722 |
|
|
|
723 |
|
|
/* SID */ |
724 |
|
|
case 0x40050: |
725 |
|
|
if (op_type == MTS_WRITE) { |
726 |
|
|
test1 = *data; |
727 |
|
|
} else { |
728 |
|
|
switch(test1) { |
729 |
|
|
case TP3420_SID_PUP: |
730 |
|
|
*data = TP3420_SR_AI; |
731 |
|
|
vm_set_irq(d->vm,C7200_PA_MGMT_IRQ); |
732 |
|
|
break; |
733 |
|
|
case TP3420_SID_ENST: |
734 |
|
|
*data = 0xB0; |
735 |
|
|
break; |
736 |
|
|
default: |
737 |
|
|
*data = 0x03; |
738 |
|
|
break; |
739 |
|
|
} |
740 |
|
|
} |
741 |
|
|
break; |
742 |
|
|
|
743 |
|
|
default: |
744 |
|
|
if (offset < MUNICH32_MEM_SIZE) |
745 |
|
|
return(m32_gen_access(&d->m32_data,cpu,offset - d->m32_offset, |
746 |
|
|
op_size,op_type,data)); |
747 |
|
|
} |
748 |
|
|
|
749 |
|
|
return NULL; |
750 |
|
|
} |
751 |
|
|
|
752 |
|
|
/* |
753 |
|
|
* pci_munich32_read() |
754 |
|
|
*/ |
755 |
|
|
static m_uint32_t pci_munich32_read(cpu_mips_t *cpu,struct pci_device *dev, |
756 |
|
|
int reg) |
757 |
|
|
{ |
758 |
|
|
struct pa_4b_data *d = dev->priv_data; |
759 |
|
|
|
760 |
|
|
#if DEBUG_ACCESS |
761 |
|
|
BRI_LOG(d,"read PCI register 0x%x\n",reg); |
762 |
|
|
#endif |
763 |
|
|
switch(reg) { |
764 |
|
|
case PCI_REG_BAR0: |
765 |
|
|
return(d->dev->phys_addr); |
766 |
|
|
default: |
767 |
|
|
return(0); |
768 |
|
|
} |
769 |
|
|
} |
770 |
|
|
|
771 |
|
|
/* |
772 |
|
|
* pci_munich32_write() |
773 |
|
|
*/ |
774 |
|
|
static void pci_munich32_write(cpu_mips_t *cpu,struct pci_device *dev, |
775 |
|
|
int reg,m_uint32_t value) |
776 |
|
|
{ |
777 |
|
|
struct pa_4b_data *d = dev->priv_data; |
778 |
|
|
|
779 |
|
|
#if DEBUG_ACCESS |
780 |
|
|
BRI_LOG(d,"write 0x%x to PCI register 0x%x\n",value,reg); |
781 |
|
|
#endif |
782 |
|
|
|
783 |
|
|
switch(reg) { |
784 |
|
|
case PCI_REG_BAR0: |
785 |
|
|
vm_map_device(cpu->vm,d->dev,(m_uint64_t)value); |
786 |
|
|
BRI_LOG(d,"registers are mapped at 0x%x\n",value); |
787 |
|
|
break; |
788 |
|
|
} |
789 |
|
|
} |
790 |
|
|
|
791 |
|
|
/* |
792 |
|
|
* dev_c7200_bri_init() |
793 |
|
|
* |
794 |
|
|
* Add a PA-4B/PA-8B port adapter into specified slot. |
795 |
|
|
*/ |
796 |
|
|
int dev_c7200_pa_bri_init(c7200_t *router,char *name,u_int pa_bay) |
797 |
|
|
{ |
798 |
|
|
struct pci_device *pci_dev; |
799 |
|
|
struct pa_4b_data *d; |
800 |
|
|
struct vdevice *dev; |
801 |
|
|
|
802 |
|
|
/* Allocate the private data structure for PA-4B chip */ |
803 |
|
|
if (!(d = malloc(sizeof(*d)))) { |
804 |
|
|
fprintf(stderr,"%s (PA-4B): out of memory\n",name); |
805 |
|
|
return(-1); |
806 |
|
|
} |
807 |
|
|
|
808 |
|
|
memset(d,0,sizeof(*d)); |
809 |
|
|
d->m32_offset = 0x08; |
810 |
|
|
d->m32_data.vm = router->vm; |
811 |
|
|
|
812 |
|
|
/* Set the EEPROM */ |
813 |
|
|
c7200_pa_set_eeprom(router,pa_bay,&eeprom_pa_4b); |
814 |
|
|
|
815 |
|
|
/* Add as PCI device PA-4B */ |
816 |
|
|
pci_dev = pci_dev_add(router->pa_bay[pa_bay].pci_map,name, |
817 |
|
|
BRI_PCI_VENDOR_ID,BRI_PCI_PRODUCT_ID, |
818 |
|
|
0,0,C7200_NETIO_IRQ,d, |
819 |
|
|
NULL,pci_munich32_read,pci_munich32_write); |
820 |
|
|
|
821 |
|
|
if (!pci_dev) { |
822 |
|
|
fprintf(stderr,"%s (PA-4B): unable to create PCI device.\n",name); |
823 |
|
|
return(-1); |
824 |
|
|
} |
825 |
|
|
|
826 |
|
|
/* Create the PA-4B structure */ |
827 |
|
|
d->name = name; |
828 |
|
|
d->pci_dev = pci_dev; |
829 |
|
|
d->vm = router->vm; |
830 |
|
|
|
831 |
|
|
/* Create the device itself */ |
832 |
|
|
if (!(dev = dev_create(name))) { |
833 |
|
|
fprintf(stderr,"%s (PA-4B): unable to create device.\n",name); |
834 |
|
|
return(-1); |
835 |
|
|
} |
836 |
|
|
|
837 |
|
|
dev->phys_len = 0x800000; |
838 |
|
|
dev->handler = pa_4b_access; |
839 |
|
|
|
840 |
|
|
/* Store device info */ |
841 |
|
|
dev->priv_data = d; |
842 |
|
|
d->dev = dev; |
843 |
|
|
|
844 |
|
|
/* Map this device to the VM */ |
845 |
|
|
vm_bind_device(router->vm,dev); |
846 |
|
|
|
847 |
|
|
/* Store device info into the router structure */ |
848 |
|
|
return(c7200_pa_set_drvinfo(router,pa_bay,d)); |
849 |
|
|
} |
850 |
|
|
|
851 |
|
|
/* Remove a PA-4B from the specified slot */ |
852 |
|
|
int dev_c7200_pa_bri_shutdown(c7200_t *router,u_int pa_bay) |
853 |
|
|
{ |
854 |
|
|
struct c7200_pa_bay *bay; |
855 |
|
|
struct pa_4b_data *d; |
856 |
|
|
|
857 |
|
|
if (!(bay = c7200_pa_get_info(router,pa_bay))) |
858 |
|
|
return(-1); |
859 |
|
|
|
860 |
|
|
d = bay->drv_info; |
861 |
|
|
|
862 |
|
|
/* Remove the PA EEPROM */ |
863 |
|
|
c7200_pa_unset_eeprom(router,pa_bay); |
864 |
|
|
|
865 |
|
|
/* Remove the PCI device */ |
866 |
|
|
pci_dev_remove(d->pci_dev); |
867 |
|
|
|
868 |
|
|
/* Remove the device from the CPU address space */ |
869 |
|
|
vm_unbind_device(router->vm,d->dev); |
870 |
|
|
cpu_group_rebuild_mts(router->vm->cpu_group); |
871 |
|
|
|
872 |
|
|
/* Free the device structure itself */ |
873 |
|
|
free(d->dev); |
874 |
|
|
free(d); |
875 |
|
|
return(0); |
876 |
|
|
} |
877 |
|
|
|
878 |
|
|
/* Bind a Network IO descriptor to a specific port */ |
879 |
|
|
int dev_c7200_pa_bri_set_nio(c7200_t *router,u_int pa_bay,u_int port_id, |
880 |
|
|
netio_desc_t *nio) |
881 |
|
|
{ |
882 |
|
|
struct pa_4b_data *d; |
883 |
|
|
|
884 |
|
|
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
885 |
|
|
return(-1); |
886 |
|
|
|
887 |
|
|
if (d->nio != NULL) |
888 |
|
|
return(-1); |
889 |
|
|
|
890 |
|
|
d->nio = nio; |
891 |
|
|
|
892 |
|
|
/* TEST */ |
893 |
|
|
d->m32_data.tx_tid = ptask_add((ptask_callback)m32_tx_scan_all_channels,&d->m32_data,NULL); |
894 |
|
|
|
895 |
|
|
//netio_rxl_add(nio,(netio_rx_handler_t)dev_pa_4b_handle_rxring,d,NULL); |
896 |
|
|
return(0); |
897 |
|
|
} |
898 |
|
|
|
899 |
|
|
/* Bind a Network IO descriptor to a specific port */ |
900 |
|
|
int dev_c7200_pa_bri_unset_nio(c7200_t *router,u_int pa_bay,u_int port_id) |
901 |
|
|
{ |
902 |
|
|
struct pa_4b_data *d; |
903 |
|
|
|
904 |
|
|
if ((port_id > 0) || !(d = c7200_pa_get_drvinfo(router,pa_bay))) |
905 |
|
|
return(-1); |
906 |
|
|
|
907 |
|
|
if (d->nio) { |
908 |
|
|
/* TEST */ |
909 |
|
|
ptask_remove(d->m32_data.tx_tid); |
910 |
|
|
|
911 |
|
|
//netio_rxl_remove(d->nio); |
912 |
|
|
d->nio = NULL; |
913 |
|
|
} |
914 |
|
|
return(0); |
915 |
|
|
} |
916 |
|
|
|
917 |
|
|
/* PA-4B driver */ |
918 |
|
|
struct c7200_pa_driver dev_c7200_pa_4b_driver = { |
919 |
|
|
"PA-4B", 0, |
920 |
|
|
dev_c7200_pa_bri_init, |
921 |
|
|
dev_c7200_pa_bri_shutdown, |
922 |
|
|
dev_c7200_pa_bri_set_nio, |
923 |
|
|
dev_c7200_pa_bri_unset_nio, |
924 |
|
|
}; |