コード例 #1
0
ファイル: device.c プロジェクト: leehongming/wr-switch-sw
/* This helper is used by probe below */
static int __wrn_map_resources(struct platform_device *pdev)
{
	int i;
	struct resource *res;
	void __iomem *ptr;
	struct wrn_dev *wrn = wrn_from_pdev(pdev);

	/*
	 * The memory regions are mapped once for all endpoints.
	 * We don't populate the whole array, but use the resource list
	 */
	for (i = 0; i < pdev->num_resources; i++) {
		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
		if (!res || !res->start)
			continue;
		ptr = ioremap(res->start, res->end + 1 - res->start);
		if (!ptr) {
			dev_err(&pdev->dev, "Remap for res %i %pr failed\n",
				i, res);
			return -ENOMEM;
		}
		/* Hack: find the block number and fill the array */
		pr_debug("Remapped %pr (block %i) to %p\n",
			 res, i, ptr);
		wrn->bases[i] = ptr;
	}
	return 0;
}
コード例 #2
0
ファイル: device.c プロジェクト: leehongming/wr-switch-sw
/* The remove function is used by probe, so it's not __devexit */
static int wrn_remove(struct platform_device *pdev)
{
	struct wrn_dev *wrn = wrn_from_pdev(pdev);
	int i, irq;
	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;
	}

	if (WR_IS_SWITCH) {
		spin_lock(&wrn->lock);
		--wrn->use_count; /* Hmmm... looks like overkill... */
		spin_unlock(&wrn->lock);
	}

	/* First of all, stop any transmission */
	writel(0, &wrn->regs->CR);

	/* Then remove devices, memory maps, interrupts */
	for (i = 0; i < WRN_NR_ENDPOINTS; i++) {
		if (wrn->dev[i]) {
			wrn_mezzanine_exit(wrn->dev[i]);
			wrn_endpoint_remove(wrn->dev[i]);
			free_netdev(wrn->dev[i]);
			wrn->dev[i] = NULL;
		}
	}

	for (i = 0; i < ARRAY_SIZE(wrn->bases); i++) {
		if (wrn->bases[i])
			iounmap(wrn->bases[i]);
	}

	/* Unregister all interrupts that were registered */
	for (i = 0; wrn->irq_registered; i++) {
		static int irqs[] = WRN_IRQ_NUMBERS;
		if (wrn->irq_registered & (1 << i)) {
			irq = irq_find_mapping(irqdomain, irqs[i]);
			free_irq(irq, wrn);
		}
		wrn->irq_registered &= ~(1 << i);
	}
	return 0;
}
コード例 #3
0
ファイル: device.c プロジェクト: Reedgarden/WRS-SW
/* The remove function is used by probe, so it's not __devexit */
static int wrn_remove(struct platform_device *pdev)
{
	struct wrn_dev *wrn = wrn_from_pdev(pdev);
	int i;

	if (WR_IS_SWITCH) {
		spin_lock(&wrn->lock);
		--wrn->use_count; /* Hmmm... looks like overkill... */
		spin_unlock(&wrn->lock);
	}

	/* First of all, stop any transmission */
	writel(0, &wrn->regs->CR);

	/* Then remove devices, memory maps, interrupts */
	for (i = 0; i < WRN_NR_ENDPOINTS; i++) {
		if (wrn->dev[i]) {
			wrn_mezzanine_exit(wrn->dev[i]);
			wrn_endpoint_remove(wrn->dev[i]);
			free_netdev(wrn->dev[i]);
			wrn->dev[i] = NULL;
		}
	}

	for (i = 0; i < ARRAY_SIZE(wrn->bases); i++) {
		if (wrn->bases[i])
			iounmap(wrn->bases[i]);
	}

	/* Unregister all interrupts that were registered */
	for (i = 0; wrn->irq_registered; i++) {
		static int irqs[] = WRN_IRQ_NUMBERS;
		if (wrn->irq_registered & (1 << i))
			free_irq(irqs[i], wrn);
		wrn->irq_registered &= ~(1 << i);
	}
	return 0;
}
コード例 #4
0
ファイル: device.c プロジェクト: leehongming/wr-switch-sw
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;
}