/* A few values that may be tweaked. */ /* Keep the ring sizes a power of two for efficiency. */ #define TX_RING_SIZE 16 #define RX_RING_SIZE 32 #define PKT_BUF_SZ 1536/* Size of each temporary Rx buffer.*/
/* "Knobs" that adjust features and parameters. */ /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */ #ifndef __arm__ staticint rx_copybreak = 200; #else /* ARM systems perform better by disregarding the bus-master
transfer capability of these cards. -- rmk */ staticint rx_copybreak = 1513; #endif /* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */ staticconstint mtu = 1500; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ staticint max_interrupt_work = 32; /* Tx timeout interval (millisecs) */ staticint watchdog = 5000;
/* Allow aggregation of Tx interrupts. Saves CPU load at the cost *ofpossibleTxstallsifthesystemisblockinginterrupts *somewhereelse.Undefinethistodisable.
*/ #define tx_interrupt_mitigation 1
/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */ #define vortex_debug debug #ifdef VORTEX_DEBUG staticint vortex_debug = VORTEX_DEBUG; #else staticint vortex_debug = 1; #endif
/* Operational parameter that usually are not changed. */
/* The Vortex size is twice that of the original EtherLinkIII series: the runtimeregisterwindow,window1,isnowalwaysmappedin. TheBoomerangsizeistwiceaslargeastheVortex--ithasadditional
bus master control registers. */ #define VORTEX_TOTAL_SIZE 0x20 #define BOOMERANG_TOTAL_SIZE 0x40
/* Set iff a MII transceiver on any interface requires mdio preamble. ThisonlysetwiththeoriginalDP83840onolder3c905boards,sotheextra
code size of a per-interface flag is not worthwhile. */ staticchar mii_preamble_required;
/* This table drives the PCI probe routines. It's mostly boilerplate in all ofthedrivers,andwilllikelybeprovidedbysomefuturekernel.
*/ enum pci_flags_bit {
PCI_USES_MASTER=4,
};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000,
EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, };
/* The top five bits written to EL3_CMD are a command, the lower 11bitsaretheparameter,ifapplicable. Notethat11parametersbitswasfineforethernet,butthenewchip canhandleFDDIlengthframes(~4500octets)andnowparameterscount
32-bit 'Dwords' rather than octets. */
/* The Rx and Tx descriptor lists. CautionAlphahackers:thesetypesare32bits!Notealsothe8byte
alignment contraint on tx_ring[] and rx_ring[]. */ #define LAST_FRAG 0x80000000 /* Last Addr/Len pair in descriptor. */ #define DN_COMPLETE 0x00010000 /* This packet has been downloaded */ struct boom_rx_desc {
__le32 next; /* Last entry points to 0. */
__le32 status;
__le32 addr; /* Up to 63 addr/len pairs possible. */
__le32 length; /* Set LAST_FRAG to indicate last pair. */
}; /* Values for the Rx status entry. */ enum rx_desc_status {
RxDComplete=0x00008000, RxDError=0x4000, /* See boomerang_rx() for actual error bits */
IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
};
/* Values for the Tx status entry. */ enum tx_desc_status {
CRCDisable=0x2000, TxDComplete=0x8000,
AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
TxIntrUploaded=0x80000000, /* IRQ when in FIFO, but maybe not sent. */
};
/* Chip features we care about in vp->capabilities, read from the EEPROM. */ enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
struct vortex_private { /* The Rx and Tx rings should be quad-word-aligned. */ struct boom_rx_desc* rx_ring; struct boom_tx_desc* tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma; /* The addresses of transmit- and receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; struct sk_buff* tx_skbuff[TX_RING_SIZE]; unsignedint cur_rx, cur_tx; /* The next free ring entry */ unsignedint dirty_tx; /* The ring entries to be free()ed. */ struct vortex_extra_stats xstats; /* NIC-specific extra stats */ struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
dma_addr_t tx_skb_dma; /* Allocated DMA address for bus master ctrl DMA. */
/* PCI configuration space information. */ struct device *gendev; void __iomem *ioaddr; /* IO address space */ void __iomem *cb_fn_base; /* CardBus function status addr space. */
/* Some values here only for performance evaluation and path-coverage */ int rx_nocopy, rx_copy, queued_packet, rx_csumhits; int card_idx;
/* The remainder are related to chip state, mostly media selection. */ struct timer_list timer; /* Media selection timer. */ int options; /* User-settable misc. driver options. */ unsignedint media_override:4, /* Passed-in media type. */
default_media:4, /* Read from the EEPROM/Wn3_Config. */
full_duplex:1, autoselect:1,
bus_master:1, /* Vortex can only do a fragment bus-m. */
full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */
flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */
partner_flow_ctrl:1, /* Partner supports flow control */
has_nway:1,
enable_wol:1, /* Wake-on-LAN is enabled */
pm_state_valid:1, /* pci_dev->saved_config_space has sane contents */
open:1,
medialock:1,
large_frames:1, /* accept large frames */
handling_irq:1; /* private in_irq indicator */ /* {get|set}_wol operations are already serialized by rtnl. *noadditionallockingisrequiredfortheenable_wolandacpi_set_WOL()
*/ int drv_flags;
u16 status_enable;
u16 intr_enable;
u16 available_media; /* From Wn3_Options. */
u16 capabilities, info1, info2; /* Various, from EEPROM. */
u16 advertising; /* NWay media advertisement */ unsignedchar phys[2]; /* MII device addresses. */
u16 deferred; /* Resend these interrupts when we
* bale from the ISR */
u16 io_size; /* Size of PCI region (for release_region) */
/* Serialises access to hardware other than MII and variables below.
* The lock hierarchy is rtnl_lock > {lock, mii_lock} > window_lock. */
spinlock_t lock;
spinlock_t mii_lock; /* Serialises access to MII */ struct mii_if_info mii; /* MII lib hooks/info */
spinlock_t window_lock; /* Serialises access to windowed regs */ int window; /* Register window */
};
/* The action to take with a media selection timer tick. Notethatwedeviatefromthe3Comorderbychecking10base2beforeAUI.
*/ enum xcvr_types {
XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
};
staticconststruct media_table { char *name; unsignedint media_bits:16, /* Bits to set in Wn4_Media register. */
mask:8, /* The transceiver-present bit in Wn3_Config.*/
next:8; /* The media type to try next. */ int wait; /* Time before we check media status. */
} media_tbl[] = {
{ "10baseT", Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
{ "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
{ "undefined", 0, 0x80, XCVR_10baseT, 10000},
{ "10base2", 0, 0x10, XCVR_AUI, (1*HZ)/10},
{ "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
{ "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14*HZ)/10},
{ "MII", 0, 0x41, XCVR_10baseT, 3*HZ },
{ "undefined", 0, 0x01, XCVR_10baseT, 10000},
{ "Autonegotiate", 0, 0x41, XCVR_10baseT, 3*HZ},
{ "MII-External", 0, 0x41, XCVR_10baseT, 3*HZ },
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
/* Variables to work-around the Compaq PCI BIOS32 problem. */ staticint compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900; staticstruct net_device *compaq_net_device;
staticint vortex_cards_found;
module_param(debug, int, 0);
module_param(global_options, int, 0);
module_param_array(options, int, NULL, 0);
module_param(global_full_duplex, int, 0);
module_param_array(full_duplex, int, NULL, 0);
module_param_array(hw_checksums, int, NULL, 0);
module_param_array(flow_ctrl, int, NULL, 0);
module_param(global_enable_wol, int, 0);
module_param_array(enable_wol, int, NULL, 0);
module_param(rx_copybreak, int, 0);
module_param(max_interrupt_work, int, 0);
module_param_hw(compaq_ioaddr, int, ioport, 0);
module_param_hw(compaq_irq, int, irq, 0);
module_param(compaq_device_id, int, 0);
module_param(watchdog, int, 0);
module_param(global_use_mmio, int, 0);
module_param_array(use_mmio, int, NULL, 0);
MODULE_PARM_DESC(debug, "3c59x debug level (0-6)");
MODULE_PARM_DESC(options, "3c59x: Bits 0-3: media type, bit 4: bus mastering, bit 9: full duplex");
MODULE_PARM_DESC(global_options, "3c59x: same as options, but applies to all NICs if options is unset");
MODULE_PARM_DESC(full_duplex, "3c59x full duplex setting(s) (1)");
MODULE_PARM_DESC(global_full_duplex, "3c59x: same as full_duplex, but applies to all NICs if full_duplex is unset");
MODULE_PARM_DESC(hw_checksums, "3c59x Hardware checksum checking by adapter(s) (0-1)");
MODULE_PARM_DESC(flow_ctrl, "3c59x 802.3x flow control usage (PAUSE only) (0-1)");
MODULE_PARM_DESC(enable_wol, "3c59x: Turn on Wake-on-LAN for adapter(s) (0-1)");
MODULE_PARM_DESC(global_enable_wol, "3c59x: same as enable_wol, but applies to all NICs if enable_wol is unset");
MODULE_PARM_DESC(rx_copybreak, "3c59x copy breakpoint for copy-only-tiny-frames");
MODULE_PARM_DESC(max_interrupt_work, "3c59x maximum events handled per interrupt");
MODULE_PARM_DESC(compaq_ioaddr, "3c59x PCI I/O base address (Compaq BIOS problem workaround)");
MODULE_PARM_DESC(compaq_irq, "3c59x PCI IRQ number (Compaq BIOS problem workaround)");
MODULE_PARM_DESC(compaq_device_id, "3c59x PCI device ID (Compaq BIOS problem workaround)");
MODULE_PARM_DESC(watchdog, "3c59x transmit timeout in milliseconds");
MODULE_PARM_DESC(global_use_mmio, "3c59x: same as use_mmio, but applies to all NICs if options is unset");
MODULE_PARM_DESC(use_mmio, "3c59x: use memory-mapped PCI I/O resource (0-1)");
/* returns count found (>= 0), or negative on error */ staticint __init vortex_eisa_init(void)
{ int eisa_found = 0; int orig_cards_found = vortex_cards_found;
/* The lower four bits are the media type. */ if (dev->mem_start) { /* *The'options'paramispassedinasthethirdargtothe *LILO'ether='argumentfornon-modularuse
*/
option = dev->mem_start;
} elseif (card_idx < MAX_UNITS) { if (options[card_idx] >= 0)
option = options[card_idx];
}
if (option > 0) { if (option & 0x8000)
vortex_debug = 7; if (option & 0x4000)
vortex_debug = 2; if (option & 0x0400)
vp->enable_wol = 1;
}
print_info = (vortex_debug > 1); if (print_info)
pr_info("See Documentation/networking/device_drivers/ethernet/3com/vortex.rst\n");
/* Check the PCI latency value. On the 3c590 series the latency timer mustbesettothemaximumvaluetoavoiddatacorruptionthatoccurs whenthetimerexpiresduringatransfer.ThisbugexiststheVortex
chip only. */
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < new_latency) {
pr_info("%s: Overriding PCI latency timer (CFLT) setting of %d, new value is %d.\n",
print_name, pci_latency, new_latency);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, new_latency);
}
}
}
/* if we are a PCI driver, we store info in pdev->driver_data
* instead of a module list */ if (pdev)
pci_set_drvdata(pdev, dev); if (edev)
eisa_set_drvdata(edev, dev);
if (global_full_duplex > 0)
vp->full_duplex = 1; if (global_enable_wol > 0)
vp->enable_wol = 1;
if (card_idx < MAX_UNITS) { if (full_duplex[card_idx] > 0)
vp->full_duplex = 1; if (flow_ctrl[card_idx] > 0)
vp->flow_ctrl = 1; if (enable_wol[card_idx] > 0)
vp->enable_wol = 1;
}
vp->mii.force_media = vp->full_duplex;
vp->options = option; /* Read the station address from the EEPROM. */
{ int base;
if (vci->drv_flags & EEPROM_8BIT)
base = 0x230; elseif (vci->drv_flags & EEPROM_OFFSET)
base = EEPROM_Read + 0x30; else
base = EEPROM_Read;
for (i = 0; i < 0x40; i++) { int timer;
window_write16(vp, base + i, 0, Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ for (timer = 10; timer >= 0; timer--) {
udelay(162); if ((window_read16(vp, 0, Wn0EepromCmd) & 0x8000) == 0) break;
}
eeprom[i] = window_read16(vp, 0, Wn0EepromData);
}
} for (i = 0; i < 0x18; i++)
checksum ^= eeprom[i];
checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) { /* Grrr, needless incompatible change 3Com. */ while (i < 0x21)
checksum ^= eeprom[i++];
checksum = (checksum ^ (checksum >> 8)) & 0xff;
} if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
pr_cont(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 3; i++)
addr[i] = htons(eeprom[i + 10]);
eth_hw_addr_set(dev, (u8 *)addr); if (print_info)
pr_cont(" %pM", dev->dev_addr); /* Unfortunately an all zero eeprom passes the checksum and this
gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) {
retval = -EINVAL;
pr_err("*** EEPROM MAC address is invalid.\n"); goto free_ring; /* With every pack */
} for (i = 0; i < 6; i++)
window_write8(vp, dev->dev_addr[i], 2, i);
if (print_info)
pr_cont(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (dev->irq <= 0 || dev->irq >= irq_get_nr_irqs())
pr_warn(" *** Warning: IRQ %d is unlikely to work! ***\n",
dev->irq);
staticvoid
issue_and_wait(struct net_device *dev, int cmd)
{ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; int i;
iowrite16(cmd, ioaddr + EL3_CMD); for (i = 0; i < 2000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) return;
}
/* OK, that didn't work. Do it the slow way. One second */ for (i = 0; i < 100000; i++) { if (!(ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) { if (vortex_debug > 1)
pr_info("%s: command 0x%04x took %d usecs\n",
dev->name, cmd, i * 10); return;
}
udelay(10);
}
pr_err("%s: command 0x%04x did not complete! Status=0x%x\n",
dev->name, cmd, ioread16(ioaddr + EL3_STATUS));
}
if (VORTEX_PCI(vp)) {
pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ if (vp->pm_state_valid)
pci_restore_state(VORTEX_PCI(vp));
err = pci_enable_device(VORTEX_PCI(vp)); if (err) {
pr_warn("%s: Could not enable device\n", dev->name); goto err_out;
}
}
/* Before initializing select the active media port. */
config = window_read32(vp, 3, Wn3_Config);
if (vp->media_override != 7) {
pr_info("%s: Media override to transceiver %d (%s).\n",
dev->name, vp->media_override,
media_tbl[vp->media_override].name);
dev->if_port = vp->media_override;
} elseif (vp->autoselect) { if (vp->has_nway) { if (vortex_debug > 1)
pr_info("%s: using NWAY device table, not %d\n",
dev->name, dev->if_port);
dev->if_port = XCVR_NWAY;
} else { /* Find first available media type, starting with 100baseTx. */
dev->if_port = XCVR_100baseTx; while (! (vp->available_media & media_tbl[dev->if_port].mask))
dev->if_port = media_tbl[dev->if_port].next; if (vortex_debug > 1)
pr_info("%s: first available media type: %s\n",
dev->name, media_tbl[dev->if_port].name);
}
} else {
dev->if_port = vp->default_media; if (vortex_debug > 1)
pr_info("%s: using default media %s\n",
dev->name, media_tbl[dev->if_port].name);
}
if (vortex_debug > 1) {
pr_debug("%s: vortex_up() irq %d media status %4.4x.\n",
dev->name, dev->irq, window_read16(vp, 4, Wn4_Media));
}
/* Set the station address and mask in window 2 each time opened. */ for (i = 0; i < 6; i++)
window_write8(vp, dev->dev_addr[i], 2, i); for (; i < 12; i+=2)
window_write16(vp, 0, 2, i);
if (vp->cb_fn_base) { unsignedshort n = window_read16(vp, 2, Wn2_ResetOptions) & ~0x4010; if (vp->drv_flags & INVERT_LED_PWR)
n |= 0x10; if (vp->drv_flags & INVERT_MII_PWR)
n |= 0x4000;
window_write16(vp, n, 2, Wn2_ResetOptions);
}
if (dev->if_port == XCVR_10base2) /* Start the thinnet transceiver. We should really wait 50ms...*/
iowrite16(StartCoax, ioaddr + EL3_CMD); if (dev->if_port != XCVR_NWAY) {
window_write16(vp,
(window_read16(vp, 4, Wn4_Media) &
~(Media_10TP|Media_SQE)) |
media_tbl[dev->if_port].media_bits, 4, Wn4_Media);
}
/* Switch to the stats window, and clear all stats by reading. */
iowrite16(StatsDisable, ioaddr + EL3_CMD); for (i = 0; i < 10; i++)
window_read8(vp, 6, i);
window_read16(vp, 6, 10);
window_read16(vp, 6, 12); /* New: On the Vortex we must also clear the BadSSD counter. */
window_read8(vp, 4, 12); /* ..and on the Boomerang we enable the extra statistics bits. */
window_write16(vp, 0x0040, 4, Wn4_NetDiag);
if (vp->full_bus_master_rx) { /* Boomerang bus master. */
vp->cur_rx = 0; /* Initialize the RxEarly register as recommended. */
iowrite16(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
iowrite32(0x0020, ioaddr + PktStatus);
iowrite32(vp->rx_ring_dma, ioaddr + UpListPtr);
} if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */
vp->cur_tx = vp->dirty_tx = 0; if (vp->drv_flags & IS_BOOMERANG)
iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Rx, Tx rings. */ for (i = 0; i < RX_RING_SIZE; i++) /* AKPM: this is done in vortex_open, too */
vp->rx_ring[i].status = 0; for (i = 0; i < TX_RING_SIZE; i++)
vp->tx_skbuff[i] = NULL;
iowrite32(0, ioaddr + DownListPtr);
} /* Set receiver mode: presumably accept b-case and phys addr only. */
set_rx_mode(dev); /* enable 802.1q tagged frames */
set_8021q_mode(dev, 1);
iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
staticint
vortex_open(struct net_device *dev)
{ struct vortex_private *vp = netdev_priv(dev); int i; int retval;
dma_addr_t dma;
/* Use the now-standard shared IRQ implementation. */ if ((retval = request_irq(dev->irq, vortex_boomerang_interrupt, IRQF_SHARED, dev->name, dev))) {
pr_err("%s: Could not reserve IRQ %d\n", dev->name, dev->irq); goto err;
}
if (vp->full_bus_master_rx) { /* Boomerang bus master. */ if (vortex_debug > 2)
pr_debug("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb;
vp->rx_ring[i].next = cpu_to_le32(vp->rx_ring_dma + sizeof(struct boom_rx_desc) * (i+1));
vp->rx_ring[i].status = 0; /* Clear complete bit. */
vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
skb = __netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN,
GFP_KERNEL);
vp->rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */
skb_reserve(skb, NET_IP_ALIGN); /* Align IP on 16 byte boundaries */
dma = dma_map_single(vp->gendev, skb->data,
PKT_BUF_SZ, DMA_FROM_DEVICE); if (dma_mapping_error(vp->gendev, dma)) break;
vp->rx_ring[i].addr = cpu_to_le32(dma);
} if (i != RX_RING_SIZE) {
pr_emerg("%s: no memory for rx ring\n", dev->name);
retval = -ENOMEM; goto err_free_skb;
} /* Wrap the ring. */
vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
}
retval = vortex_up(dev); if (!retval) goto out;
err_free_skb: for (i = 0; i < RX_RING_SIZE; i++) { if (vp->rx_skbuff[i]) {
dev_kfree_skb(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = NULL;
}
}
free_irq(dev->irq, dev);
err: if (vortex_debug > 1)
pr_err("%s: vortex_open() fails: returning %d\n", dev->name, retval);
out: return retval;
}
staticvoid
vortex_timer(struct timer_list *t)
{ struct vortex_private *vp = timer_container_of(vp, t, timer); struct net_device *dev = vp->mii.dev; void __iomem *ioaddr = vp->ioaddr; int next_tick = 60*HZ; int ok = 0; int media_status;
if (vortex_debug > 2) {
pr_debug("%s: Media selection timer tick happened, %s.\n",
dev->name, media_tbl[dev->if_port].name);
pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
}
media_status = window_read16(vp, 4, Wn4_Media); switch (dev->if_port) { case XCVR_10baseT: case XCVR_100baseTx: case XCVR_100baseFx: if (media_status & Media_LnkBeat) {
netif_carrier_on(dev);
ok = 1; if (vortex_debug > 1)
pr_debug("%s: Media %s has link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
} else {
netif_carrier_off(dev); if (vortex_debug > 1) {
pr_debug("%s: Media %s has no link beat, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
}
} break; case XCVR_MII: case XCVR_NWAY:
{
ok = 1;
vortex_check_media(dev, 0);
} break; default: /* Other media types handled by Tx timeouts. */ if (vortex_debug > 1)
pr_debug("%s: Media %s has no indication, %x.\n",
dev->name, media_tbl[dev->if_port].name, media_status);
ok = 1;
}
if (dev->flags & IFF_SLAVE || !netif_carrier_ok(dev))
next_tick = 5*HZ;
if (vp->medialock) goto leave_media_alone;
if (!ok) { unsignedint config;
spin_lock_irq(&vp->lock);
do {
dev->if_port = media_tbl[dev->if_port].next;
} while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); if (dev->if_port == XCVR_Default) { /* Go back to default. */
dev->if_port = vp->default_media; if (vortex_debug > 1)
pr_debug("%s: Media selection failing, using default %s port.\n",
dev->name, media_tbl[dev->if_port].name);
} else { if (vortex_debug > 1)
pr_debug("%s: Media selection failed, now trying %s port.\n",
dev->name, media_tbl[dev->if_port].name);
next_tick = media_tbl[dev->if_port].wait;
}
window_write16(vp,
(media_status & ~(Media_10TP|Media_SQE)) |
media_tbl[dev->if_port].media_bits, 4, Wn4_Media);
if (status & TxComplete) { /* Really "TxError" for us. */
tx_status = ioread8(ioaddr + TxStatus); /* Presumably a tx-timeout. We must merely re-enable. */ if (vortex_debug > 2 ||
(tx_status != 0x88 && vortex_debug > 0)) {
pr_err("%s: Transmit error, Tx status register %2.2x.\n",
dev->name, tx_status); if (tx_status == 0x82) {
pr_err("Probably a duplex mismatch. See " "Documentation/networking/device_drivers/ethernet/3com/vortex.rst\n");
}
dump_tx_ring(dev);
} if (tx_status & 0x14) dev->stats.tx_fifo_errors++; if (tx_status & 0x38) dev->stats.tx_aborted_errors++; if (tx_status & 0x08) vp->xstats.tx_max_collisions++;
iowrite8(0, ioaddr + TxStatus); if (tx_status & 0x30) { /* txJabber or txUnderrun */
do_tx_reset = 1;
} elseif ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */
do_tx_reset = 1;
reset_mask = 0x0108; /* Reset interface logic, but not download logic */
} else { /* Merely re-enable the transmitter. */
iowrite16(TxEnable, ioaddr + EL3_CMD);
}
}
if (status & RxEarly) /* Rx early is unused. */
iowrite16(AckIntr | RxEarly, ioaddr + EL3_CMD);
if (status & StatsFull) { /* Empty statistics. */ staticint DoneDidThat; if (vortex_debug > 4)
pr_debug("%s: Updating stats.\n", dev->name);
update_stats(ioaddr, dev); /* HACK: Disable statistics as an interrupt source. */ /* This occurs when we have the wrong media type! */ if (DoneDidThat == 0 &&
ioread16(ioaddr + EL3_STATUS) & StatsFull) {
pr_warn("%s: Updating statistics failed, disabling stats as an interrupt source\n",
dev->name);
iowrite16(SetIntrEnb |
(window_read16(vp, 5, 10) & ~StatsFull),
ioaddr + EL3_CMD);
vp->intr_enable &= ~StatsFull;
DoneDidThat++;
}
} if (status & IntReq) { /* Restore all interrupt sources. */
iowrite16(vp->status_enable, ioaddr + EL3_CMD);
iowrite16(vp->intr_enable, ioaddr + EL3_CMD);
} if (status & HostError) {
u16 fifo_diag;
fifo_diag = window_read16(vp, 4, Wn4_FIFODiag);
pr_err("%s: Host error, FIFO diagnostic register %4.4x.\n",
dev->name, fifo_diag); /* Adapter failure requires Tx/Rx reset and reinit. */ if (vp->full_bus_master_tx) { int bus_status = ioread32(ioaddr + PktStatus); /* 0x80000000 PCI master abort. */ /* 0x40000000 PCI target abort. */ if (vortex_debug)
pr_err("%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);
/* In this case, blow the card away */ /* Must not enter D3 or we can't legally issue the reset! */
vortex_down(dev, 0);
issue_and_wait(dev, TotalReset | 0xff);
vortex_up(dev); /* AKPM: bug. vortex_up() assumes that the rx ring is full. It may not be. */
} elseif (fifo_diag & 0x0400)
do_tx_reset = 1; if (fifo_diag & 0x3000) { /* Reset Rx fifo and upload logic */
issue_and_wait(dev, RxReset|0x07); /* Set the Rx filter to the current state. */
set_rx_mode(dev); /* enable 802.1q VLAN tagged frames */
set_8021q_mode(dev, 1);
iowrite16(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
iowrite16(AckIntr | HostError, ioaddr + EL3_CMD);
}
}
if (do_tx_reset) {
issue_and_wait(dev, TxReset|reset_mask);
iowrite16(TxEnable, ioaddr + EL3_CMD); if (!vp->full_bus_master_tx)
netif_wake_queue(dev);
}
}
/* Put out the doubleword header... */
iowrite32(skb->len, ioaddr + TX_FIFO); if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3;
vp->tx_skb_dma = dma_map_single(vp->gendev, skb->data, len,
DMA_TO_DEVICE); if (dma_mapping_error(vp->gendev, vp->tx_skb_dma)) {
dev_kfree_skb_any(skb);
dev->stats.tx_dropped++; return NETDEV_TX_OK;
}
spin_lock_irq(&vp->window_lock);
window_set(vp, 7);
iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
iowrite16(len, ioaddr + Wn7_MasterLen);
spin_unlock_irq(&vp->window_lock);
vp->tx_skb = skb;
skb_tx_timestamp(skb);
iowrite16(StartDMADown, ioaddr + EL3_CMD); /* netif_wake_queue() will be called at the DMADone interrupt. */
} else { /* ... and the packet rounded to a doubleword. */
skb_tx_timestamp(skb);
iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
dev_consume_skb_any (skb); if (ioread16(ioaddr + TxFree) > 1536) {
netif_start_queue (dev); /* AKPM: redundant? */
} else { /* Interrupt us when the FIFO has room for max-sized packet. */
netif_stop_queue(dev);
iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
}
}
netdev_sent_queue(dev, skblen);
/* Clear the Tx status stack. */
{ int tx_status; int i = 32;
while (--i > 0 && (tx_status = ioread8(ioaddr + TxStatus)) > 0) { if (tx_status & 0x3C) { /* A Tx-disabling error occurred. */ if (vortex_debug > 2)
pr_debug("%s: Tx error, status %2.2x.\n",
dev->name, tx_status); if (tx_status & 0x04) dev->stats.tx_fifo_errors++; if (tx_status & 0x38) dev->stats.tx_aborted_errors++; if (tx_status & 0x30) {
issue_and_wait(dev, TxReset);
}
iowrite16(TxEnable, ioaddr + EL3_CMD);
}
iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
} return NETDEV_TX_OK;
}
if (vortex_debug > 6)
pr_debug("vortex_interrupt(). status=0x%4x\n", status);
if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs cause this */
handled = 1;
if (status & IntReq) {
status |= vp->deferred;
vp->deferred = 0;
}
if (status == 0xffff) /* h/w no longer present (hotplug)? */ goto handler_exit;
if (vortex_debug > 4)
pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
dev->name, status, ioread8(ioaddr + Timer));
spin_lock(&vp->window_lock);
window_set(vp, 7);
do { if (vortex_debug > 5)
pr_debug("%s: In interrupt loop, status %4.4x.\n",
dev->name, status); if (status & RxComplete)
vortex_rx(dev);
if (status & TxAvailable) { if (vortex_debug > 5)
pr_debug(" TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */
iowrite16(AckIntr | TxAvailable, ioaddr + EL3_CMD);
netif_wake_queue (dev);
}
if (status & DMADone) { if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) {
iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
dma_unmap_single(vp->gendev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, DMA_TO_DEVICE);
pkts_compl++;
bytes_compl += vp->tx_skb->len;
dev_consume_skb_irq(vp->tx_skb); /* Release the transferred buffer */ if (ioread16(ioaddr + TxFree) > 1536) { /* *AKPM:FIXME:Idon'tthinkweneedthis.Ifthequeuewasstoppeddueto *insufficientFIFOroom,theTxAvailabletestwillsucceedandcall *netif_wake_queue()
*/
netif_wake_queue(dev);
} else { /* Interrupt when FIFO has room for max-sized packet. */
iowrite16(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
netif_stop_queue(dev);
}
}
} /* Check for all uncommon interrupts at once. */ if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) { if (status == 0xffff) break; if (status & RxEarly)
vortex_rx(dev);
spin_unlock(&vp->window_lock);
vortex_error(dev, status);
spin_lock(&vp->window_lock);
window_set(vp, 7);
}
if (--work_done < 0) {
pr_warn("%s: Too much work in interrupt, status %4.4x\n",
dev->name, status); /* Disable all pending interrupts. */ do {
vp->deferred |= status;
iowrite16(SetStatusEnb | (~vp->deferred & vp->status_enable),
ioaddr + EL3_CMD);
iowrite16(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
} while ((status = ioread16(ioaddr + EL3_CMD)) & IntLatch); /* The timer will reenable interrupts. */
mod_timer(&vp->timer, jiffies + 1*HZ); break;
} /* Acknowledge the IRQ. */
iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
if (vortex_debug > 6)
pr_debug("boomerang_interrupt. status=0x%4x\n", status);
if ((status & IntLatch) == 0) goto handler_exit; /* No interrupt: shared IRQs can cause this */
handled = 1;
if (status == 0xffff) { /* h/w no longer present (hotplug)? */ if (vortex_debug > 1)
pr_debug("boomerang_interrupt(1): status = 0xffff\n"); goto handler_exit;
}
if (status & IntReq) {
status |= vp->deferred;
vp->deferred = 0;
}
if (vortex_debug > 4)
pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
dev->name, status, ioread8(ioaddr + Timer)); do { if (vortex_debug > 5)
pr_debug("%s: In interrupt loop, status %4.4x.\n",
dev->name, status); if (status & UpComplete) {
iowrite16(AckIntr | UpComplete, ioaddr + EL3_CMD); if (vortex_debug > 5)
pr_debug("boomerang_interrupt->boomerang_rx\n");
boomerang_rx(dev);
}
if (status & DownComplete) { unsignedint dirty_tx = vp->dirty_tx;
iowrite16(AckIntr | DownComplete, ioaddr + EL3_CMD); while (vp->cur_tx - dirty_tx > 0) { int entry = dirty_tx % TX_RING_SIZE; #if1/* AKPM: the latter is faster, but cyclone-only */ if (ioread32(ioaddr + DownListPtr) ==
vp->tx_ring_dma + entry * sizeof(struct boom_tx_desc)) break; /* It still hasn't been processed. */ #else if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0) break; /* It still hasn't been processed. */ #endif
if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; #if DO_ZEROCOPY int i;
dma_unmap_single(vp->gendev,
le32_to_cpu(vp->tx_ring[entry].frag[0].addr),
le32_to_cpu(vp->tx_ring[entry].frag[0].length)&0xFFF,
DMA_TO_DEVICE);
if (vp->full_bus_master_rx)
ret = _boomerang_interrupt(dev->irq, dev); else
ret = _vortex_interrupt(dev->irq, dev);
spin_unlock_irqrestore(&vp->lock, flags);
return ret;
}
staticint vortex_rx(struct net_device *dev)
{ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; int i; short rx_status;
if (vortex_debug > 5)
pr_debug("vortex_rx(): status %4.4x, rx_status %4.4x.\n",
ioread16(ioaddr+EL3_STATUS), ioread16(ioaddr+RxStatus)); while ((rx_status = ioread16(ioaddr + RxStatus)) > 0) { if (rx_status & 0x4000) { /* Error, update stats. */ unsignedchar rx_error = ioread8(ioaddr + RxErrors); if (vortex_debug > 2)
pr_debug(" Rx error: status %2.2x.\n", rx_error);
dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; if (rx_error & 0x04) dev->stats.rx_frame_errors++; if (rx_error & 0x08) dev->stats.rx_crc_errors++; if (rx_error & 0x10) dev->stats.rx_length_errors++;
} else { /* The packet length: up to 4.5K!. */ int pkt_len = rx_status & 0x1fff; struct sk_buff *skb;
skb = netdev_alloc_skb(dev, pkt_len + 5); if (vortex_debug > 4)
pr_debug("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status); if (skb != NULL) {
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ if (vp->bus_master &&
! (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)) {
dma_addr_t dma = dma_map_single(vp->gendev, skb_put(skb, pkt_len),
pkt_len, DMA_FROM_DEVICE);
iowrite32(dma, ioaddr + Wn7_MasterAddr);
iowrite16((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
iowrite16(StartDMAUp, ioaddr + EL3_CMD); while (ioread16(ioaddr + Wn7_MasterStatus) & 0x8000)
;
dma_unmap_single(vp->gendev, dma, pkt_len, DMA_FROM_DEVICE);
} else {
ioread32_rep(ioaddr + RX_FIFO,
skb_put(skb, pkt_len),
(pkt_len + 3) >> 2);
}
iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->stats.rx_packets++; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) if ( ! (ioread16(ioaddr + EL3_STATUS) & CmdInProgress)) break; continue;
} elseif (vortex_debug > 0)
pr_notice("%s: No memory to allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
dev->stats.rx_dropped++;
}
issue_and_wait(dev, RxDiscard);
}
return0;
}
staticint
boomerang_rx(struct net_device *dev)
{ struct vortex_private *vp = netdev_priv(dev); int entry = vp->cur_rx % RX_RING_SIZE; void __iomem *ioaddr = vp->ioaddr; int rx_status; int rx_work_limit = RX_RING_SIZE;
if (vortex_debug > 5)
pr_debug("boomerang_rx(): status %4.4x\n", ioread16(ioaddr+EL3_STATUS));
while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){ if (--rx_work_limit < 0) break; if (rx_status & RxDError) { /* Error, update stats. */ unsignedchar rx_error = rx_status >> 16; if (vortex_debug > 2)
pr_debug(" Rx error: status %2.2x.\n", rx_error);
dev->stats.rx_errors++; if (rx_error & 0x01) dev->stats.rx_over_errors++; if (rx_error & 0x02) dev->stats.rx_length_errors++; if (rx_error & 0x04) dev->stats.rx_frame_errors++; if (rx_error & 0x08) dev->stats.rx_crc_errors++; if (rx_error & 0x10) dev->stats.rx_length_errors++;
} else { /* The packet length: up to 4.5K!. */ int pkt_len = rx_status & 0x1fff; struct sk_buff *skb, *newskb;
dma_addr_t newdma;
dma_addr_t dma = le32_to_cpu(vp->rx_ring[entry].addr);
if (vortex_debug > 4)
pr_debug("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
/* Check if the packet is long enough to just accept without
copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak &&
(skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
dma_sync_single_for_cpu(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE); /* 'skb_put()' points to the start of sk_buff data area. */
skb_put_data(skb, vp->rx_skbuff[entry]->data,
pkt_len);
dma_sync_single_for_device(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE);
vp->rx_copy++;
} else { /* Pre-allocate the replacement skb. If it or its *mappingfailsthenrecyclethebufferthatsalready *inplace
*/
newskb = netdev_alloc_skb_ip_align(dev, PKT_BUF_SZ); if (!newskb) {
dev->stats.rx_dropped++; goto clear_complete;
}
newdma = dma_map_single(vp->gendev, newskb->data,
PKT_BUF_SZ, DMA_FROM_DEVICE); if (dma_mapping_error(vp->gendev, newdma)) {
dev->stats.rx_dropped++;
consume_skb(newskb); goto clear_complete;
}
/* Pass up the skbuff already on the Rx ring. */
skb = vp->rx_skbuff[entry];
vp->rx_skbuff[entry] = newskb;
vp->rx_ring[entry].addr = cpu_to_le32(newdma);
skb_put(skb, pkt_len);
dma_unmap_single(vp->gendev, dma, PKT_BUF_SZ, DMA_FROM_DEVICE);
vp->rx_nocopy++;
}
skb->protocol = eth_type_trans(skb, dev);
{ /* Use hardware checksum info. */ int csum_bits = rx_status & 0xee000000; if (csum_bits &&
(csum_bits == (IPChksumValid | TCPChksumValid) ||
csum_bits == (IPChksumValid | UDPChksumValid))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
vp->rx_csumhits++;
}
}
netif_rx(skb);
dev->stats.rx_packets++;
}
if (netif_device_present(dev))
vortex_down(dev, 1);
if (vortex_debug > 1) {
pr_debug("%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
dev->name, ioread16(ioaddr + EL3_STATUS), ioread8(ioaddr + TxStatus));
pr_debug("%s: vortex close stats: rx_nocopy %d rx_copy %d" " tx_queued %d Rx pre-checksummed %d.\n",
dev->name, vp->rx_nocopy, vp->rx_copy, vp->queued_packet, vp->rx_csumhits);
}
#if DO_ZEROCOPY if (vp->rx_csumhits &&
(vp->drv_flags & HAS_HWCKSM) == 0 &&
(vp->card_idx >= MAX_UNITS || hw_checksums[vp->card_idx] == -1)) {
pr_warn("%s supports hardware checksums, and we're not using them!\n",
dev->name);
} #endif
free_irq(dev->irq, dev);
if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */ for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) {
dma_unmap_single(vp->gendev, le32_to_cpu(vp->rx_ring[i].addr),
PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb(vp->rx_skbuff[i]);
vp->rx_skbuff[i] = NULL;
}
} if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */ for (i = 0; i < TX_RING_SIZE; i++) { if (vp->tx_skbuff[i]) { struct sk_buff *skb = vp->tx_skbuff[i]; #if DO_ZEROCOPY int k;
/* Pre-Cyclone chips have no documented multicast filter, so the only multicastsettingistoreceiveallmulticastframes.Atleast
the chip has a very clean way to set the mode, unlike many others. */ staticvoid set_rx_mode(struct net_device *dev)
{ struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; int new_mode;
#if IS_ENABLED(CONFIG_VLAN_8021Q) /* Setup the card so that it can receive frames with an 802.1q VLAN tag. NotethatthismustbedoneaftereachRxResetduetosomebackwards
compatibility logic in the Cyclone and Tornado ASICs */
/* The Ethernet Type used for 802.1q tagged frames */ #define VLAN_ETHER_TYPE 0x8100
staticvoid set_8021q_mode(struct net_device *dev, int enable)
{ struct vortex_private *vp = netdev_priv(dev); int mac_ctrl;
if ((vp->drv_flags&IS_CYCLONE) || (vp->drv_flags&IS_TORNADO)) { /* cyclone and tornado chipsets can recognize 802.1q
* tagged frames and treat them correctly */
int max_pkt_size = dev->mtu+14; /* MTU+Ethernet header */ if (enable)
max_pkt_size += 4; /* 802.1Q VLAN tag */
/* set VlanEtherType to let the hardware checksumming
treat tagged frames correctly */
window_write16(vp, VLAN_ETHER_TYPE, 7, Wn7_VlanEtherType);
} else { /* on older cards we have to enable large frames */
staticvoid set_8021q_mode(struct net_device *dev, int enable)
{
}
#endif
/* MII transceiver control section. ReadandwritetheMIIregistersusingsoftware-generatedserial MDIOprotocol.SeetheMIIspecificationsorDP83840Adatasheet
for details. */
/* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually metbyback-to-backPCII/Ocycles,butweinsertadelaytoavoid
"overclocking" issues. */ staticvoid mdio_delay(struct vortex_private *vp)
{
window_read32(vp, 4, Wn4_PhysicalMgmt);
}
if (vp->enable_wol) { /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
window_write16(vp, 2, 7, 0x0c); /* The RxFilter must accept the WOL frames. */
iowrite16(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
iowrite16(RxEnable, ioaddr + EL3_CMD);
if (pci_enable_wake(VORTEX_PCI(vp), PCI_D3hot, 1)) {
pr_info("%s: WOL not supported.\n", pci_name(VORTEX_PCI(vp)));
vp->enable_wol = 0; return;
}
if (VORTEX_PCI(vp)->current_state < PCI_D3hot) return;
/* Change the power state to D3; RxEnable doesn't take effect. */
pci_set_power_state(VORTEX_PCI(vp), PCI_D3hot);
}
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.83Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-01)
¤
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.