From 75482a0663d789a7bc55eedff4a4f6fed0d3f811 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:05:36 +0200 Subject: [PATCH 01/13] net: ifup: Set current ethernet device when doing ifup When doing an ifup set the current interface to the one just brought up so that it is actually used. Signed-off-by: Sascha Hauer --- net/ifup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ifup.c b/net/ifup.c index 409b338ec..f3b65f780 100644 --- a/net/ifup.c +++ b/net/ifup.c @@ -58,6 +58,8 @@ int ifup(const char *name, unsigned flags) if (edev && edev->ipaddr && !(flags & IFUP_FLAG_FORCE)) return 0; + eth_set_current(edev); + env_push_context(); setenv("ip", ""); From 22b878d2518a2b31c5991f9c47a2b176f0ac246d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:04:10 +0200 Subject: [PATCH 02/13] net: Pass eth_device to net_receive So that barebox has the information which interface a packet came from. Signed-off-by: Sascha Hauer --- drivers/net/altera_tse.c | 2 +- drivers/net/ar231x.c | 2 +- drivers/net/arc_emac.c | 2 +- drivers/net/at91_ether.c | 2 +- drivers/net/cpsw.c | 2 +- drivers/net/cs8900.c | 2 +- drivers/net/davinci_emac.c | 2 +- drivers/net/designware.c | 2 +- drivers/net/dm9k.c | 2 +- drivers/net/ep93xx.c | 2 +- drivers/net/ethoc.c | 2 +- drivers/net/fec_imx.c | 2 +- drivers/net/fec_mpc5200.c | 2 +- drivers/net/gianfar.c | 2 +- drivers/net/ks8851_mll.c | 2 +- drivers/net/macb.c | 4 ++-- drivers/net/netx_eth.c | 2 +- drivers/net/orion-gbe.c | 2 +- drivers/net/smc91111.c | 2 +- drivers/net/smc911x.c | 2 +- drivers/net/tap.c | 2 +- drivers/net/usb/asix.c | 2 +- drivers/net/usb/smsc95xx.c | 4 ++-- drivers/net/usb/usbnet.c | 2 +- drivers/net/xgmac.c | 2 +- include/net.h | 2 +- net/net.c | 2 +- 27 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c index 6978e2a2e..4bbf59558 100644 --- a/drivers/net/altera_tse.c +++ b/drivers/net/altera_tse.c @@ -402,7 +402,7 @@ static int tse_eth_rx(struct eth_device *edev) ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { packet_length = rx_desc->actual_bytes_transferred; - net_receive(NetRxPackets[0], packet_length); + net_receive(edev, NetRxPackets[0], packet_length); /* Clear Run */ rx_sgdma->control = (rx_sgdma->control & (~ALT_SGDMA_CONTROL_RUN_MSK)); diff --git a/drivers/net/ar231x.c b/drivers/net/ar231x.c index 515de17b1..572008a83 100644 --- a/drivers/net/ar231x.c +++ b/drivers/net/ar231x.c @@ -217,7 +217,7 @@ static int ar231x_eth_recv(struct eth_device *edev) u16 length = ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN; - net_receive((void *)rxdsc->buffer_ptr, length); + net_receive(edev, (void *)rxdsc->buffer_ptr, length); } /* Clean descriptor. now it is owned by DMA. */ priv->next_rxdsc = (struct ar231x_descr *)rxdsc->next_dsc_ptr; diff --git a/drivers/net/arc_emac.c b/drivers/net/arc_emac.c index 1f1e88919..3f6f81495 100644 --- a/drivers/net/arc_emac.c +++ b/drivers/net/arc_emac.c @@ -304,7 +304,7 @@ static int arc_emac_recv(struct eth_device *edev) dma_inv_range((unsigned long)rxbd->data, (unsigned long)rxbd->data + pktlen); - net_receive((unsigned char *)rxbd->data, pktlen); + net_receive(edev, (unsigned char *)rxbd->data, pktlen); rxbd->info = cpu_to_le32(FOR_EMAC | PKTSIZE); } diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c index bf2f957a3..e09ea83f6 100644 --- a/drivers/net/at91_ether.c +++ b/drivers/net/at91_ether.c @@ -224,7 +224,7 @@ static int at91_ether_rx(struct eth_device *edev) size = rbfp->size & RBF_SIZE; - net_receive((unsigned char *)(rbfp->addr & RBF_ADDR), size); + net_receive(edev, (unsigned char *)(rbfp->addr & RBF_ADDR), size); rbfp->addr &= ~RBF_OWNER; if (rbfp->addr & RBF_WRAP) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index ec3263d4a..a5cbacf09 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -895,7 +895,7 @@ static int cpsw_recv(struct eth_device *edev) while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) { dma_inv_range((ulong)buffer, (ulong)buffer + len); - net_receive(buffer, len); + net_receive(edev, buffer, len); cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE); } diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c index aa9d9a079..dccb808f9 100644 --- a/drivers/net/cs8900.c +++ b/drivers/net/cs8900.c @@ -309,7 +309,7 @@ static int cs8900_recv(struct eth_device *dev) if (len & 1) { *addr++ = readw(priv->regs + CS8900_RTDATA0); } - net_receive(NetRxPackets[0], len); + net_receive(dev, NetRxPackets[0], len); return len; } diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 7848f50b9..ce367a365 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -462,7 +462,7 @@ static int davinci_emac_recv(struct eth_device *edev) dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len); dma_inv_range((ulong)pkt, (ulong)readl(rx_curr_desc + EMAC_DESC_BUFFER) + len); - net_receive(pkt, len); + net_receive(edev, pkt, len); ret = len; } diff --git a/drivers/net/designware.c b/drivers/net/designware.c index e706f54b3..ac2eca5ae 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -356,7 +356,7 @@ static int dwc_ether_rx(struct eth_device *dev) dma_inv_range((unsigned long)desc_p->dmamac_addr, (unsigned long)desc_p->dmamac_addr + length); - net_receive(desc_p->dmamac_addr, length); + net_receive(dev, desc_p->dmamac_addr, length); desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c index 4c288709a..e98b8f408 100644 --- a/drivers/net/dm9k.c +++ b/drivers/net/dm9k.c @@ -633,7 +633,7 @@ static int dm9k_eth_rx(struct eth_device *edev) dev_dbg(dev, "Receiving packet\n"); dm9k_rd(priv->buswidth, priv->iodata, priv->pckt, rx_len); dev_dbg(dev, "passing %u bytes packet to upper layer\n", rx_len); - net_receive(priv->pckt, rx_len); + net_receive(edev, priv->pckt, rx_len); } else { dev_dbg(dev, "Discarding packet\n"); dm9k_dump(priv->buswidth, priv->iodata, rx_len); /* discard packet */ diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c index 1ecef1339..4b73abff3 100644 --- a/drivers/net/ep93xx.c +++ b/drivers/net/ep93xx.c @@ -344,7 +344,7 @@ static int ep93xx_eth_rcv_packet(struct eth_device *edev) * used when we pass the data off to the protocol * layer via net_receive(). */ - net_receive((uchar *)priv->rx_dq.current->word1, + net_receive(edev, (uchar *)priv->rx_dq.current->word1, RX_STATUS_FRAME_LEN(priv->rx_sq.current)); pr_debug("reporting %d bytes...\n", RX_STATUS_FRAME_LEN(priv->rx_sq.current)); diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index b00087578..ced84df7a 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -369,7 +369,7 @@ static int ethoc_rx(struct eth_device *edev, int limit) size -= 4; /* strip the CRC */ invalidate_dcache_range(bd.addr, bd.addr + PKTSIZE); - net_receive((unsigned char *)bd.addr, size); + net_receive(edev, (unsigned char *)bd.addr, size); } /* clear the buffer descriptor so it can be reused */ diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c index 72e689dcb..88f9e75df 100644 --- a/drivers/net/fec_imx.c +++ b/drivers/net/fec_imx.c @@ -581,7 +581,7 @@ static int fec_recv(struct eth_device *dev) */ frame = phys_to_virt(readl(&rbd->data_pointer)); frame_length = readw(&rbd->data_length) - 4; - net_receive(frame->data, frame_length); + net_receive(dev, frame->data, frame_length); len = frame_length; } else { if (bd_status & FEC_RBD_ERR) { diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c index acad20c23..41a3b58d5 100644 --- a/drivers/net/fec_mpc5200.c +++ b/drivers/net/fec_mpc5200.c @@ -622,7 +622,7 @@ static int mpc5xxx_fec_recv(struct eth_device *dev) */ memcpy(buff, frame->head, 14); memcpy(buff + 14, frame->data, frame_length); - net_receive(buff, frame_length); + net_receive(dev, buff, frame_length); len = frame_length; } /* diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index f944c6c06..3370b5cdb 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -413,7 +413,7 @@ static int gfar_recv(struct eth_device *edev) /* Send the packet up if there were no errors */ if (!(priv->rxbd[priv->rxidx].status & RXBD_STATS)) { - net_receive(NetRxPackets[priv->rxidx], length - 4); + net_receive(edev, NetRxPackets[priv->rxidx], length - 4); } else { dev_err(dev, "Got error %x\n", (priv->rxbd[priv->rxidx].status & RXBD_STATS)); diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 9c0e5a7a1..83d1b0280 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -693,7 +693,7 @@ static int ks8851_rx_frame(struct ks_net *ks) if (RxStatus & RXFSHR_RXFV) { /* Pass to upper layer */ dev_dbg(dev, "passing packet to upper layer\n\n"); - net_receive(NetRxPackets[0], RxLen); + net_receive(&ks->edev, NetRxPackets[0], RxLen); return RxLen; } else if (RxStatus & RXFSHR_ERR) { dev_err(dev, "RxStatus error 0x%04x\n", RxStatus & RXFSHR_ERR); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index d8523cee3..12a2a3c6c 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -187,7 +187,7 @@ static int gem_recv(struct eth_device *edev) status = macb->rx_ring[macb->rx_tail].ctrl; length = MACB_BFEXT(RX_FRMLEN, status); buffer = macb->rx_buffer + macb->rx_buffer_size * macb->rx_tail; - net_receive(buffer, length); + net_receive(edev, buffer, length); macb->rx_ring[macb->rx_tail].addr &= ~MACB_BIT(RX_USED); barrier(); @@ -237,7 +237,7 @@ static int macb_recv(struct eth_device *edev) buffer = (void *)NetRxPackets[0]; } - net_receive(buffer, length); + net_receive(edev, buffer, length); if (++rx_tail >= macb->rx_ring_size) rx_tail = 0; reclaim_rx_buffers(macb, rx_tail); diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c index 309f4cb73..96dbc7c5d 100644 --- a/drivers/net/netx_eth.c +++ b/drivers/net/netx_eth.c @@ -110,7 +110,7 @@ static int netx_eth_rx (struct eth_device *edev) /* get data */ memcpy((void*)NetRxPackets[0], (void *)(SRAM_BASE(seg) + frameno * 1560), len); /* pass to barebox */ - net_receive(NetRxPackets[0], len); + net_receive(edev, NetRxPackets[0], len); PFIFO_REG(PFIFO_BASE(EMPTY_PTR_FIFO(xcno))) = FIFO_PTR_SEGMENT(seg) | diff --git a/drivers/net/orion-gbe.c b/drivers/net/orion-gbe.c index 00f5e543c..17497047a 100644 --- a/drivers/net/orion-gbe.c +++ b/drivers/net/orion-gbe.c @@ -303,7 +303,7 @@ static int port_recv(struct eth_device *edev) ALIGN(PKTSIZE, 8)); /* received packet is padded with two null bytes */ - net_receive(rxdesc->buf_ptr + 0x2, rxdesc->byte_cnt - 0x2); + net_receive(edev, rxdesc->buf_ptr + 0x2, rxdesc->byte_cnt - 0x2); ret = 0; recv_err: diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c index ba81e2499..7baa7490f 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -1169,7 +1169,7 @@ static int smc91c111_eth_rx(struct eth_device *edev) if (!is_error) { /* Pass the packet up to the protocol layers. */ - net_receive(NetRxPackets[0], packet_length); + net_receive(edev, NetRxPackets[0], packet_length); return 0; } diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index e0d78d06e..9977ae3f3 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -478,7 +478,7 @@ static int smc911x_eth_rx(struct eth_device *edev) dev_err(&edev->dev, "dropped bad packet. Status: 0x%08x\n", status); else - net_receive(NetRxPackets[0], pktlen); + net_receive(edev, NetRxPackets[0], pktlen); } return 0; diff --git a/drivers/net/tap.c b/drivers/net/tap.c index 436b0e085..2458fb52c 100644 --- a/drivers/net/tap.c +++ b/drivers/net/tap.c @@ -45,7 +45,7 @@ int tap_eth_rx (struct eth_device *edev) length = linux_read_nonblock(priv->fd, NetRxPackets[0], PKTSIZE); if (length > 0) - net_receive(NetRxPackets[0], length); + net_receive(edev, NetRxPackets[0], length); return 0; } diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 2145d3f46..d6ac322b7 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -431,7 +431,7 @@ static int asix_rx_fixup(struct usbnet *dev, void *buf, int len) return 0; } - net_receive(buf, size); + net_receive(&dev->edev, buf, size); buf += ((size + 1) & 0xfffe); len -= ((size + 1) & 0xfffe); diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index eb8f0becc..053da1822 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -793,11 +793,11 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len) /* last frame in this batch */ if (len == size) { - net_receive(buf, len - 4); + net_receive(&dev->edev, buf, len - 4); return 1; } - net_receive(packet, len - 4); + net_receive(&dev->edev, packet, len - 4); } len -= size; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 80b4ae7b9..13f58e3ea 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -138,7 +138,7 @@ static int usbnet_recv(struct eth_device *edev) if (info->rx_fixup) return info->rx_fixup(dev, rx_buf, alen); else - net_receive(rx_buf, alen); + net_receive(edev, rx_buf, alen); } return 0; diff --git a/drivers/net/xgmac.c b/drivers/net/xgmac.c index b4bfd0899..cc22d0ea5 100644 --- a/drivers/net/xgmac.c +++ b/drivers/net/xgmac.c @@ -617,7 +617,7 @@ static int xgmac_recv(struct eth_device *edev) length = desc_get_rx_frame_len(rxdesc); - net_receive(desc_get_buf_addr(rxdesc), length); + net_receive(edev, desc_get_buf_addr(rxdesc), length); /* set descriptor back to owned by XGMAC */ desc_set_rx_owner(rxdesc); diff --git a/include/net.h b/include/net.h index 3b800b78f..a1665524c 100644 --- a/include/net.h +++ b/include/net.h @@ -413,7 +413,7 @@ struct eth_device *eth_get_byname(const char *name); * * Return 0 if the packet is successfully handled. Can be ignored */ -int net_receive(unsigned char *pkt, int len); +int net_receive(struct eth_device *edev, unsigned char *pkt, int len); struct net_connection { struct ethernet *et; diff --git a/net/net.c b/net/net.c index 20051bc12..e43a3aba6 100644 --- a/net/net.c +++ b/net/net.c @@ -619,7 +619,7 @@ bad: return 0; } -int net_receive(unsigned char *pkt, int len) +int net_receive(struct eth_device *edev, unsigned char *pkt, int len) { struct ethernet *et = (struct ethernet *)pkt; int et_protlen = ntohs(et->et_protlen); From be0404c21f22da2d736168b2e56a9ae583cc3e95 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:08:04 +0200 Subject: [PATCH 03/13] net: Allow to use multiple network interfaces at once In barebox network packets always go out at the current ethernet device and are expected to be received from the current interface. This has some side effects. When for example an NFS is mounted when one interface is active and the interface is changed afterwards the NFS packets leave the new interface, but the NFS server won't be reachable there. Instead of changing the whole network traffic to the current ethernet interface we now initialize a network connection with the current network interface, but then the connection will continue to use that interface even when the current interface is changed. Signed-off-by: Sascha Hauer --- include/net.h | 3 ++- net/eth.c | 68 +++++++++++++++++++++++++++------------------------ net/net.c | 19 +++++++------- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/include/net.h b/include/net.h index a1665524c..c0f7517c3 100644 --- a/include/net.h +++ b/include/net.h @@ -68,7 +68,7 @@ struct eth_device { int eth_register(struct eth_device* dev); /* Register network device */ void eth_unregister(struct eth_device* dev); /* Unregister network device */ -int eth_send(void *packet, int length); /* Send a packet */ +int eth_send(struct eth_device *edev, void *packet, int length); /* Send a packet */ int eth_rx(void); /* Check for received packets */ /* associate a MAC address to a ethernet device. Should be called by @@ -419,6 +419,7 @@ struct net_connection { struct ethernet *et; struct iphdr *ip; struct udphdr *udp; + struct eth_device *edev; struct icmphdr *icmp; unsigned char *packet; struct list_head list; diff --git a/net/eth.c b/net/eth.c index 3ced3cddb..26a5ff747 100644 --- a/net/eth.c +++ b/net/eth.c @@ -131,11 +131,6 @@ void of_eth_register_ethaddr(struct device_node *node, const char *ethaddr) void eth_set_current(struct eth_device *eth) { - if (eth_current && eth_current->active) { - eth_current->halt(eth_current); - eth_current->active = 0; - } - eth_current = eth; } @@ -178,83 +173,92 @@ int eth_complete(struct string_list *sl, char *instr) /* * Check for link if we haven't done so for longer. */ -static int eth_carrier_check(int force) +static int eth_carrier_check(struct eth_device *edev, int force) { int ret; if (!IS_ENABLED(CONFIG_PHYLIB)) return 0; - if (!eth_current->phydev) + if (!edev->phydev) return 0; if (force) - phy_wait_aneg_done(eth_current->phydev); + phy_wait_aneg_done(edev->phydev); if (force || is_timeout(last_link_check, 5 * SECOND) || - !eth_current->phydev->link) { - ret = phy_update_status(eth_current->phydev); + !edev->phydev->link) { + ret = phy_update_status(edev->phydev); if (ret) return ret; last_link_check = get_time_ns(); } - return eth_current->phydev->link ? 0 : -ENETDOWN; + return edev->phydev->link ? 0 : -ENETDOWN; } /* * Check if we have a current ethernet device and * eventually open it if we have to. */ -static int eth_check_open(void) +static int eth_check_open(struct eth_device *edev) { int ret; - if (!eth_current) - return -ENODEV; - - if (eth_current->active) + if (edev->active) return 0; - ret = eth_current->open(eth_current); + ret = edev->open(eth_current); if (ret) return ret; - eth_current->active = 1; + edev->active = 1; - return eth_carrier_check(1); + return eth_carrier_check(edev, 1); } -int eth_send(void *packet, int length) +int eth_send(struct eth_device *edev, void *packet, int length) { int ret; - ret = eth_check_open(); + ret = eth_check_open(edev); if (ret) return ret; - ret = eth_carrier_check(0); + ret = eth_carrier_check(edev, 0); if (ret) return ret; led_trigger_network(LED_TRIGGER_NET_TX); - return eth_current->send(eth_current, packet, length); + return edev->send(eth_current, packet, length); +} + +static int __eth_rx(struct eth_device *edev) +{ + int ret; + + ret = eth_check_open(edev); + if (ret) + return ret; + + ret = eth_carrier_check(edev, 0); + if (ret) + return ret; + + return edev->recv(eth_current); } int eth_rx(void) { - int ret; + struct eth_device *edev; - ret = eth_check_open(); - if (ret) - return ret; + list_for_each_entry(edev, &netdev_list, list) { + if (edev->active) + __eth_rx(edev); + } - ret = eth_carrier_check(0); - if (ret) - return ret; - - return eth_current->recv(eth_current); + return 0; } static int eth_set_ethaddr(struct param_d *param, void *priv) diff --git a/net/net.c b/net/net.c index e43a3aba6..f54267ae5 100644 --- a/net/net.c +++ b/net/net.c @@ -241,7 +241,7 @@ static int arp_request(IPaddr_t dest, unsigned char *ether) arp_ether = ether; - ret = eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); + ret = eth_send(edev, arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); if (ret) return ret; arp_start = get_time_ns(); @@ -253,7 +253,7 @@ static int arp_request(IPaddr_t dest, unsigned char *ether) if (is_timeout(arp_start, 3 * SECOND)) { printf("T "); arp_start = get_time_ns(); - ret = eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); + ret = eth_send(edev, arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); if (ret) return ret; retries++; @@ -358,6 +358,7 @@ static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler, con = xzalloc(sizeof(*con)); con->packet = net_alloc_packet(); con->priv = ctx; + con->edev = edev; memset(con->packet, 0, PKTSIZE); con->et = (struct ethernet *)con->packet; @@ -437,7 +438,7 @@ static int net_ip_send(struct net_connection *con, int len) con->ip->check = 0; con->ip->check = ~net_checksum((unsigned char *)con->ip, sizeof(struct iphdr)); - return eth_send(con->packet, ETHER_HDR_SIZE + sizeof(struct iphdr) + len); + return eth_send(con->edev, con->packet, ETHER_HDR_SIZE + sizeof(struct iphdr) + len); } int net_udp_send(struct net_connection *con, int len) @@ -480,7 +481,7 @@ static int net_answer_arp(unsigned char *pkt, int len) if (!packet) return 0; memcpy(packet, pkt, ETHER_HDR_SIZE + ARP_HDR_SIZE); - ret = eth_send(packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); + ret = eth_send(edev, packet, ETHER_HDR_SIZE + ARP_HDR_SIZE); free(packet); return ret; @@ -497,9 +498,8 @@ static void net_bad_packet(unsigned char *pkt, int len) #endif } -static int net_handle_arp(unsigned char *pkt, int len) +static int net_handle_arp(struct eth_device *edev, unsigned char *pkt, int len) { - struct eth_device *edev = eth_get_current(); struct arprequest *arp; debug("%s: got arp\n", __func__); @@ -580,10 +580,9 @@ static int net_handle_icmp(unsigned char *pkt, int len) return 0; } -static int net_handle_ip(unsigned char *pkt, int len) +static int net_handle_ip(struct eth_device *edev, unsigned char *pkt, int len) { struct iphdr *ip = (struct iphdr *)(pkt + ETHER_HDR_SIZE); - struct eth_device *edev = eth_get_current(); IPaddr_t tmp; debug("%s\n", __func__); @@ -634,10 +633,10 @@ int net_receive(struct eth_device *edev, unsigned char *pkt, int len) switch (et_protlen) { case PROT_ARP: - ret = net_handle_arp(pkt, len); + ret = net_handle_arp(edev, pkt, len); break; case PROT_IP: - ret = net_handle_ip(pkt, len); + ret = net_handle_ip(edev, pkt, len); break; default: debug("%s: got unknown protocol type: %d\n", __func__, et_protlen); From 0ca1d8a456e6201d653e5bad5b0af826f77d7793 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:33:33 +0200 Subject: [PATCH 04/13] net: phy: Print ethernet device in the link information When multiple ethernet devices are in use it's interesting to know which one has link. Signed-off-by: Sascha Hauer --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 879939d4a..5975637ff 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -49,7 +49,7 @@ int phy_update_status(struct phy_device *dev) dev->adjust_link(edev); if (dev->link) - pr_info("%dMbps %s duplex link detected\n", dev->speed, + dev_info(&edev->dev, "%dMbps %s duplex link detected\n", dev->speed, dev->duplex ? "full" : "half"); return 0; From 0cf4630cd277e2a71340c47262cd66c930b0d541 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 May 2014 09:56:35 +0200 Subject: [PATCH 05/13] net: take eth id from devicetree alias If the devicetree has an alias for the ethernet device, then use it. Signed-off-by: Sascha Hauer --- net/eth.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/eth.c b/net/eth.c index 26a5ff747..b830f7924 100644 --- a/net/eth.c +++ b/net/eth.c @@ -330,12 +330,21 @@ int eth_register(struct eth_device *edev) } strcpy(edev->dev.name, "eth"); - edev->dev.id = DEVICE_ID_DYNAMIC; if (edev->parent) edev->dev.parent = edev->parent; - register_device(&edev->dev); + if (edev->dev.parent && edev->dev.parent->device_node) { + edev->dev.id = of_alias_get_id(edev->dev.parent->device_node, "ethernet"); + if (edev->dev.id < 0) + edev->dev.id = DEVICE_ID_DYNAMIC; + } else { + edev->dev.id = DEVICE_ID_DYNAMIC; + } + + ret = register_device(&edev->dev); + if (ret) + return ret; dev_add_param_ip(dev, "ipaddr", NULL, NULL, &edev->ipaddr, edev); dev_add_param_ip(dev, "serverip", NULL, NULL, &edev->serverip, edev); From 1655068ddddd9665068b6b45b8ae53da351dec77 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:24:28 +0200 Subject: [PATCH 06/13] net: cpsw: Pass correct slave Pass the current slave to cpsw_slave_init/cpsw_update_link, not the first one. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index a5cbacf09..d45afbf73 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -801,8 +801,8 @@ static int cpsw_open(struct eth_device *edev) ALE_SECURE); cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port); - cpsw_slave_init(&priv->slaves[0], priv); - cpsw_update_link(&priv->slaves[0], priv); + cpsw_slave_init(slave, priv); + cpsw_update_link(slave, priv); /* init descriptor pool */ for (i = 0; i < NUM_DESCS; i++) { From 6698b2dd51cf7c7ef76d70df43aa02891ddd5777 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 15 May 2014 09:45:52 +0200 Subject: [PATCH 07/13] net: cpsw: register slaves as devices This makes it possible to directly call dev_dbg and friends on the slave. Also the ethernet aliases in the devicetree now match the devices. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index d45afbf73..e8a8cdb24 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -183,6 +183,7 @@ struct cpsw_slave { phy_interface_t phy_if; struct eth_device edev; struct cpsw_priv *cpsw; + struct device_d dev; }; struct cpdma_desc { @@ -916,6 +917,15 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, { void *regs = priv->regs; struct eth_device *edev = &slave->edev; + struct device_d *dev = &slave->dev; + int ret; + + sprintf(dev->name, "cpsw-slave"); + dev->id = slave->slave_num; + dev->parent = priv->dev; + ret = register_device(dev); + if (ret) + return ret; dev_dbg(priv->dev, "* %s\n", __func__); @@ -932,7 +942,7 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, edev->recv = cpsw_recv; edev->get_ethaddr = cpsw_get_hwaddr; edev->set_ethaddr = cpsw_set_hwaddr; - edev->parent = priv->dev; + edev->parent = dev; return eth_register(edev); } @@ -1077,6 +1087,7 @@ static int cpsw_probe_dt(struct cpsw_priv *priv) if (ret) return ret; + slave->dev.device_node = child; slave->phy_id = phy_id[1]; slave->phy_if = of_get_phy_mode(child); slave->slave_num = i; From a1463175bdb109ad8ce64a27aa08bf2affaf5e8b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:41:58 +0200 Subject: [PATCH 08/13] net: cpsw: use slave device for dev_dbg Since the cpsw has two slaves which handle one network interface each the slave number is interesting during debugging. use the slave device for dev_dbg. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index e8a8cdb24..026c0bc09 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -541,9 +541,8 @@ static inline void soft_reset(struct cpsw_priv *priv, void *reg) static int cpsw_get_hwaddr(struct eth_device *edev, unsigned char *mac) { struct cpsw_slave *slave = edev->priv; - struct cpsw_priv *priv = slave->cpsw; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); return -1; } @@ -553,7 +552,7 @@ static int cpsw_set_hwaddr(struct eth_device *edev, unsigned char *mac) struct cpsw_slave *slave = edev->priv; struct cpsw_priv *priv = slave->cpsw; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); memcpy(&priv->mac_addr, mac, sizeof(priv->mac_addr)); @@ -569,7 +568,7 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, struct phy_device *phydev = slave->edev.phydev; u32 mac_control = 0; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); if (!phydev) return; @@ -595,11 +594,11 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, return; if (mac_control) { - dev_dbg(priv->dev, "link up on port %d, speed %d, %s duplex\n", - slave->slave_num, phydev->speed, + dev_dbg(&slave->dev, "link up, speed %d, %s duplex\n", + phydev->speed, (phydev->duplex == DUPLEX_FULL) ? "full" : "half"); } else { - dev_dbg(priv->dev, "link down on port %d\n", slave->slave_num); + dev_dbg(&slave->dev, "link down\n"); } writel(mac_control, &slave->sliver->mac_control); @@ -610,7 +609,7 @@ static int cpsw_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv) { int link = 0; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); cpsw_slave_update_link(slave, priv, &link); @@ -622,7 +621,7 @@ static void cpsw_adjust_link(struct eth_device *edev) struct cpsw_slave *slave = edev->priv; struct cpsw_priv *priv = slave->cpsw; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); cpsw_update_link(slave, priv); } @@ -639,7 +638,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) { u32 slave_port; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); soft_reset(priv, &slave->sliver->soft_reset); @@ -770,7 +769,7 @@ static int cpsw_open(struct eth_device *edev) struct cpsw_priv *priv = slave->cpsw; int i, ret; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); ret = phy_device_connect(edev, &priv->miibus, slave->phy_id, cpsw_adjust_link, 0, slave->phy_if); @@ -843,7 +842,7 @@ static int cpsw_open(struct eth_device *edev) ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i], PKTSIZE); if (ret < 0) { - dev_err(priv->dev, "error %d submitting rx desc\n", ret); + dev_err(&slave->dev, "error %d submitting rx desc\n", ret); break; } } @@ -856,6 +855,8 @@ static void cpsw_halt(struct eth_device *edev) struct cpsw_slave *slave = edev->priv; struct cpsw_priv *priv = slave->cpsw; + dev_dbg(priv->dev, "* %s slave %d\n", __func__, slave->slave_num); + writel(0, priv->dma_regs + CPDMA_TXCONTROL); writel(0, priv->dma_regs + CPDMA_RXCONTROL); @@ -873,12 +874,12 @@ static int cpsw_send(struct eth_device *edev, void *packet, int length) void *buffer; int ret, len; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s slave %d\n", __func__, slave->slave_num); /* first reap completed packets */ while (cpdma_process(priv, &priv->tx_chan, &buffer, &len) >= 0); - dev_dbg(priv->dev, "%s: %i bytes @ 0x%p\n", __func__, length, packet); + dev_dbg(&slave->dev, "%s: %i bytes @ 0x%p\n", __func__, length, packet); dma_flush_range((ulong) packet, (ulong)packet + length); @@ -927,7 +928,7 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, if (ret) return ret; - dev_dbg(priv->dev, "* %s\n", __func__); + dev_dbg(&slave->dev, "* %s\n", __func__); slave->slave_num = slave_num; slave->regs = regs + priv->slave_ofs + priv->slave_size * slave_num; From 6322a0305f0f87b3fcee5386d605925e5f10aefc Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:45:32 +0200 Subject: [PATCH 09/13] net: cpsw: Always write mac_control register Instead of keeping track of the mac_control register value and only writing to it when it changed just always write it. This is more safe anyway since the mac_control register content is altered in the soft_reset functions. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 026c0bc09..493092698 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -178,7 +178,6 @@ struct cpsw_slave { struct cpsw_slave_regs *regs; struct cpsw_sliver_regs *sliver; int slave_num; - u32 mac_control; int phy_id; phy_interface_t phy_if; struct eth_device edev; @@ -590,9 +589,6 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, mac_control |= BIT(0); /* FULLDUPLEXEN */ } - if (mac_control == slave->mac_control) - return; - if (mac_control) { dev_dbg(&slave->dev, "link up, speed %d, %s duplex\n", phydev->speed, @@ -602,7 +598,6 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, } writel(mac_control, &slave->sliver->mac_control); - slave->mac_control = mac_control; } static int cpsw_update_link(struct cpsw_slave *slave, struct cpsw_priv *priv) @@ -649,8 +644,6 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) /* setup max packet size, and mac address */ writel(PKT_MAX, &slave->sliver->rx_maxlen); - slave->mac_control = 0; /* no link yet */ - /* enable forwarding */ slave_port = cpsw_get_slave_port(priv, slave->slave_num); cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD); From 26576f8ef552c3be2dded065c546d3b38903ddbc Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 14 May 2014 16:48:26 +0200 Subject: [PATCH 10/13] net: cpsw: Allow multiple slaves The driver is ready now for handling both slaved, so add support for it. Signed-off-by: Sascha Hauer --- drivers/net/cpsw.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 493092698..ccae5376c 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -572,9 +572,6 @@ static void cpsw_slave_update_link(struct cpsw_slave *slave, if (!phydev) return; - if (slave->slave_num) - return; - if (phydev->link) { *link = 1; mac_control = BIT(5); /* MIIEN */ @@ -1096,9 +1093,6 @@ static int cpsw_probe_dt(struct cpsw_priv *priv) cpsw_gmii_sel_am335x(slave); } - /* Only one slave supported by this driver */ - priv->num_slaves = 1; - return 0; } @@ -1110,7 +1104,7 @@ int cpsw_probe(struct device_d *dev) uint64_t start; uint32_t phy_mask; struct cpsw_data *cpsw_data; - int ret; + int i, ret; dev_dbg(dev, "* %s\n", __func__); @@ -1202,9 +1196,11 @@ int cpsw_probe(struct device_d *dev) mdiobus_register(&priv->miibus); - ret = cpsw_slave_setup(&priv->slaves[0], 0, priv); - if (ret) - goto out; + for (i = 0; i < priv->num_slaves; i++) { + ret = cpsw_slave_setup(&priv->slaves[i], i, priv); + if (ret) + goto out; + } return 0; out: From b4ce62d3d23a2a910aefe803afc564c8b77ca205 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Wed, 14 May 2014 18:59:29 +0200 Subject: [PATCH 11/13] drivers/net/ethoc: add mdio bus support Signed-off-by: Franck Jullien Signed-off-by: Sascha Hauer --- drivers/net/Kconfig | 1 + drivers/net/ethoc.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 057abd2bc..7a0d5e107 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -80,6 +80,7 @@ config DRIVER_NET_EP93XX config DRIVER_NET_ETHOC bool "OpenCores ethernet MAC driver" + select PHYLIB help This option enables support for the OpenCores 10/100 Mbps Ethernet MAC core. diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index ced84df7a..679e1e552 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -178,6 +178,8 @@ struct ethoc { u32 num_rx; u32 cur_rx; + + struct mii_bus miibus; }; /** @@ -481,6 +483,54 @@ static int ethoc_send_packet(struct eth_device *edev, void *packet, int length) return 0; } +static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg) +{ + struct ethoc *priv = bus->priv; + u64 start; + u32 data; + + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg)); + ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ); + + start = get_time_ns(); + while (ethoc_read(priv, MIISTATUS) & MIISTATUS_BUSY) { + if (is_timeout(start, 2 * MSECOND)) { + dev_err(bus->parent, "PHY command timeout\n"); + return -EBUSY; + } + } + + data = ethoc_read(priv, MIIRX_DATA); + + /* reset MII command register */ + ethoc_write(priv, MIICOMMAND, 0); + + return data; +} + +static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val) +{ + struct ethoc *priv = bus->priv; + u64 start; + + ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg)); + ethoc_write(priv, MIITX_DATA, val); + ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE); + + start = get_time_ns(); + while (ethoc_read(priv, MIISTATUS) & MIISTATUS_BUSY) { + if (is_timeout(start, 2 * MSECOND)) { + dev_err(bus->parent, "PHY command timeout\n"); + return -EBUSY; + } + } + + /* reset MII command register */ + ethoc_write(priv, MIICOMMAND, 0); + + return 0; +} + static int ethoc_probe(struct device_d *dev) { struct eth_device *edev; @@ -493,6 +543,11 @@ static int ethoc_probe(struct device_d *dev) priv = edev->priv; priv->iobase = dev_request_mem_region(dev, 0); + priv->miibus.read = ethoc_mdio_read; + priv->miibus.write = ethoc_mdio_write; + priv->miibus.priv = priv; + priv->miibus.parent = dev; + edev->init = ethoc_init_dev; edev->open = ethoc_open; edev->send = ethoc_send_packet; @@ -503,6 +558,8 @@ static int ethoc_probe(struct device_d *dev) edev->set_ethaddr = ethoc_set_ethaddr; edev->parent = dev; + mdiobus_register(&priv->miibus); + eth_register(edev); return 0; From b158af4f08a8f1ad24df52baff34389296adc2a1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 19 May 2014 22:34:59 +0200 Subject: [PATCH 12/13] net: arc_emac: remove delay from mdio polling loop Avoid unneeded delay when waiting for the completion of a mdio operation and return as soon as possible. Signed-off-by: Beniamino Galvani Signed-off-by: Sascha Hauer --- drivers/net/arc_emac.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/net/arc_emac.c b/drivers/net/arc_emac.c index 3f6f81495..23df3fdbc 100644 --- a/drivers/net/arc_emac.c +++ b/drivers/net/arc_emac.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -342,26 +343,18 @@ static int arc_emac_set_ethaddr(struct eth_device *edev, unsigned char *mac) return 0; } -/* Number of seconds we wait for "MDIO complete" flag to appear */ -#define ARC_MDIO_COMPLETE_POLL_COUNT 1 - static int arc_mdio_complete_wait(struct arc_emac_priv *priv) { - unsigned int i; + uint64_t start = get_time_ns(); - for (i = 0; i < ARC_MDIO_COMPLETE_POLL_COUNT * 40; i++) { - unsigned int status = arc_reg_get(priv, R_STATUS); - - status &= MDIO_MASK; - - if (status) { + while (!is_timeout(start, 1000 * MSECOND)) { + if (arc_reg_get(priv, R_STATUS) & MDIO_MASK) { /* Reset "MDIO complete" flag */ - arc_reg_set(priv, R_STATUS, status); + arc_reg_set(priv, R_STATUS, MDIO_MASK); return 0; } - - mdelay(25); } + return -ETIMEDOUT; } From 15b0abce264be775aa63dc0de9c74d39529baf84 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 19 May 2014 22:35:00 +0200 Subject: [PATCH 13/13] net: arc_emac: disable interrupts The driver doesn't use interrupts and Linux driver crashes when emac interrupts are enabled at boot: keep them disabled. Signed-off-by: Beniamino Galvani Signed-off-by: Sascha Hauer --- drivers/net/arc_emac.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/arc_emac.c b/drivers/net/arc_emac.c index 23df3fdbc..8b74ea570 100644 --- a/drivers/net/arc_emac.c +++ b/drivers/net/arc_emac.c @@ -210,9 +210,6 @@ static int arc_emac_open(struct eth_device *edev) arc_reg_set(priv, R_RX_RING, (unsigned int)priv->rxbd); arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd); - /* Enable interrupts */ - arc_reg_set(priv, R_ENABLE, RXINT_MASK | ERR_MASK); - /* Set CONTROL */ arc_reg_set(priv, R_CTRL, (RX_BD_NUM << 24) | /* RX BD table length */ @@ -317,9 +314,6 @@ static void arc_emac_halt(struct eth_device *edev) { struct arc_emac_priv *priv = edev->priv; - /* Disable interrupts */ - arc_reg_clr(priv, R_ENABLE, RXINT_MASK | ERR_MASK); - /* Disable EMAC */ arc_reg_clr(priv, R_CTRL, EN_MASK); } @@ -440,6 +434,9 @@ static int arc_emac_probe(struct device_d *dev) /* Set poll rate so that it polls every 1 ms */ arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000); + /* Disable interrupts */ + arc_reg_set(priv, R_ENABLE, 0); + mdiobus_register(miibus); eth_register(edev);