126 |
struct am79c971_data { |
struct am79c971_data { |
127 |
char *name; |
char *name; |
128 |
|
|
129 |
|
/* Lock */ |
130 |
|
pthread_mutex_t lock; |
131 |
|
|
132 |
/* Interface type (10baseT or 100baseTX) */ |
/* Interface type (10baseT or 100baseTX) */ |
133 |
int type; |
int type; |
134 |
|
|
135 |
|
/* RX/TX clearing count */ |
136 |
|
int rx_tx_clear_count; |
137 |
|
|
138 |
/* Current RAP (Register Address Pointer) value */ |
/* Current RAP (Register Address Pointer) value */ |
139 |
m_uint8_t rap; |
m_uint8_t rap; |
140 |
|
|
178 |
/* Log an am79c971 message */ |
/* Log an am79c971 message */ |
179 |
#define AM79C971_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
#define AM79C971_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg) |
180 |
|
|
181 |
|
/* Lock/Unlock primitives */ |
182 |
|
#define AM79C971_LOCK(d) pthread_mutex_lock(&(d)->lock) |
183 |
|
#define AM79C971_UNLOCK(d) pthread_mutex_unlock(&(d)->lock) |
184 |
|
|
185 |
static m_uint16_t mii_reg_values[32] = { |
static m_uint16_t mii_reg_values[32] = { |
186 |
0x1000, 0x782D, 0x2000, 0x5C01, 0x01E1, 0x0000, 0x0000, 0x0000, |
0x1000, 0x782D, 0x0013, 0x78E2, 0x01E1, 0xC9E1, 0x000F, 0x2001, |
187 |
|
0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, |
188 |
|
0x0104, 0x4780, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, |
189 |
|
0x0000, 0x0000, 0x00C8, 0x0000, 0xFFFF, 0x0000, 0x0000, 0x0000, |
190 |
|
|
191 |
|
#if 0 |
192 |
|
0x1000, 0x782D, 0x0013, 0x78e2, 0x01E1, 0xC9E1, 0x0000, 0x0000, |
193 |
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, |
194 |
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x8060, |
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x8060, |
195 |
0x8020, 0x0820, 0x0000, 0x3800, 0xA3B9, 0x0000, 0x0000, 0x0000, |
0x8023, 0x0820, 0x0000, 0x3800, 0xA3B9, 0x0000, 0x0000, 0x0000, |
196 |
|
#endif |
197 |
}; |
}; |
198 |
|
|
199 |
/* Read a MII register */ |
/* Read a MII register */ |
219 |
{ |
{ |
220 |
n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt; |
n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt; |
221 |
|
|
222 |
/* Accept systematically frames if we are running is promiscuous mode */ |
/* Accept systematically frames if we are running in promiscuous mode */ |
223 |
if (d->csr[15] & AM79C971_CSR15_PROM) |
if (d->csr[15] & AM79C971_CSR15_PROM) |
224 |
return(TRUE); |
return(TRUE); |
225 |
|
|
235 |
} |
} |
236 |
|
|
237 |
/* Update the Interrupt Flag bit of csr0 */ |
/* Update the Interrupt Flag bit of csr0 */ |
238 |
static void am79c971_update_intr_flag(struct am79c971_data *d) |
static void am79c971_update_irq_status(struct am79c971_data *d) |
239 |
{ |
{ |
240 |
m_uint32_t mask; |
m_uint32_t mask; |
241 |
|
|
242 |
mask = d->csr[3] & AM79C971_CSR3_IM_MASK; |
/* Bits set in CR3 disable the specified interrupts */ |
243 |
|
mask = AM79C971_CSR3_IM_MASK & ~(d->csr[3] & AM79C971_CSR3_IM_MASK); |
244 |
|
|
245 |
if (d->csr[0] & mask) |
if (d->csr[0] & mask) |
246 |
d->csr[0] |= AM79C971_CSR0_INTR; |
d->csr[0] |= AM79C971_CSR0_INTR; |
247 |
} |
else |
248 |
|
d->csr[0] &= ~AM79C971_CSR0_INTR; |
249 |
|
|
250 |
/* Trigger an interrupt */ |
if ((d->csr[0] & (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) == |
251 |
static int am79c971_trigger_irq(struct am79c971_data *d) |
(AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) |
252 |
{ |
{ |
|
if (d->csr[0] & (AM79C971_CSR0_INTR|AM79C971_CSR0_IENA)) { |
|
253 |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
254 |
return(TRUE); |
} else { |
255 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
256 |
} |
} |
|
|
|
|
return(FALSE); |
|
257 |
} |
} |
258 |
|
|
259 |
/* Update RX/TX ON bits of csr0 */ |
/* Update RX/TX ON bits of csr0 */ |
341 |
/* Update RX/TX ON bits of csr0 since csr15 has been modified */ |
/* Update RX/TX ON bits of csr0 since csr15 has been modified */ |
342 |
am79c971_update_rx_tx_on_bits(d); |
am79c971_update_rx_tx_on_bits(d); |
343 |
AM79C971_LOG(d,"CSR0 = 0x%4.4x\n",d->csr[0]); |
AM79C971_LOG(d,"CSR0 = 0x%4.4x\n",d->csr[0]); |
|
|
|
|
am79c971_update_intr_flag(d); |
|
|
|
|
|
if (am79c971_trigger_irq(d)) |
|
|
AM79C971_LOG(d,"triggering IDON interrupt\n"); |
|
|
|
|
344 |
return(0); |
return(0); |
345 |
} |
} |
346 |
|
|
372 |
//AM79C971_LOG(d,"stopping interface!\n"); |
//AM79C971_LOG(d,"stopping interface!\n"); |
373 |
d->csr[0] = AM79C971_CSR0_STOP; |
d->csr[0] = AM79C971_CSR0_STOP; |
374 |
d->tx_pos = d->rx_pos = 0; |
d->tx_pos = d->rx_pos = 0; |
375 |
|
am79c971_update_irq_status(d); |
376 |
break; |
break; |
377 |
} |
} |
378 |
|
|
379 |
/* These bits are cleared when set to 1 */ |
/* These bits are cleared when set to 1 */ |
380 |
mask = AM79C971_CSR0_BABL | AM79C971_CSR0_CERR; |
mask = AM79C971_CSR0_BABL | AM79C971_CSR0_CERR; |
381 |
mask |= AM79C971_CSR0_MISS | AM79C971_CSR0_MERR; |
mask |= AM79C971_CSR0_MISS | AM79C971_CSR0_MERR; |
|
mask |= AM79C971_CSR0_RINT | AM79C971_CSR0_TINT; |
|
382 |
mask |= AM79C971_CSR0_IDON; |
mask |= AM79C971_CSR0_IDON; |
383 |
|
|
384 |
|
if (++d->rx_tx_clear_count == 3) { |
385 |
|
mask |= AM79C971_CSR0_RINT | AM79C971_CSR0_TINT; |
386 |
|
d->rx_tx_clear_count = 0; |
387 |
|
} |
388 |
|
|
389 |
d->csr[0] &= ~(*data & mask); |
d->csr[0] &= ~(*data & mask); |
390 |
|
|
391 |
/* Save the Interrupt Enable bit */ |
/* Save the Interrupt Enable bit */ |
405 |
d->csr[0] &= ~AM79C971_CSR0_STOP; |
d->csr[0] &= ~AM79C971_CSR0_STOP; |
406 |
am79c971_update_rx_tx_on_bits(d); |
am79c971_update_rx_tx_on_bits(d); |
407 |
} |
} |
408 |
|
|
409 |
|
/* Update IRQ status */ |
410 |
|
am79c971_update_irq_status(d); |
411 |
} |
} |
412 |
break; |
break; |
413 |
|
|
419 |
} else { |
} else { |
420 |
*data = (d->tx_l2len << 12) | (d->rx_l2len << 8); |
*data = (d->tx_l2len << 12) | (d->rx_l2len << 8); |
421 |
} |
} |
422 |
break; |
break; |
423 |
|
|
424 |
case 15: /* CSR15: Mode */ |
case 15: /* CSR15: Mode */ |
425 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
531 |
} |
} |
532 |
#endif |
#endif |
533 |
|
|
534 |
|
AM79C971_LOCK(d); |
535 |
|
|
536 |
switch(offset) { |
switch(offset) { |
537 |
case 0x14: /* RAP (Register Address Pointer) */ |
case 0x14: /* RAP (Register Address Pointer) */ |
538 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
551 |
break; |
break; |
552 |
} |
} |
553 |
|
|
554 |
|
AM79C971_UNLOCK(d); |
555 |
return NULL; |
return NULL; |
556 |
} |
} |
557 |
|
|
640 |
u_char *pkt_ptr = pkt; |
u_char *pkt_ptr = pkt; |
641 |
m_uint8_t sw_style; |
m_uint8_t sw_style; |
642 |
int i; |
int i; |
643 |
|
|
644 |
/* Truncate the packet if it is too big */ |
/* Truncate the packet if it is too big */ |
645 |
pkt_len = m_min(pkt_len,AM79C971_MAX_PKT_SIZE); |
pkt_len = m_min(pkt_len,AM79C971_MAX_PKT_SIZE); |
646 |
|
|
722 |
physmem_copy_u32_to_vm(d->vm,rx_start+4,rxd0.rmd[1]); |
physmem_copy_u32_to_vm(d->vm,rx_start+4,rxd0.rmd[1]); |
723 |
|
|
724 |
d->csr[0] |= AM79C971_CSR0_RINT; |
d->csr[0] |= AM79C971_CSR0_RINT; |
725 |
am79c971_update_intr_flag(d); |
am79c971_update_irq_status(d); |
|
am79c971_trigger_irq(d); |
|
726 |
return(TRUE); |
return(TRUE); |
727 |
} |
} |
728 |
|
|
745 |
mem_dump(log_file,pkt,pkt_len); |
mem_dump(log_file,pkt,pkt_len); |
746 |
#endif |
#endif |
747 |
|
|
748 |
|
AM79C971_LOCK(d); |
749 |
|
|
750 |
/* |
/* |
751 |
* Receive only multicast/broadcast trafic + unicast traffic |
* Receive only multicast/broadcast trafic + unicast traffic |
752 |
* for this virtual machine. |
* for this virtual machine. |
755 |
if (am79c971_handle_mac_addr(d,pkt)) |
if (am79c971_handle_mac_addr(d,pkt)) |
756 |
am79c971_receive_pkt(d,pkt,pkt_len); |
am79c971_receive_pkt(d,pkt,pkt_len); |
757 |
|
|
758 |
|
AM79C971_UNLOCK(d); |
759 |
return(TRUE); |
return(TRUE); |
760 |
} |
} |
761 |
|
|
849 |
/* Copy packet data */ |
/* Copy packet data */ |
850 |
clen = ~((ptxd->tmd[1] & AM79C971_TMD1_LEN) - 1); |
clen = ~((ptxd->tmd[1] & AM79C971_TMD1_LEN) - 1); |
851 |
clen &= AM79C971_TMD1_LEN; |
clen &= AM79C971_TMD1_LEN; |
852 |
|
|
853 |
physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tmd[0],clen); |
physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->tmd[0],clen); |
854 |
|
|
855 |
pkt_ptr += clen; |
pkt_ptr += clen; |
896 |
|
|
897 |
/* Generate TX interrupt */ |
/* Generate TX interrupt */ |
898 |
d->csr[0] |= AM79C971_CSR0_TINT; |
d->csr[0] |= AM79C971_CSR0_TINT; |
899 |
am79c971_update_intr_flag(d); |
am79c971_update_irq_status(d); |
|
am79c971_trigger_irq(d); |
|
900 |
return(TRUE); |
return(TRUE); |
901 |
} |
} |
902 |
|
|
905 |
{ |
{ |
906 |
int i; |
int i; |
907 |
|
|
908 |
|
AM79C971_LOCK(d); |
909 |
|
|
910 |
for(i=0;i<AM79C971_TXRING_PASS_COUNT;i++) |
for(i=0;i<AM79C971_TXRING_PASS_COUNT;i++) |
911 |
if (!am79c971_handle_txring_single(d)) |
if (!am79c971_handle_txring_single(d)) |
912 |
break; |
break; |
913 |
|
|
914 |
|
AM79C971_UNLOCK(d); |
915 |
return(TRUE); |
return(TRUE); |
916 |
} |
} |
917 |
|
|
984 |
|
|
985 |
memset(d,0,sizeof(*d)); |
memset(d,0,sizeof(*d)); |
986 |
memcpy(d->mii_regs[0],mii_reg_values,sizeof(mii_reg_values)); |
memcpy(d->mii_regs[0],mii_reg_values,sizeof(mii_reg_values)); |
987 |
|
pthread_mutex_init(&d->lock,NULL); |
988 |
|
|
989 |
/* Add as PCI device */ |
/* Add as PCI device */ |
990 |
pci_dev = pci_dev_add(pci_bus,name, |
pci_dev = pci_dev_add(pci_bus,name, |