mal.c

来自「linux 内核源代码」· C语言 代码 · 共 727 行 · 第 1/2 页

C
727
字号
	 * fairness.	 */	list_for_each(l, &mal->poll_list) {		struct mal_commac *mc =			list_entry(l, struct mal_commac, poll_list);		int n;		if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))			continue;		n = mc->ops->poll_rx(mc->dev, budget);		if (n) {			received += n;			budget -= n;			if (budget <= 0)				goto more_work; // XXX What if this is the last one ?		}	}	/* We need to disable IRQs to protect from RXDE IRQ here */	spin_lock_irqsave(&mal->lock, flags);	__napi_complete(napi);	mal_enable_eob_irq(mal);	spin_unlock_irqrestore(&mal->lock, flags);	/* Check for "rotting" packet(s) */	list_for_each(l, &mal->poll_list) {		struct mal_commac *mc =			list_entry(l, struct mal_commac, poll_list);		if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))			continue;		if (unlikely(mc->ops->peek_rx(mc->dev) ||			     test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) {			MAL_DBG2(mal, "rotting packet" NL);			if (napi_reschedule(napi))				mal_disable_eob_irq(mal);			else				MAL_DBG2(mal, "already in poll list" NL);			if (budget > 0)				goto again;			else				goto more_work;		}		mc->ops->poll_tx(mc->dev);	} more_work:	MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received);	return received;}static void mal_reset(struct mal_instance *mal){	int n = 10;	MAL_DBG(mal, "reset" NL);	set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);	/* Wait for reset to complete (1 system clock) */	while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)		--n;	if (unlikely(!n))		printk(KERN_ERR "mal%d: reset timeout\n", mal->index);}int mal_get_regs_len(struct mal_instance *mal){	return sizeof(struct emac_ethtool_regs_subhdr) +	    sizeof(struct mal_regs);}void *mal_dump_regs(struct mal_instance *mal, void *buf){	struct emac_ethtool_regs_subhdr *hdr = buf;	struct mal_regs *regs = (struct mal_regs *)(hdr + 1);	int i;	hdr->version = mal->version;	hdr->index = mal->index;	regs->tx_count = mal->num_tx_chans;	regs->rx_count = mal->num_rx_chans;	regs->cfg = get_mal_dcrn(mal, MAL_CFG);	regs->esr = get_mal_dcrn(mal, MAL_ESR);	regs->ier = get_mal_dcrn(mal, MAL_IER);	regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR);	regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR);	regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR);	regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR);	regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR);	regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR);	regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR);	regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR);	for (i = 0; i < regs->tx_count; ++i)		regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i));	for (i = 0; i < regs->rx_count; ++i) {		regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i));		regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i));	}	return regs + 1;}static int __devinit mal_probe(struct of_device *ofdev,			       const struct of_device_id *match){	struct mal_instance *mal;	int err = 0, i, bd_size;	int index = mal_count++;	unsigned int dcr_base;	const u32 *prop;	u32 cfg;	mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);	if (!mal) {		printk(KERN_ERR		       "mal%d: out of memory allocating MAL structure!\n",		       index);		return -ENOMEM;	}	mal->index = index;	mal->ofdev = ofdev;	mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1;	MAL_DBG(mal, "probe" NL);	prop = of_get_property(ofdev->node, "num-tx-chans", NULL);	if (prop == NULL) {		printk(KERN_ERR		       "mal%d: can't find MAL num-tx-chans property!\n",		       index);		err = -ENODEV;		goto fail;	}	mal->num_tx_chans = prop[0];	prop = of_get_property(ofdev->node, "num-rx-chans", NULL);	if (prop == NULL) {		printk(KERN_ERR		       "mal%d: can't find MAL num-rx-chans property!\n",		       index);		err = -ENODEV;		goto fail;	}	mal->num_rx_chans = prop[0];	dcr_base = dcr_resource_start(ofdev->node, 0);	if (dcr_base == 0) {		printk(KERN_ERR		       "mal%d: can't find DCR resource!\n", index);		err = -ENODEV;		goto fail;	}	mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100);	if (!DCR_MAP_OK(mal->dcr_host)) {		printk(KERN_ERR		       "mal%d: failed to map DCRs !\n", index);		err = -ENODEV;		goto fail;	}	mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);	mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);	mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);	mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);	mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);	if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||	    mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||	    mal->rxde_irq == NO_IRQ) {		printk(KERN_ERR		       "mal%d: failed to map interrupts !\n", index);		err = -ENODEV;		goto fail_unmap;	}	INIT_LIST_HEAD(&mal->poll_list);	INIT_LIST_HEAD(&mal->list);	spin_lock_init(&mal->lock);	netif_napi_add(NULL, &mal->napi, mal_poll,		       CONFIG_IBM_NEW_EMAC_POLL_WEIGHT);	/* Load power-on reset defaults */	mal_reset(mal);	/* Set the MAL configuration register */	cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT;	cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA;	/* Current Axon is not happy with priority being non-0, it can	 * deadlock, fix it up here	 */	if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon"))		cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);	/* Apply configuration */	set_mal_dcrn(mal, MAL_CFG, cfg);	/* Allocate space for BD rings */	BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32);	BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32);	bd_size = sizeof(struct mal_descriptor) *		(NUM_TX_BUFF * mal->num_tx_chans +		 NUM_RX_BUFF * mal->num_rx_chans);	mal->bd_virt =		dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,				   GFP_KERNEL);	if (mal->bd_virt == NULL) {		printk(KERN_ERR		       "mal%d: out of memory allocating RX/TX descriptors!\n",		       index);		err = -ENOMEM;		goto fail_unmap;	}	memset(mal->bd_virt, 0, bd_size);	for (i = 0; i < mal->num_tx_chans; ++i)		set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +			     sizeof(struct mal_descriptor) *			     mal_tx_bd_offset(mal, i));	for (i = 0; i < mal->num_rx_chans; ++i)		set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma +			     sizeof(struct mal_descriptor) *			     mal_rx_bd_offset(mal, i));	err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);	if (err)		goto fail2;	err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);	if (err)		goto fail3;	err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);	if (err)		goto fail4;	err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);	if (err)		goto fail5;	err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);	if (err)		goto fail6;	/* Enable all MAL SERR interrupt sources */	if (mal->version == 2)		set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS);	else		set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS);	/* Enable EOB interrupt */	mal_enable_eob_irq(mal);	printk(KERN_INFO	       "MAL v%d %s, %d TX channels, %d RX channels\n",	       mal->version, ofdev->node->full_name,	       mal->num_tx_chans, mal->num_rx_chans);	/* Advertise this instance to the rest of the world */	wmb();	dev_set_drvdata(&ofdev->dev, mal);	mal_dbg_register(mal);	return 0; fail6:	free_irq(mal->rxde_irq, mal); fail5:	free_irq(mal->txeob_irq, mal); fail4:	free_irq(mal->txde_irq, mal); fail3:	free_irq(mal->serr_irq, mal); fail2:	dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); fail_unmap:	dcr_unmap(mal->dcr_host, 0x100); fail:	kfree(mal);	return err;}static int __devexit mal_remove(struct of_device *ofdev){	struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);	MAL_DBG(mal, "remove" NL);	/* Synchronize with scheduled polling */	napi_disable(&mal->napi);	if (!list_empty(&mal->list)) {		/* This is *very* bad */		printk(KERN_EMERG		       "mal%d: commac list is not empty on remove!\n",		       mal->index);		WARN_ON(1);	}	dev_set_drvdata(&ofdev->dev, NULL);	free_irq(mal->serr_irq, mal);	free_irq(mal->txde_irq, mal);	free_irq(mal->txeob_irq, mal);	free_irq(mal->rxde_irq, mal);	free_irq(mal->rxeob_irq, mal);	mal_reset(mal);	mal_dbg_unregister(mal);	dma_free_coherent(&ofdev->dev,			  sizeof(struct mal_descriptor) *			  (NUM_TX_BUFF * mal->num_tx_chans +			   NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt,			  mal->bd_dma);	kfree(mal);	return 0;}static struct of_device_id mal_platform_match[] ={	{		.compatible	= "ibm,mcmal",	},	{		.compatible	= "ibm,mcmal2",	},	/* Backward compat */	{		.type		= "mcmal-dma",		.compatible	= "ibm,mcmal",	},	{		.type		= "mcmal-dma",		.compatible	= "ibm,mcmal2",	},	{},};static struct of_platform_driver mal_of_driver = {	.name = "mcmal",	.match_table = mal_platform_match,	.probe = mal_probe,	.remove = mal_remove,};int __init mal_init(void){	return of_register_platform_driver(&mal_of_driver);}void mal_exit(void){	of_unregister_platform_driver(&mal_of_driver);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?