📄 dev_gt.c
字号:
} /* Abort RX DMA */ if (*data & GT_SDCMR_AR) port->sdcmr &= ~GT_SDCMR_ERD; /* Start TX High */ if (*data & GT_SDCMR_TXDH) { port->sdcmr |= GT_SDCMR_TXDH; port->sdcmr &= ~GT_SDCMR_STDH; } /* Start TX Low */ if (*data & GT_SDCMR_TXDL) { port->sdcmr |= GT_SDCMR_TXDL; port->sdcmr &= ~GT_SDCMR_STDL; } /* Stop TX High */ if (*data & GT_SDCMR_STDH) { port->sdcmr &= ~GT_SDCMR_TXDH; port->sdcmr |= GT_SDCMR_STDH; } /* Stop TX Low */ if (*data & GT_SDCMR_STDL) { port->sdcmr &= ~GT_SDCMR_TXDL; port->sdcmr |= GT_SDCMR_STDL; } } else { *data = port->sdcmr; } break; case 0x85800: case 0x89800: if (op_type == MTS_READ) { *data = port->rx_bytes; port->rx_bytes = 0; } break; case 0x85804: case 0x89804: if (op_type == MTS_READ) { *data = port->tx_bytes; port->tx_bytes = 0; } break; case 0x85808: case 0x89808: if (op_type == MTS_READ) { *data = port->rx_frames; port->rx_frames = 0; } break; case 0x8580C: case 0x8980C: if (op_type == MTS_READ) { *data = port->tx_frames; port->tx_frames = 0; } break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"GT96100/ETH", "read access to unknown register 0x%x, pc=0x%llx\n", offset,cpu->pc); } else { cpu_log(cpu,"GT96100/ETH", "write access to unknown register 0x%x, value=0x%llx, " "pc=0x%llx\n",offset,*data,cpu->pc); }#endif } if (op_type == MTS_READ) *data = swap32(*data); return(TRUE);}/* * dev_gt96100_access() */void *dev_gt96100_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset, u_int op_size,u_int op_type,m_uint64_t *data){ struct gt_data *gt_data = dev->priv_data; if (op_type == MTS_READ) *data = 0; if (gt_dma_access(cpu,dev,offset,op_size,op_type,data) != 0) return NULL; if (gt_eth_access(cpu,dev,offset,op_size,op_type,data) != 0) return NULL; switch(offset) { /* Watchdog configuration register */ case 0x101a80: break; /* Watchdog value register */ case 0x101a84: break; case 0x008: /* ras10_low */ if (op_type == MTS_READ) *data = swap32(0x000); break; case 0x010: /* ras10_high */ if (op_type == MTS_READ) *data = swap32(0x7F); break; case 0x018: /* ras32_low */ if (op_type == MTS_READ) *data = swap32(0x100); break; case 0x020: /* ras32_high */ if (op_type == MTS_READ) *data = swap32(0x7F); break; case 0x400: /* ras0_low */ if (op_type == MTS_READ) *data = swap32(0x00); break; case 0x404: /* ras0_high */ if (op_type == MTS_READ) *data = swap32(0xFF); break; case 0x408: /* ras1_low */ if (op_type == MTS_READ) *data = swap32(0x7F); break; case 0x40c: /* ras1_high */ if (op_type == MTS_READ) *data = swap32(0x00); break; case 0x410: /* ras2_low */ if (op_type == MTS_READ) *data = swap32(0x00); break; case 0x414: /* ras2_high */ if (op_type == MTS_READ) *data = swap32(0xFF); break; case 0x418: /* ras3_low */ if (op_type == MTS_READ) *data = swap32(0x7F); break; case 0x41c: /* ras3_high */ if (op_type == MTS_READ) *data = swap32(0x00); break; case 0xc08: /* pci0_cs10 */ if (op_type == MTS_READ) *data = swap32(0xFFF); break; case 0xc0c: /* pci0_cs32 */ if (op_type == MTS_READ) *data = swap32(0xFFF); break; case 0xc00: /* pci_cmd */ if (op_type == MTS_READ) *data = swap32(0x00008001); break; /* ===== Interrupt Main Cause Register ===== */ case 0xc18: if (op_type == MTS_READ) { *data = gt_data->int_cause_reg; /* TODO: signal Eth0/Eth1 */ //*data |= (1 << 30) | (1 << 31) | 1; *data = swap32(*data); } else { gt_data->int_cause_reg &= swap32(*data); gt_update_irq_status(gt_data); } break; /* ===== Interrupt Mask Register ===== */ case 0xc1c: if (op_type == MTS_READ) { *data = swap32(gt_data->int_mask_reg); } else { gt_data->int_mask_reg = swap32(*data); gt_update_irq_status(gt_data); } break; /* ===== Interrupt High Cause Register ===== */ case 0xc98: if (op_type == MTS_READ) { *data = 0; /* interrupt on ethernet port 0 ? */ if (gt_data->eth_ports[0].icr & GT_ICR_INT_SUM) *data |= GT_IHCR_ETH0_SUM; /* interrupt on ethernet port 1 ? */ if (gt_data->eth_ports[1].icr & GT_ICR_INT_SUM) *data |= GT_IHCR_ETH1_SUM; *data = swap32(*data); } break; /* Serial Cause Register */ case 0x103a00: if (op_type == MTS_READ) { *data = 0; /* interrupt on ethernet port 0 ? */ if (gt_data->eth_ports[0].icr & GT_ICR_INT_SUM) *data |= GT_SCR_ETH0_SUM; /* interrupt on ethernet port 1 ? */ if (gt_data->eth_ports[1].icr & GT_ICR_INT_SUM) *data |= GT_SCR_ETH1_SUM; *data = swap32(*data); } break; /* ===== PCI Bus 1 ===== */ case 0xcf0: pci_dev_addr_handler(cpu,gt_data->bus[1],op_type,TRUE,data); break; case 0xcf4: pci_dev_data_handler(cpu,gt_data->bus[1],op_type,TRUE,data); break; /* ===== PCI Bus 0 ===== */ case PCI_BUS_ADDR: /* pci configuration address (0xcf8) */ pci_dev_addr_handler(cpu,gt_data->bus[0],op_type,TRUE,data); break; case PCI_BUS_DATA: /* pci data address (0xcfc) */ pci_dev_data_handler(cpu,gt_data->bus[0],op_type,TRUE,data); break;#if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"GT96100","read from addr 0x%x, pc=0x%llx\n", offset,cpu->pc); } else { cpu_log(cpu,"GT96100","write to addr 0x%x, value=0x%llx, " "pc=0x%llx\n",offset,*data,cpu->pc); }#endif } return NULL;}/* Read an Ethernet descriptor */static void gt_eth_desc_read(struct gt_data *d,m_uint32_t addr, struct eth_desc *desc){ physmem_copy_from_vm(d->vm,desc,addr,sizeof(struct eth_desc)); /* byte-swapping */ desc->cmd_stat = vmtoh32(desc->cmd_stat); desc->buf_size = vmtoh32(desc->buf_size); desc->next_ptr = vmtoh32(desc->next_ptr); desc->buf_ptr = vmtoh32(desc->buf_ptr);}/* Write an Ethernet descriptor */static void gt_eth_desc_write(struct gt_data *d,m_uint32_t addr, struct eth_desc *desc){ struct eth_desc tmp; /* byte-swapping */ tmp.cmd_stat = vmtoh32(desc->cmd_stat); tmp.buf_size = vmtoh32(desc->buf_size); tmp.next_ptr = vmtoh32(desc->next_ptr); tmp.buf_ptr = vmtoh32(desc->buf_ptr); physmem_copy_to_vm(d->vm,&tmp,addr,sizeof(struct eth_desc));}/* Handle a TX queue (single packet) */static int gt_eth_handle_txqueue(struct gt_data *d,struct eth_port *port, int queue){ u_char pkt[GT_MAX_PKT_SIZE],*pkt_ptr; struct eth_desc txd0,ctxd,*ptxd; m_uint32_t tx_start,tx_current; m_uint32_t len,tot_len; int abort = FALSE; /* Check if this TX queue is active */ if ((queue == 0) && (port->sdcmr & GT_SDCMR_STDL)) return(FALSE); if ((queue == 1) && (port->sdcmr & GT_SDCMR_STDH)) return(FALSE); /* Copy the current txring descriptor */ tx_start = tx_current = port->tx_current[queue]; if (!tx_start) goto done; ptxd = &txd0; gt_eth_desc_read(d,tx_start,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.cmd_stat & GT_TXDESC_OWN)) goto done; /* Empty packet for now */ pkt_ptr = pkt; tot_len = 0; for(;;) {#if DEBUG_ETH_TX GT_LOG(d,"gt_eth_handle_txqueue: loop: " "cmd_stat=0x%x, buf_size=0x%x, next_ptr=0x%x, buf_ptr=0x%x\n", ptxd->cmd_stat,ptxd->buf_size,ptxd->next_ptr,ptxd->buf_ptr);#endif if (!(ptxd->cmd_stat & GT_TXDESC_OWN)) { GT_LOG(d,"gt_eth_handle_txqueue: descriptor not owned!\n"); abort = TRUE; break; } /* Copy packet data to the buffer */ len = (ptxd->buf_size & GT_TXDESC_BC_MASK) >> GT_TXDESC_BC_SHIFT; physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->buf_ptr,len); pkt_ptr += len; tot_len += len; /* Clear the OWN bit if this is not the first descriptor */ if (!(ptxd->cmd_stat & GT_TXDESC_F)) { ptxd->cmd_stat &= ~GT_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_current,ptxd->cmd_stat); } tx_current = ptxd->next_ptr; /* Last descriptor or no more desc available ? */ if (ptxd->cmd_stat & GT_TXDESC_L) break; if (!tx_current) { abort = TRUE; break; } /* Fetch the next descriptor */ gt_eth_desc_read(d,tx_current,&ctxd); ptxd = &ctxd; } if ((tot_len != 0) && !abort) {#if DEBUG_ETH_TX GT_LOG(d,"Ethernet: sending packet of %u bytes\n",tot_len); mem_dump(log_file,pkt,tot_len);#endif /* send it on wire */ netio_send(port->nio,pkt,tot_len); /* Update MIB counters */ port->tx_bytes += tot_len; port->tx_frames++; } /* Clear the OWN flag of the first descriptor */ txd0.cmd_stat &= ~GT_TXDESC_OWN; physmem_copy_u32_to_vm(d->vm,tx_start+4,txd0.cmd_stat); port->tx_current[queue] = tx_current; /* Notify host about transmitted packet */ if (queue == 0) port->icr |= GT_ICR_TXBUFL; else port->icr |= GT_ICR_TXBUFH; done: if (abort) { /* TX underrun */ port->icr |= GT_ICR_TXUDR; if (queue == 0) port->icr |= GT_ICR_TXERRL; else port->icr |= GT_ICR_TXERRH; } else { /* End of queue has been reached */ if (!tx_current) { if (queue == 0) port->icr |= GT_ICR_TXENDL; else port->icr |= GT_ICR_TXENDH; } } /* Update the interrupt status */ gt_eth_update_int_status(d,port); return(TRUE);}/* Handle TX ring of the specified port */static void gt_eth_handle_port_txqueues(struct gt_data *d,u_int port){ gt_eth_handle_txqueue(d,&d->eth_ports[port],0); /* TX Low */ gt_eth_handle_txqueue(d,&d->eth_ports[port],1); /* TX High */}/* Handle all TX rings of all Ethernet ports */static int gt_eth_handle_txqueues(struct gt_data *d){ int i; for(i=0;i<GT_ETH_PORTS;i++) gt_eth_handle_port_txqueues(d,i); return(TRUE);}/* Inverse a nibble */static const int inv_nibble[16] = { 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF };/* Inverse a 9-bit value */static inline u_int gt_hash_inv_9bit(u_int val){ u_int res; res = inv_nibble[val & 0x0F] << 5; res |= inv_nibble[(val & 0xF0) >> 4] << 1; res |= (val & 0x100) >> 8; return(res);}/* * Compute hash value for Ethernet address filtering. * Two modes are available (p.271 of the GT96100 doc). */static u_int gt_eth_hash_value(n_eth_addr_t *addr,int mode){ m_uint64_t tmp; u_int res; int i; /* Swap the nibbles */ for(i=0,tmp=0;i<N_ETH_ALEN;i++) { tmp <<= 8; tmp |= (inv_nibble[addr->eth_addr_byte[i] & 0x0F]) << 4; tmp |= inv_nibble[(addr->eth_addr_byte[i] & 0xF0) >> 4]; } if (mode == 0) { /* Fill bits 0:8 */ res = (tmp & 0x00000003) | ((tmp & 0x00007f00) >> 6); res ^= (tmp & 0x00ff8000) >> 15; res ^= (tmp & 0x1ff000000ULL) >> 24; /* Fill bits 9:14 */ res |= (tmp & 0xfc) << 7; } else { /* Fill bits 0:8 */ res = gt_hash_inv_9bit((tmp & 0x00007fc0) >> 6); res ^= gt_hash_inv_9bit((tmp & 0x00ff8000) >> 15); res ^= gt_hash_inv_9bit((tmp & 0x1ff000000ULL) >> 24);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -