/* Actual transmission over a single endpoint */ static void __wrn_tx_desc(struct wrn_ep *ep, int desc, void *data, int len, int id, int do_stamp) { struct wrn_dev *wrn = ep->wrn; int offset = __wrn_desc_offset(wrn, WRN_DDIR_TX, desc); u32 *ptr = __wrn_desc_mem(wrn, WRN_DDIR_TX, desc); struct wrn_txd __iomem *tx = wrn->txd + desc; /* data */ pr_debug("%s: %i -- data %p, len %i ", __func__, __LINE__, data, len); pr_debug("-- desc %i (tx %p)\n", desc, tx); __wrn_copy_out(ptr, data, len); /* TX register 3: mask of endpoints (FIXME: broadcast) */ //printk("EP Num: %d\n", ep->ep_number); writel(1<<ep->ep_number, &tx->tx3); /* TX register 2: offset and length */ writel(offset | (len << 16), &tx->tx2); /* TX register 1: id and masks -- and tx_enable if needed */ writel((len < 60 ? NIC_TX1_D1_PAD_E : 0) | NIC_TX1_D1_READY | (do_stamp ? NIC_TX1_D1_TS_E : 0) | (id << 16), &tx->tx1); }
static int wrn_probe(struct platform_device *pdev) { struct net_device *netdev; struct wrn_ep *ep; struct wrn_dev *wrn = wrn_from_pdev(pdev); int i, err = 0, irq; /* Lazily: irqs are not in the resource list */ static int irqs[] = WRN_IRQ_NUMBERS; static char *irq_names[] = WRN_IRQ_NAMES; static irq_handler_t irq_handlers[] = WRN_IRQ_HANDLERS; struct irq_domain *irqdomain; irqdomain = irq_find_host((struct device_node *)irqdomain_name); if (!irqdomain) { dev_err(&pdev->dev, "The IRQ domain %s does not exist\n", irqdomain_name); return -EINVAL; } /* No need to lock_irq: we only protect count and continue unlocked */ if (WR_IS_SWITCH) { spin_lock(&wrn->lock); if (++wrn->use_count != 1) { --wrn->use_count; spin_unlock(&wrn->lock); return -EBUSY; } spin_unlock(&wrn->lock); } /* Map our resource list and instantiate the shortcut pointers */ if ( (err = __wrn_map_resources(pdev)) ) goto out; wrn->regs = wrn->bases[WRN_FB_NIC]; wrn->txtsu_regs = wrn->bases[WRN_FB_TS]; wrn->ppsg_regs = wrn->bases[WRN_FB_PPSG]; wrn->txd = ((void *)wrn->regs) + 0x80; /* was: TX1_D1 */ wrn->rxd = ((void *)wrn->regs) + 0x100; /* was: RX1_D1 */ wrn->databuf = (void *)wrn->regs + NIC_MEM_BASE; tasklet_init(&wrn->rx_tlet, wrn_rx_interrupt, (unsigned long)wrn); if (0) printk("regs %p, txd %p, rxd %p, buffer %p\n", wrn->regs, wrn->txd, wrn->rxd, wrn->databuf); if (WR_IS_SWITCH) { /* Register the interrupt handlers (not shared) */ for (i = 0; i < ARRAY_SIZE(irq_names); i++) { irq = irq_find_mapping(irqdomain, irqs[i]); err = request_irq(irq, irq_handlers[i], IRQF_TRIGGER_LOW, irq_names[i], wrn); if (err) goto out; wrn->irq_registered |= 1 << i; } } /* Finally, register one interface per endpoint */ memset(wrn->dev, 0, sizeof(wrn->dev)); for (i = 0; i < WRN_NR_ENDPOINTS; i++) { netdev = alloc_etherdev(sizeof(struct wrn_ep)); netdev->dev.parent = &pdev->dev; if (!netdev) { dev_err(&pdev->dev, "Etherdev alloc failed.\n"); err = -ENOMEM; goto out; } /* The ep structure is filled before calling ep_probe */ ep = netdev_priv(netdev); ep->wrn = wrn; ep->ep_regs = wrn->bases[WRN_FB_EP] + i * FPGA_SIZE_EACH_EP; ep->ep_number = i; #if 0 /* FIXME: UPlink or not? */ if (i < WRN_NR_UPLINK) set_bit(WRN_EP_IS_UPLINK, &ep->ep_flags); #endif /* The netdevice thing is registered from the endpoint */ err = wrn_endpoint_probe(netdev); if (err == -ENODEV) break; if (err) goto out; /* This endpoint went in properly */ wrn->dev[i] = netdev; err = wrn_mezzanine_init(netdev); if (err) dev_err(&pdev->dev, "Init mezzanine code: " "error %i\n", err); } if (i == 0) return -ENODEV; /* no endpoints */ for (i = 0; i < WRN_NR_TXDESC; i++) { /* Clear all tx descriptors */ struct wrn_txd *tx; tx = wrn->txd + i; writel(0, &tx->tx1); } /* Now, prepare RX descriptors */ for (i = 0; i < WRN_NR_RXDESC; i++) { struct wrn_rxd *rx; int offset; rx = wrn->rxd + i; offset = __wrn_desc_offset(wrn, WRN_DDIR_RX, i); writel( (2000 << 16) | offset, &rx->rx3); writel(NIC_RX1_D1_EMPTY, &rx->rx1); } /* * make sure all head/tail are 0 -- not needed here, but if we * disable and then re-enable, this _is_ needed */ wrn->next_tx_head = wrn->next_tx_tail = wrn->next_rx = 0; writel(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR); writel(WRN_IRQ_ALL, (void *)wrn->regs + 0x24 /* EIC_IER */); wrn_tstamp_init(wrn); err = 0; out: if (err) { /* Call the remove function to avoid duplicating code */ wrn_remove(pdev); } else { dev_info(&pdev->dev, "White Rabbit NIC driver\n"); } return err; }