📄 4xx_enet.c
字号:
/* handle MAX TX EOB interrupt from a tx */ if (my_uic0msr & UIC_MTE) { mal_rx_eob = mfdcr (maltxeobisr); mtdcr (maltxeobisr, mal_rx_eob); mtdcr (UIC0SR, UIC_MTE); } /* handle MAL RX EOB interupt from a receive */ /* check for EOB on valid channels */ if (my_uic0msr & UIC_MRE) { mal_rx_eob = mfdcr (malrxeobisr); if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */ /* clear EOB mtdcr(malrxeobisr, mal_rx_eob); */ enet_rcv (dev, emac_isr); /* indicate that we serviced an interrupt */ serviced = 1; rc = 0; } } mtdcr (UIC0SR, UIC_MRE); /* Clear */ mtdcr (uic1sr, UIC_MS | UIC_MTDE | UIC_MRDE); /* Clear */ switch (hw_p->devnum) { case 0: mtdcr (uic1sr, UIC_ETH0); break; case 1: mtdcr (uic1sr, UIC_ETH1); break;#if defined (CONFIG_440GX) case 2: mtdcr (uic2sr, UIC_ETH2); break; case 3: mtdcr (uic2sr, UIC_ETH3); break;#endif /* CONFIG_440GX */ default: break; } } while (serviced); return (rc);}#else /* CONFIG_440 */int enetInt (struct eth_device *dev){ int serviced; int rc = -1; /* default to not us */ unsigned long mal_isr; unsigned long emac_isr = 0; unsigned long mal_rx_eob; unsigned long my_uicmsr; EMAC_4XX_HW_PST hw_p; /* * Because the mal is generic, we need to get the current * eth device */#if defined(CONFIG_NET_MULTI) dev = eth_get_dev();#else dev = emac0_dev;#endif hw_p = dev->priv; /* enter loop that stays in interrupt code until nothing to service */ do { serviced = 0; my_uicmsr = mfdcr (uicmsr); if ((my_uicmsr & (MAL_UIC_DEF | EMAC_UIC_DEF)) == 0) { /* not for us */ return (rc); } /* get and clear controller status interrupts */ /* look at Mal and EMAC interrupts */ if ((MAL_UIC_DEF & my_uicmsr) != 0) { /* we have a MAL interrupt */ mal_isr = mfdcr (malesr); /* look for mal error */ if ((my_uicmsr & MAL_UIC_ERR) != 0) { mal_err (dev, mal_isr, my_uicmsr, MAL_UIC_DEF, MAL_UIC_ERR); serviced = 1; rc = 0; } } /* port by port dispatch of emac interrupts */ if ((SEL_UIC_DEF(hw_p->devnum) & my_uicmsr) != 0) { /* look for EMAC errors */ emac_isr = in32 (EMAC_ISR + hw_p->hw_addr); if ((hw_p->emac_ier & emac_isr) != 0) { emac_err (dev, emac_isr); serviced = 1; rc = 0; } } if (((hw_p->emac_ier & emac_isr) != 0) || ((MAL_UIC_ERR & my_uicmsr) != 0)) { mtdcr (uicsr, MAL_UIC_DEF | SEL_UIC_DEF(hw_p->devnum)); /* Clear */ return (rc); /* we had errors so get out */ } /* handle MAX TX EOB interrupt from a tx */ if (my_uicmsr & UIC_MAL_TXEOB) { mal_rx_eob = mfdcr (maltxeobisr); mtdcr (maltxeobisr, mal_rx_eob); mtdcr (uicsr, UIC_MAL_TXEOB); } /* handle MAL RX EOB interupt from a receive */ /* check for EOB on valid channels */ if (my_uicmsr & UIC_MAL_RXEOB) { mal_rx_eob = mfdcr (malrxeobisr); if ((mal_rx_eob & (0x80000000 >> hw_p->devnum)) != 0) { /* call emac routine for channel x */ /* clear EOB mtdcr(malrxeobisr, mal_rx_eob); */ enet_rcv (dev, emac_isr); /* indicate that we serviced an interrupt */ serviced = 1; rc = 0; } } mtdcr (uicsr, MAL_UIC_DEF|EMAC_UIC_DEF|EMAC_UIC_DEF1); /* Clear */ } while (serviced); return (rc);}#endif /* CONFIG_440 *//*-----------------------------------------------------------------------------+ * MAL Error Routine *-----------------------------------------------------------------------------*/static void mal_err (struct eth_device *dev, unsigned long isr, unsigned long uic, unsigned long maldef, unsigned long mal_errr){ EMAC_4XX_HW_PST hw_p = dev->priv; mtdcr (malesr, isr); /* clear interrupt */ /* clear DE interrupt */ mtdcr (maltxdeir, 0xC0000000); mtdcr (malrxdeir, 0x80000000);#ifdef INFO_4XX_ENET printf ("\nMAL error occured.... ISR = %lx UIC = = %lx MAL_DEF = %lx MAL_ERR= %lx \n", isr, uic, maldef, mal_errr);#endif eth_init (hw_p->bis); /* start again... */}/*-----------------------------------------------------------------------------+ * EMAC Error Routine *-----------------------------------------------------------------------------*/static void emac_err (struct eth_device *dev, unsigned long isr){ EMAC_4XX_HW_PST hw_p = dev->priv; printf ("EMAC%d error occured.... ISR = %lx\n", hw_p->devnum, isr); out32 (EMAC_ISR + hw_p->hw_addr, isr);}/*-----------------------------------------------------------------------------+ * enet_rcv() handles the ethernet receive data *-----------------------------------------------------------------------------*/static void enet_rcv (struct eth_device *dev, unsigned long malisr){ struct enet_frame *ef_ptr; unsigned long data_len; unsigned long rx_eob_isr; EMAC_4XX_HW_PST hw_p = dev->priv; int handled = 0; int i; int loop_count = 0; rx_eob_isr = mfdcr (malrxeobisr); if ((0x80000000 >> hw_p->devnum) & rx_eob_isr) { /* clear EOB */ mtdcr (malrxeobisr, rx_eob_isr); /* EMAC RX done */ while (1) { /* do all */ i = hw_p->rx_slot; if ((MAL_RX_CTRL_EMPTY & hw_p->rx[i].ctrl) || (loop_count >= NUM_RX_BUFF)) break; loop_count++; hw_p->rx_slot++; if (NUM_RX_BUFF == hw_p->rx_slot) hw_p->rx_slot = 0; handled++; data_len = (unsigned long) hw_p->rx[i].data_len; /* Get len */ if (data_len) { if (data_len > ENET_MAX_MTU) /* Check len */ data_len = 0; else { if (EMAC_RX_ERRORS & hw_p->rx[i].ctrl) { /* Check Errors */ data_len = 0; hw_p->stats.rx_err_log[hw_p-> rx_err_index] = hw_p->rx[i].ctrl; hw_p->rx_err_index++; if (hw_p->rx_err_index == MAX_ERR_LOG) hw_p->rx_err_index = 0; } /* emac_erros */ } /* data_len < max mtu */ } /* if data_len */ if (!data_len) { /* no data */ hw_p->rx[i].ctrl |= MAL_RX_CTRL_EMPTY; /* Free Recv Buffer */ hw_p->stats.data_len_err++; /* Error at Rx */ } /* !data_len */ /* AS.HARNOIS */ /* Check if user has already eaten buffer */ /* if not => ERROR */ else if (hw_p->rx_ready[hw_p->rx_i_index] != -1) { if (hw_p->is_receiving) printf ("ERROR : Receive buffers are full!\n"); break; } else { hw_p->stats.rx_frames++; hw_p->stats.rx += data_len; ef_ptr = (struct enet_frame *) hw_p->rx[i]. data_ptr;#ifdef INFO_4XX_ENET hw_p->stats.pkts_rx++;#endif /* AS.HARNOIS * use ring buffer */ hw_p->rx_ready[hw_p->rx_i_index] = i; hw_p->rx_i_index++; if (NUM_RX_BUFF == hw_p->rx_i_index) hw_p->rx_i_index = 0; /* AS.HARNOIS * free receive buffer only when * buffer has been handled (eth_rx) rx[i].ctrl |= MAL_RX_CTRL_EMPTY; */ } /* if data_len */ } /* while */ } /* if EMACK_RXCHL */}static int ppc_4xx_eth_rx (struct eth_device *dev){ int length; int user_index; unsigned long msr; EMAC_4XX_HW_PST hw_p = dev->priv; hw_p->is_receiving = 1; /* tell driver */ for (;;) { /* AS.HARNOIS * use ring buffer and * get index from rx buffer desciptor queue */ user_index = hw_p->rx_ready[hw_p->rx_u_index]; if (user_index == -1) { length = -1; break; /* nothing received - leave for() loop */ } msr = mfmsr (); mtmsr (msr & ~(MSR_EE)); length = hw_p->rx[user_index].data_len; /* Pass the packet up to the protocol layers. */ /* NetReceive(NetRxPackets[rxIdx], length - 4); */ /* NetReceive(NetRxPackets[i], length); */ NetReceive (NetRxPackets[user_index], length - 4); /* Free Recv Buffer */ hw_p->rx[user_index].ctrl |= MAL_RX_CTRL_EMPTY; /* Free rx buffer descriptor queue */ hw_p->rx_ready[hw_p->rx_u_index] = -1; hw_p->rx_u_index++; if (NUM_RX_BUFF == hw_p->rx_u_index) hw_p->rx_u_index = 0;#ifdef INFO_4XX_ENET hw_p->stats.pkts_handled++;#endif mtmsr (msr); /* Enable IRQ's */ } hw_p->is_receiving = 0; /* tell driver */ return length;}int ppc_4xx_eth_initialize (bd_t * bis){ static int virgin = 0; struct eth_device *dev; int eth_num = 0; EMAC_4XX_HW_PST hw = NULL;#if defined(CONFIG_440GX) unsigned long pfc1; mfsdr (sdr_pfc1, pfc1); pfc1 &= ~(0x01e00000); pfc1 |= 0x01200000; mtsdr (sdr_pfc1, pfc1);#endif /* set phy num and mode */ bis->bi_phynum[0] = CONFIG_PHY_ADDR;#if defined(CONFIG_PHY1_ADDR) bis->bi_phynum[1] = CONFIG_PHY1_ADDR;#endif#if defined(CONFIG_440GX) bis->bi_phynum[2] = CONFIG_PHY2_ADDR; bis->bi_phynum[3] = CONFIG_PHY3_ADDR; bis->bi_phymode[0] = 0; bis->bi_phymode[1] = 0; bis->bi_phymode[2] = 2; bis->bi_phymode[3] = 2;#if defined (CONFIG_440GX) ppc_4xx_eth_setup_bridge(0, bis);#endif#endif for (eth_num = 0; eth_num < LAST_EMAC_NUM; eth_num++) { /* See if we can actually bring up the interface, otherwise, skip it */ switch (eth_num) { default: /* fall through */ case 0: if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) { bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; continue; } break;#ifdef CONFIG_HAS_ETH1 case 1: if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) { bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; continue; } break;#endif#ifdef CONFIG_HAS_ETH2 case 2: if (memcmp (bis->bi_enet2addr, "\0\0\0\0\0\0", 6) == 0) { bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; continue; } break;#endif#ifdef CONFIG_HAS_ETH3 case 3: if (memcmp (bis->bi_enet3addr, "\0\0\0\0\0\0", 6) == 0) { bis->bi_phymode[eth_num] = BI_PHYMODE_NONE; continue; } break;#endif } /* Allocate device structure */ dev = (struct eth_device *) malloc (sizeof (*dev)); if (dev == NULL) { printf ("ppc_4xx_eth_initialize: " "Cannot allocate eth_device %d\n", eth_num); return (-1); } memset(dev, 0, sizeof(*dev)); /* Allocate our private use data */ hw = (EMAC_4XX_HW_PST) malloc (sizeof (*hw)); if (hw == NULL) { printf ("ppc_4xx_eth_initialize: " "Cannot allocate private hw data for eth_device %d", eth_num); free (dev); return (-1); } memset(hw, 0, sizeof(*hw)); switch (eth_num) { default: /* fall through */ case 0: hw->hw_addr = 0; memcpy (dev->enetaddr, bis->bi_enetaddr, 6); break;#ifdef CONFIG_HAS_ETH1 case 1: hw->hw_addr = 0x100; memcpy (dev->enetaddr, bis->bi_enet1addr, 6); break;#endif#ifdef CONFIG_HAS_ETH2 case 2: hw->hw_addr = 0x400; memcpy (dev->enetaddr, bis->bi_enet2addr, 6); break;#endif#ifdef CONFIG_HAS_ETH3 case 3: hw->hw_addr = 0x600; memcpy (dev->enetaddr, bis->bi_enet3addr, 6); break;#endif } hw->devnum = eth_num; hw->print_speed = 1; sprintf (dev->name, "ppc_4xx_eth%d", eth_num); dev->priv = (void *) hw; dev->init = ppc_4xx_eth_init; dev->halt = ppc_4xx_eth_halt; dev->send = ppc_4xx_eth_send; dev->recv = ppc_4xx_eth_rx; if (0 == virgin) { /* set the MAL IER ??? names may change with new spec ??? */ mal_ier = MAL_IER_DE | MAL_IER_NE | MAL_IER_TE | MAL_IER_OPBE | MAL_IER_PLBE; mtdcr (malesr, 0xffffffff); /* clear pending interrupts */ mtdcr (maltxdeir, 0xffffffff); /* clear pending interrupts */ mtdcr (malrxdeir, 0xffffffff); /* clear pending interrupts */ mtdcr (malier, mal_ier); /* install MAL interrupt handler */ irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, dev); irq_install_handler (VECNUM_MTE, (interrupt_handler_t *) enetInt, dev); irq_install_handler (VECNUM_MRE, (interrupt_handler_t *) enetInt, dev); irq_install_handler (VECNUM_TXDE, (interrupt_handler_t *) enetInt, dev); irq_install_handler (VECNUM_RXDE, (interrupt_handler_t *) enetInt, dev); virgin = 1; }#if defined(CONFIG_NET_MULTI) eth_register (dev);#else emac0_dev = dev;#endif#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) miiphy_register (dev->name, emac4xx_miiphy_read, emac4xx_miiphy_write);#endif } /* end for each supported device */ return (1);}#if !defined(CONFIG_NET_MULTI)void eth_halt (void) { if (emac0_dev) { ppc_4xx_eth_halt(emac0_dev); free(emac0_dev); emac0_dev = NULL; }}int eth_init (bd_t *bis){ ppc_4xx_eth_initialize(bis); if (emac0_dev) { return ppc_4xx_eth_init(emac0_dev, bis); } else { printf("ERROR: ethaddr not set!\n"); return -1; }}int eth_send(volatile void *packet, int length){ return (ppc_4xx_eth_send(emac0_dev, packet, length));}int eth_rx(void){ return (ppc_4xx_eth_rx(emac0_dev));}int emac4xx_miiphy_initialize (bd_t * bis){#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) miiphy_register ("ppc_4xx_eth0", emac4xx_miiphy_read, emac4xx_miiphy_write);#endif return 0;}#endif /* !defined(CONFIG_NET_MULTI) */#endif /* #if (CONFIG_COMMANDS & CFG_CMD_NET) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -