📄 dev_mpc860.c
字号:
scc_chan_info_t *scc_info; m_uint16_t bd_offset; ssize_t clen,tot_len; u_char *pkt_ptr; u_int mrblr; int irq = FALSE; scc_info = &scc_chan_info[scc_chan]; chan = &d->scc_chan[scc_chan]; /* Get the RBPTR (offset 0x10) register */ bd_offset = dpram_r16(d,scc_info->dpram_base+0x10); /* Get the maximum buffer size */ mrblr = dpram_r16(d,scc_info->dpram_base+0x06); /* Try to acquire the first descriptor */ prxd = &rxd0; mpc860_scc_fetch_bd(d,bd_offset,prxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(rxd0.ctrl & MPC860_SCC_RXBD_CTRL_E)) return(FALSE); pkt_ptr = pkt; tot_len = pkt_len; while(tot_len > 0) { /* Write data into the RX buffer */ clen = m_min(mrblr,tot_len); physmem_copy_to_vm(d->vm,pkt_ptr,prxd->bp,clen); pkt_ptr += clen; tot_len -= clen; /* Signal IRQ ? */ if (prxd->ctrl & MPC860_SCC_RXBD_CTRL_I) irq = TRUE; /* Set the Last flag if we have finished */ if (!tot_len) { /* Set the full length */ switch(chan->gsmr_lo & MPC860_GSMRL_MODE_MASK) { case MPC860_SCC_MODE_ETH: pkt_len += 4; break; case MPC860_SCC_MODE_HDLC: pkt_len += 2; break; } dpram_w16(d,prxd->offset+0x02,pkt_len); prxd->ctrl |= MPC860_SCC_RXBD_CTRL_L; } else { /* Update the length field */ dpram_w16(d,prxd->offset+0x02,clen); } /* * Clear the empty bit (except for the first descriptor, * which is cleared when the full packet has been stored). */ if (prxd != &rxd0) { prxd->ctrl &= ~MPC860_SCC_RXBD_CTRL_E; dpram_w16(d,prxd->offset+0x00,prxd->ctrl); } /* Set pointer on next RX descriptor (wrap ring if necessary) */ if (prxd->ctrl & MPC860_SCC_RXBD_CTRL_W) { bd_offset = dpram_r16(d,scc_info->dpram_base+0x00); } else { bd_offset += MPC860_SCC_BD_SIZE; } dpram_w16(d,scc_info->dpram_base+0x10,bd_offset); /* If this is the last descriptor, we have finished */ if (!tot_len) { mpc860_scc_fetch_bd(d,bd_offset,&crxd); prxd = &crxd; } } /* Clear the Empty bit of the first RX descriptor and set First bit */ rxd0.ctrl &= ~MPC860_SCC_RXBD_CTRL_E; rxd0.ctrl |= MPC860_SCC_RXBD_CTRL_F; dpram_w16(d,rxd0.offset+0x00,rxd0.ctrl); /* Trigger SCC IRQ */ if (irq) { d->scc_chan[scc_chan].scce |= MPC860_SCCE_RXB; mpc860_scc_update_irq(d,scc_chan); } return(TRUE);}/* Set NIO for the specified SCC channel */int mpc860_scc_set_nio(struct mpc860_data *d,u_int scc_chan,netio_desc_t *nio){ struct mpc860_scc_chan *chan; if (!d || (scc_chan >= MPC860_SCC_NR_CHAN)) return(-1); chan = &d->scc_chan[scc_chan]; /* check that a NIO is not already bound */ if (chan->nio != NULL) return(-1); chan->nio = nio; netio_rxl_add(nio,(netio_rx_handler_t)mpc860_scc_handle_rx_pkt, d,(void *)scc_chan); return(0);}/* Unset NIO of the specified SCC channel */int mpc860_scc_unset_nio(struct mpc860_data *d,u_int scc_chan){ struct mpc860_scc_chan *chan; if (!d || (scc_chan >= MPC860_SCC_NR_CHAN)) return(-1); chan = &d->scc_chan[scc_chan]; if (chan->nio != NULL) { netio_rxl_remove(chan->nio); chan->nio = NULL; } return(0);}/* * SCC register access. * * SCC1: 0x0a00 to 0x0a1f * SCC2: 0x0a20 to 0x0a3f * SCC3: 0x0a40 to 0x0a5f * SCC4: 0x0a60 to 0x0a7f */static int dev_mpc860_scc_access(struct mpc860_data *d,m_uint32_t offset, u_int op_size,u_int op_type,m_uint64_t *data){ struct mpc860_scc_chan *chan; u_int scc_chan,reg; /* Extract channel ID and register */ scc_chan = (offset >> 5) & 0x03; reg = offset & 0x1F; chan = &d->scc_chan[scc_chan]; switch(reg) { /* GSMRL - General SCC mode register (Low part) */ case 0x00: if (op_type == MTS_READ) *data = chan->gsmr_lo; else chan->gsmr_lo = *data; break; /* GSMRH - General SCC mode register (High part) */ case 0x04: if (op_type == MTS_READ) *data = chan->gsmr_hi; else chan->gsmr_hi = *data; break; /* PSMR - Protocol-Specific Mode Register */ case 0x08: if (op_type == MTS_READ) *data = chan->psmr; else chan->psmr = *data; break; /* TOD - Transmit On Demand */ case 0x0c: if ((op_type == MTS_WRITE) && (*data & 0x8000)) mpc860_scc_handle_tx_ring(d,scc_chan); break; /* SCCE - SCC Event Register */ case 0x10: if (op_type == MTS_READ) *data = chan->scce; else { chan->scce &= ~(*data); mpc860_scc_update_irq(d,scc_chan); } break; /* SCCM - SCC Mask Register */ case 0x14: if (op_type == MTS_READ) *data = chan->sccm; else { chan->sccm = *data; mpc860_scc_update_irq(d,scc_chan); } break; } return(0);}/* ======================================================================== *//* FEC (Fast Ethernet Controller) *//* ======================================================================== *//* Trigger interrupt for FEC */static void mpc860_fec_update_irq_status(struct mpc860_data *d){ u_int level,siu_bit; level = (d->fec_ivec & MPC860_IVEC_ILEVEL_MASK) >> MPC860_IVEC_ILEVEL_SHIFT; siu_bit = mpc860_get_siu_lvl(level); if (d->fec_ievent & d->fec_imask) mpc860_set_pending_irq(d,siu_bit); else mpc860_clear_pending_irq(d,siu_bit);}/* Fetch a FEC buffer descriptor, located in external memory */static int mpc860_fec_fetch_bd(struct mpc860_data *d,m_uint32_t bd_addr, struct mpc860_fec_bd *bd){ m_uint32_t w0,w1; /* Set BD address */ bd->bd_addr = bd_addr; w0 = physmem_copy_u32_from_vm(d->vm,bd_addr); w1 = physmem_copy_u32_from_vm(d->vm,bd_addr+4); bd->ctrl = w0 >> 16; bd->buf_len = w0 & 0xFFFF; bd->bp = w1;#if DEBUG_FEC MPC_LOG(d,"fetched FEC BD at 0x%8.8x, bp=0x%8.8x, len=%d\n", bd->bd_addr,bd->bp,bd->buf_len);#endif return(0);}/* Handle the TX ring of the FEC (transmit a single packet) */static int mpc860_fec_handle_tx_ring_single(struct mpc860_data *d){ u_char tx_pkt[MPC860_FEC_MAX_PKT_SIZE]; struct mpc860_fec_bd txd0,ctxd,*ptxd; m_uint32_t clen,tot_len; u_char *pkt_ptr; int done = FALSE; if (!d->fec_xdes_current) return(FALSE); /* Try to acquire the first descriptor */ ptxd = &txd0; mpc860_fec_fetch_bd(d,d->fec_xdes_current,ptxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(txd0.ctrl & MPC860_FEC_TXBD_CTRL_R)) return(FALSE); /* Empty packet for now */ pkt_ptr = tx_pkt; tot_len = 0; do { /* Copy data into the buffer */ clen = ptxd->buf_len; physmem_copy_from_vm(d->vm,pkt_ptr,ptxd->bp,clen); pkt_ptr += clen; tot_len += clen; /* * Clear the ready bit (except for the first descriptor, * which is cleared when the full packet has been sent). */ if (ptxd != &txd0) { ptxd->ctrl &= ~MPC860_FEC_TXBD_CTRL_R; physmem_copy_u16_to_vm(d->vm,ptxd->bd_addr+0x00,ptxd->ctrl); } /* Set pointer on next TX descriptor (wrap ring if necessary) */ if (ptxd->ctrl & MPC860_FEC_TXBD_CTRL_W) { d->fec_xdes_current = d->fec_xdes_start; } else { d->fec_xdes_current += MPC860_FEC_BD_SIZE; } /* If this is the last descriptor, we have finished */ if (!(ptxd->ctrl & MPC860_FEC_TXBD_CTRL_L)) { mpc860_fec_fetch_bd(d,d->fec_xdes_current,&ctxd); ptxd = &ctxd; } else { done = TRUE; } }while(!done); if (tot_len != 0) {#if DEBUG_FEC MPC_LOG(d,"FEC: sending packet of %u bytes\n",tot_len); mem_dump(log_file,tx_pkt,tot_len);#endif /* send packet on wire */ netio_send(d->fec_nio,tx_pkt,tot_len); } /* Clear the Ready bit of the first TX descriptor */ txd0.ctrl &= ~MPC860_FEC_TXBD_CTRL_R; physmem_copy_u16_to_vm(d->vm,txd0.bd_addr+0x00,txd0.ctrl); /* Trigger FEC IRQ */ d->fec_ievent |= MPC860_IEVENT_TFINT | MPC860_IEVENT_TXB; mpc860_fec_update_irq_status(d); return(TRUE);}/* Handle the TX ring of the FEC (multiple pkts possible) */static int mpc860_fec_handle_tx_ring(struct mpc860_data *d){ int i; for(i=0;i<MPC860_TXRING_PASS_COUNT;i++) if (!mpc860_fec_handle_tx_ring_single(d)) break; return(TRUE);}/* Handle RX packet for the Fast Ethernet Controller */static int mpc860_fec_handle_rx_pkt(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct mpc860_data *d,void *arg){ n_eth_hdr_t *hdr = (n_eth_hdr_t *)pkt; struct mpc860_fec_bd rxd0,crxd,*prxd; ssize_t clen,tot_len; u_char *pkt_ptr; if (!d->fec_rdes_current) return(FALSE); /* Try to acquire the first descriptor */ prxd = &rxd0; mpc860_fec_fetch_bd(d,d->fec_rdes_current,prxd); /* If we don't own the first descriptor, we cannot transmit */ if (!(rxd0.ctrl & MPC860_FEC_RXBD_CTRL_E)) return(FALSE); pkt_ptr = pkt; tot_len = pkt_len; while(tot_len > 0) { /* Write data into the RX buffer */ clen = m_min(d->fec_rbuf_size,tot_len); physmem_copy_to_vm(d->vm,pkt_ptr,prxd->bp,clen); pkt_ptr += clen; tot_len -= clen; /* Set the Last flag if we have finished */ if (!tot_len) { /* Set the full length */ physmem_copy_u16_to_vm(d->vm,prxd->bd_addr+0x02,pkt_len+4); prxd->ctrl |= MPC860_FEC_RXBD_CTRL_L; if (eth_addr_is_bcast(&hdr->daddr)) prxd->ctrl |= MPC860_FEC_RXBD_CTRL_BC; else if (eth_addr_is_mcast(&hdr->daddr)) prxd->ctrl |= MPC860_FEC_RXBD_CTRL_MC; } else { /* Update the length field */ physmem_copy_u16_to_vm(d->vm,prxd->bd_addr+0x02,clen); } /* * Clear the empty bit (except for the first descriptor, * which is cleared when the full packet has been stored). */ if (prxd != &rxd0) { prxd->ctrl &= ~MPC860_FEC_RXBD_CTRL_E; physmem_copy_u16_to_vm(d->vm,prxd->bd_addr+0x00,prxd->ctrl); } /* Set pointer on next RX descriptor (wrap ring if necessary) */ if (prxd->ctrl & MPC860_FEC_RXBD_CTRL_W) { d->fec_rdes_current = d->fec_rdes_start; } else { d->fec_rdes_current += MPC860_FEC_BD_SIZE; } /* If this is the last descriptor, we have finished */ if (!tot_len) { mpc860_fec_fetch_bd(d,d->fec_rdes_current,&crxd); prxd = &crxd; } } /* Clear the Empty bit of the first RX descriptor */ rxd0.ctrl &= ~MPC860_FEC_RXBD_CTRL_E; physmem_copy_u16_to_vm(d->vm,rxd0.bd_addr+0x00,rxd0.ctrl); /* Trigger FEC IRQ */ d->fec_ievent |= MPC860_IEVENT_RFINT | MPC860_IEVENT_RXB; mpc860_fec_update_irq_status(d); return(TRUE);}/* MII register read access */static void mpc860_fec_mii_read_access(struct mpc860_data *d, u_int phy,u_int reg){ m_uint16_t res; res = d->fec_mii_regs[reg]; switch(reg) { case 0x00: res = 0x1100; break; case 0x01: if (d->fec_nio) res = 0x7829; else res = 0; break; case 0x02: res = 0x7810; break; case 0x03: res = 0x0003; break; case 0x04: res = 0x1E1; break; case 0x05: res = 0x41E1; break; case 0x06: res = 0x0004; break; case 0x10: res = 0x0084; break; case 0x11: res = 0x4780; break; case 0x12: res = 0x4000; break; case 0x13: res = 0x0094; break; case 0x14: res = 0x28c8; break; default: res = 0; } d->fec_mii_data &= 0xFFFF0000; d->fec_mii_data |= res;}/* MII register read access */static void mpc860_fec_mii_write_access(struct mpc860_data *d, u_int phy,u_int reg){#if DEBUG_FEC MPC_LOG(d,"FEC: Writing 0x%8.8x to MII reg %d\n", d->fec_mii_data & 0xFFFF,reg);#endif d->fec_mii_regs[reg] = d->fec_mii_data & 0xFFFF;}/* MII register access */static void mpc860_fec_mii_access(struct mpc860_data *d){ u_int op,phy,reg; op = (d->fec_mii_data & MPC860_MII_OP_MASK) >> MPC860_MII_OP_SHIFT; phy = (d->fec_mii_data & MPC860_MII_PHY_MASK) >> MPC860_MII_PHY_SHIFT; reg = (d->fec_mii_data & MPC860_MII_REG_MASK) >> MPC860_MII_REG_SHIFT; switch(op) { /* MII write */ case 0x01: mpc860_fec_mii_write_access(d,phy,reg); break; /* MII read */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -