X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fnet%2Fpcnet.c;h=0928bc398b14187232e1a80b9bcd630c6fdaa6be;hb=5fdb3c0e7ee6bac6b8809ae69e52f16d22d45035;hp=669b2561789d879e2066ee9c29327af18ba2b7f3;hpb=1023a1e6a9b506c318ee9330d90d3acdf5593f89;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 669b256..0928bc3 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -8,7 +8,9 @@ #include #include +#include #include +#include #include #include #include @@ -82,10 +84,16 @@ struct pcnet_priv { /* Receive Buffer space */ unsigned char rx_buf[RX_RING_SIZE][PKT_BUF_SZ + 4]; struct pcnet_uncached_priv *uc; +#ifdef CONFIG_DM_ETH + struct udevice *dev; + const char *name; +#else pci_dev_t dev; - void __iomem *iobase; char *name; +#endif + void __iomem *iobase; u8 *enetaddr; + u16 status; int cur_rx; int cur_tx; }; @@ -135,7 +143,11 @@ static inline pci_addr_t pcnet_virt_to_mem(struct pcnet_priv *lp, void *addr) { void *virt_addr = addr; +#ifdef CONFIG_DM_ETH + return dm_pci_virt_to_mem(lp->dev, virt_addr); +#else return pci_virt_to_mem(lp->dev, virt_addr); +#endif } static struct pci_device_id supported[] = { @@ -143,9 +155,8 @@ static struct pci_device_id supported[] = { {} }; -static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr) +static int pcnet_probe_common(struct pcnet_priv *lp) { - struct pcnet_priv *lp = dev->priv; int chip_version; char *chipname; int i; @@ -199,9 +210,8 @@ static int pcnet_probe(struct eth_device *dev, bd_t *bis, int dev_nr) return 0; } -static int pcnet_init(struct eth_device *dev, bd_t *bis) +static int pcnet_init_common(struct pcnet_priv *lp) { - struct pcnet_priv *lp = dev->priv; struct pcnet_uncached_priv *uc; int i, val; unsigned long addr; @@ -319,9 +329,8 @@ static int pcnet_init(struct eth_device *dev, bd_t *bis) return 0; } -static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) +static int pcnet_send_common(struct pcnet_priv *lp, void *packet, int pkt_len) { - struct pcnet_priv *lp = dev->priv; int i, status; u32 addr; struct pcnet_tx_head *entry = &lp->uc->tx_ring[lp->cur_tx]; @@ -368,65 +377,70 @@ static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) return pkt_len; } -static int pcnet_recv (struct eth_device *dev) +static int pcnet_recv_common(struct pcnet_priv *lp, unsigned char **bufp) { - struct pcnet_priv *lp = dev->priv; struct pcnet_rx_head *entry; unsigned char *buf; int pkt_len = 0; - u16 status, err_status; - - while (1) { - entry = &lp->uc->rx_ring[lp->cur_rx]; - /* - * If we own the next entry, it's a new packet. Send it up. - */ - status = readw(&entry->status); - if ((status & 0x8000) != 0) - break; - err_status = status >> 8; - - if (err_status != 0x03) { /* There was an error. */ - printf("%s: Rx%d", lp->name, lp->cur_rx); - PCNET_DEBUG1(" (status=0x%x)", err_status); - if (err_status & 0x20) - printf(" Frame"); - if (err_status & 0x10) - printf(" Overflow"); - if (err_status & 0x08) - printf(" CRC"); - if (err_status & 0x04) - printf(" Fifo"); - printf(" Error\n"); - status &= 0x03ff; - - } else { - pkt_len = (readl(&entry->msg_length) & 0xfff) - 4; - if (pkt_len < 60) { - printf("%s: Rx%d: invalid packet length %d\n", - lp->name, lp->cur_rx, pkt_len); - } else { - buf = lp->rx_buf[lp->cur_rx]; - invalidate_dcache_range((unsigned long)buf, - (unsigned long)buf + pkt_len); - net_process_received_packet(buf, pkt_len); - PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", - lp->cur_rx, pkt_len, buf); - } - } + u16 err_status; - status |= 0x8000; - writew(status, &entry->status); + entry = &lp->uc->rx_ring[lp->cur_rx]; + /* + * If we own the next entry, it's a new packet. Send it up. + */ + lp->status = readw(&entry->status); + if ((lp->status & 0x8000) != 0) + return 0; + err_status = lp->status >> 8; + + if (err_status != 0x03) { /* There was an error. */ + printf("%s: Rx%d", lp->name, lp->cur_rx); + PCNET_DEBUG1(" (status=0x%x)", err_status); + if (err_status & 0x20) + printf(" Frame"); + if (err_status & 0x10) + printf(" Overflow"); + if (err_status & 0x08) + printf(" CRC"); + if (err_status & 0x04) + printf(" Fifo"); + printf(" Error\n"); + lp->status &= 0x03ff; + return 0; + } - if (++lp->cur_rx >= RX_RING_SIZE) - lp->cur_rx = 0; + pkt_len = (readl(&entry->msg_length) & 0xfff) - 4; + if (pkt_len < 60) { + printf("%s: Rx%d: invalid packet length %d\n", + lp->name, lp->cur_rx, pkt_len); + return 0; } + + *bufp = lp->rx_buf[lp->cur_rx]; + invalidate_dcache_range((unsigned long)*bufp, + (unsigned long)*bufp + pkt_len); + + PCNET_DEBUG2("Rx%d: %d bytes from 0x%p\n", + lp->cur_rx, pkt_len, buf); + return pkt_len; } -static void pcnet_halt(struct eth_device *dev) +static void pcnet_free_pkt_common(struct pcnet_priv *lp, unsigned int len) +{ + struct pcnet_rx_head *entry; + + entry = &lp->uc->rx_ring[lp->cur_rx]; + + lp->status |= 0x8000; + writew(lp->status, &entry->status); + + if (++lp->cur_rx >= RX_RING_SIZE) + lp->cur_rx = 0; +} + +static void pcnet_halt_common(struct pcnet_priv *lp) { - struct pcnet_priv *lp = dev->priv; int i; PCNET_DEBUG1("%s: %s...\n", lp->name, __func__); @@ -444,6 +458,43 @@ static void pcnet_halt(struct eth_device *dev) printf("%s: TIMEOUT: controller reset failed\n", lp->name); } +#ifndef CONFIG_DM_ETH +static int pcnet_init(struct eth_device *dev, bd_t *bis) +{ + struct pcnet_priv *lp = dev->priv; + + return pcnet_init_common(lp); +} + +static int pcnet_send(struct eth_device *dev, void *packet, int pkt_len) +{ + struct pcnet_priv *lp = dev->priv; + + return pcnet_send_common(lp, packet, pkt_len); +} + +static int pcnet_recv(struct eth_device *dev) +{ + struct pcnet_priv *lp = dev->priv; + uchar *packet; + int ret; + + ret = pcnet_recv_common(lp, &packet); + if (ret > 0) + net_process_received_packet(packet, ret); + if (ret) + pcnet_free_pkt_common(lp, ret); + + return ret; +} + +static void pcnet_halt(struct eth_device *dev) +{ + struct pcnet_priv *lp = dev->priv; + + pcnet_halt_common(lp); +} + int pcnet_initialize(bd_t *bis) { pci_dev_t devbusfn; @@ -512,7 +563,7 @@ int pcnet_initialize(bd_t *bis) /* * Probe the PCnet chip. */ - if (pcnet_probe(dev, bis, dev_nr) < 0) { + if (pcnet_probe_common(lp) < 0) { free(dev); continue; } @@ -532,3 +583,117 @@ int pcnet_initialize(bd_t *bis) return dev_nr; } +#else /* DM_ETH */ +static int pcnet_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct pcnet_priv *priv = dev_get_priv(dev); + + memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr)); + + return pcnet_init_common(priv); +} + +static void pcnet_stop(struct udevice *dev) +{ + struct pcnet_priv *priv = dev_get_priv(dev); + + pcnet_halt_common(priv); +} + +static int pcnet_send(struct udevice *dev, void *packet, int length) +{ + struct pcnet_priv *priv = dev_get_priv(dev); + int ret; + + ret = pcnet_send_common(priv, packet, length); + + return ret ? 0 : -ETIMEDOUT; +} + +static int pcnet_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct pcnet_priv *priv = dev_get_priv(dev); + + return pcnet_recv_common(priv, packetp); +} + +static int pcnet_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct pcnet_priv *priv = dev_get_priv(dev); + + pcnet_free_pkt_common(priv, length); + + return 0; +} + +static int pcnet_bind(struct udevice *dev) +{ + static int card_number; + char name[16]; + + sprintf(name, "pcnet#%u", card_number++); + + return device_set_name(dev, name); +} + +static int pcnet_probe(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct pcnet_priv *lp = dev_get_priv(dev); + u16 command, status; + u32 iobase; + int ret; + + dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase); + iobase &= ~0xf; + + lp->uc = map_physmem((phys_addr_t)&lp->ucp, + sizeof(lp->ucp), MAP_NOCACHE); + lp->dev = dev; + lp->name = dev->name; + lp->enetaddr = plat->enetaddr; + lp->iobase = (void *)dm_pci_mem_to_phys(dev, iobase); + + flush_dcache_range((unsigned long)lp, + (unsigned long)lp + sizeof(*lp)); + + command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + dm_pci_write_config16(dev, PCI_COMMAND, command); + dm_pci_read_config16(dev, PCI_COMMAND, &status); + if ((status & command) != command) { + printf("%s: Couldn't enable IO access or Bus Mastering\n", + lp->name); + return -EINVAL; + } + + dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x20); + + ret = pcnet_probe_common(lp); + if (ret) + return ret; + + return 0; +} + +static const struct eth_ops pcnet_ops = { + .start = pcnet_start, + .send = pcnet_send, + .recv = pcnet_recv, + .stop = pcnet_stop, + .free_pkt = pcnet_free_pkt, +}; + +U_BOOT_DRIVER(eth_pcnet) = { + .name = "eth_pcnet", + .id = UCLASS_ETH, + .bind = pcnet_bind, + .probe = pcnet_probe, + .ops = &pcnet_ops, + .priv_auto_alloc_size = sizeof(struct pcnet_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_UC_FLAG_ALLOC_PRIV_DMA, +}; + +U_BOOT_PCI_DEVICE(eth_pcnet, supported); +#endif