// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/net/ethernet/ibm/emac/mal.c * * Memory Access Layer (MAL) support * * Copyright 2007 Benjamin Herrenschmidt, IBM Corp. * <benh@kernel.crashing.org> * * Based on the arch/ppc version of the driver: * * Copyright (c) 2004, 2005 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * * Based on original work by * Benjamin Herrenschmidt <benh@kernel.crashing.org>, * David Gibson <hermes@gibson.dropbear.id.au>, * * Armin Kuster <akuster@mvista.com> * Copyright 2002 MontaVista Softare Inc.
*/
void mal_disable_tx_channel(struct mal_instance *mal, int channel)
{
set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel));
MAL_DBG(mal, "disable_tx(%d)" NL, channel);
}
void mal_enable_rx_channel(struct mal_instance *mal, int channel)
{ unsignedlong flags;
/* * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple * of 8, but enabling in MAL_RXCASR needs the divided by 8 value * for the bitmask
*/ if (!(channel % 8))
channel >>= 3;
void mal_disable_rx_channel(struct mal_instance *mal, int channel)
{ /* * On some 4xx PPC's (e.g. 460EX/GT), the rx channel is a multiple * of 8, but enabling in MAL_RXCASR needs the divided by 8 value * for the bitmask
*/ if (!(channel % 8))
channel >>= 3;
// XXX might want to cache MAL_CFG as the DCR read can be slooooow
set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE);
}
/* synchronized by NAPI state */ staticinlinevoid mal_disable_eob_irq(struct mal_instance *mal)
{ // XXX might want to cache MAL_CFG as the DCR read can be slooooow
set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE);
/* Clear the error status register */
set_mal_dcrn(mal, MAL_ESR, esr);
MAL_DBG(mal, "SERR %08x" NL, esr);
if (esr & MAL_ESR_EVB) { if (esr & MAL_ESR_DE) { /* We ignore Descriptor error, * TXDE or RXDE interrupt will be generated anyway.
*/ return IRQ_HANDLED;
}
if (esr & MAL_ESR_PEIN) { /* PLB error, it's probably buggy hardware or * incorrect physical address in BD (i.e. bug)
*/ if (net_ratelimit())
printk(KERN_ERR "mal%d: system error, " "PLB (ESR = 0x%08x)\n",
mal->index, esr); return IRQ_HANDLED;
}
/* OPB error, it's probably buggy hardware or incorrect * EBC setup
*/ if (net_ratelimit())
printk(KERN_ERR "mal%d: system error, OPB (ESR = 0x%08x)\n",
mal->index, esr);
} return IRQ_HANDLED;
}
void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
{ /* Spinlock-type semantics: only one caller disable poll at a time */ while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags))
msleep(1);
/* Synchronize with the MAL NAPI poller */
napi_synchronize(&mal->napi);
}
/* Feels better to trigger a poll here to catch up with events that * may have happened on this channel while disabled. It will most * probably be delayed until the next interrupt but that's mostly a * non-issue in the context where this is called.
*/
napi_schedule(&mal->napi);
}
staticint mal_poll(struct napi_struct *napi, int budget)
{ struct mal_instance *mal = container_of(napi, struct mal_instance, napi); struct list_head *l; int received = 0; unsignedlong flags;
/* Process RX skbs. * * We _might_ need something more smart here to enforce polling * 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 - received); if (n) {
received += n; if (received >= budget) return budget;
}
}
if (napi_complete_done(napi, received)) { /* We need to disable IRQs to protect from RXDE IRQ here */
spin_lock_irqsave(&mal->lock, flags);
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_schedule(napi)) goto more_work;
/* 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->dev.of_node, "ibm,mcmal-axon"))
cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.