static void sonic_tx_timeout(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); int i; /* * put the Sonic into software-reset mode and * disable all interrupts before releasing DMA buffers */ SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* We could resend the original skbs. Easier to re-initialise. */ for (i = 0; i < SONIC_NUM_TDS; i++) { if(lp->tx_laddr[i]) { dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); lp->tx_laddr[i] = (dma_addr_t)0; } if(lp->tx_skb[i]) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i] = NULL; } } /* Try to restart the adaptor. */ sonic_init(dev); lp->stats.tx_errors++; dev->trans_start = jiffies; /* prevent tx timeout */ netif_wake_queue(dev); }
static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; unsigned short val; if (hwreg_present((void *)prom_addr)) { int i; for (i = 0; i < 6; i++) dev->dev_addr[i] = SONIC_READ_PROM(i); if (!INVALID_MAC(dev->dev_addr)) return; bit_reverse_addr(dev->dev_addr); if (!INVALID_MAC(dev->dev_addr)) return; printk(KERN_WARNING "macsonic: MAC address in PROM seems " "to be invalid, trying CAM\n"); } else { printk(KERN_WARNING "macsonic: cannot read MAC address from " "PROM, trying CAM\n"); } SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_CEP, 15); val = SONIC_READ(SONIC_CAP2); dev->dev_addr[5] = val >> 8; dev->dev_addr[4] = val & 0xff; val = SONIC_READ(SONIC_CAP1); dev->dev_addr[3] = val >> 8; dev->dev_addr[2] = val & 0xff; val = SONIC_READ(SONIC_CAP0); dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; if (!INVALID_MAC(dev->dev_addr)) return; printk(KERN_WARNING "macsonic: MAC address in CAM entry 15 " "seems invalid, will use a random MAC\n"); random_ether_addr(dev->dev_addr); }
static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; /* On NuBus boards we can sometimes look in the ROM resources. No such luck for comm-slot/onboard. */ for(i = 0; i < 6; i++) dev->dev_addr[i] = SONIC_READ_PROM(i); /* Most of the time, the address is bit-reversed. The NetBSD source has a rather long and detailed historical account of why this is so. */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) bit_reverse_addr(dev->dev_addr); else return 0; /* If we still have what seems to be a bogus address, we'll look in the CAM. The top entry should be ours. */ /* Danger! This only works if MacOS has already initialized the card... */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) { unsigned short val; printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_CEP, 15); val = SONIC_READ(SONIC_CAP2); dev->dev_addr[5] = val >> 8; dev->dev_addr[4] = val & 0xff; val = SONIC_READ(SONIC_CAP1); dev->dev_addr[3] = val >> 8; dev->dev_addr[2] = val & 0xff; val = SONIC_READ(SONIC_CAP0); dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; printk(KERN_INFO "HW Address from CAM 15: %pM\n", dev->dev_addr); } else return 0;
/* * Get the current statistics. * This may be called with the device open or closed. */ static struct net_device_stats * sonic_get_stats(struct net_device *dev) { struct sonic_local *lp = (struct sonic_local *)dev->priv; unsigned int base_addr = dev->base_addr; /* read the tally counter from the SONIC and reset them */ lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT); SONIC_WRITE(SONIC_CRCT,0xffff); lp->stats.rx_frame_errors += SONIC_READ(SONIC_FAET); SONIC_WRITE(SONIC_FAET,0xffff); lp->stats.rx_missed_errors += SONIC_READ(SONIC_MPT); SONIC_WRITE(SONIC_MPT,0xffff); return &lp->stats; }
static int __init macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ if ((lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); return -ENOMEM; } /* Now set up the pointers to point to the appropriate places */ lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->open = macsonic_open; dev->stop = macsonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; dev->tx_timeout = sonic_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ SONIC_WRITE(SONIC_CRCT, 0xffff); SONIC_WRITE(SONIC_FAET, 0xffff); SONIC_WRITE(SONIC_MPT, 0xffff); return 0; }
static int __devinit macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ if ((lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", dev_name(lp->device)); return -ENOMEM; } /* Now set up the pointers to point to the appropriate places */ lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->netdev_ops = &macsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ SONIC_WRITE(SONIC_CRCT, 0xffff); SONIC_WRITE(SONIC_FAET, 0xffff); SONIC_WRITE(SONIC_MPT, 0xffff); return 0; }
/* * Close the SONIC device */ static int sonic_close(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); int i; if (sonic_debug > 2) printk("sonic_close\n"); netif_stop_queue(dev); /* * stop the SONIC, disable interrupts */ SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* unmap and free skbs that haven't been transmitted */ for (i = 0; i < SONIC_NUM_TDS; i++) { if(lp->tx_laddr[i]) { dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); lp->tx_laddr[i] = (dma_addr_t)0; } if(lp->tx_skb[i]) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i] = NULL; } } /* unmap and free the receive buffers */ for (i = 0; i < SONIC_NUM_RRS; i++) { if(lp->rx_laddr[i]) { dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); lp->rx_laddr[i] = (dma_addr_t)0; } if(lp->rx_skb[i]) { dev_kfree_skb(lp->rx_skb[i]); lp->rx_skb[i] = NULL; } } return 0; }
/* * Set or clear the multicast filter for this adaptor. */ static void sonic_multicast_list(struct net_device *dev) { struct sonic_local *lp = (struct sonic_local *)dev->priv; unsigned int base_addr = dev->base_addr; unsigned int rcr; struct dev_mc_list *dmi = dev->mc_list; unsigned char *addr; int i; rcr = SONIC_READ(SONIC_RCR) & ~(SONIC_RCR_PRO | SONIC_RCR_AMC); rcr |= SONIC_RCR_BRD; /* accept broadcast packets */ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */ rcr |= SONIC_RCR_PRO; } else { if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) { rcr |= SONIC_RCR_AMC; } else { if (sonic_debug > 2) printk ("sonic_multicast_list: mc_count %d\n",dev->mc_count); lp->cda.cam_enable = 1; /* always enable our own address */ for (i = 1; i <= dev->mc_count; i++) { addr = dmi->dmi_addr; dmi = dmi->next; lp->cda.cam_desc[i].cam_cap0 = addr[1] << 8 | addr[0]; lp->cda.cam_desc[i].cam_cap1 = addr[3] << 8 | addr[2]; lp->cda.cam_desc[i].cam_cap2 = addr[5] << 8 | addr[4]; lp->cda.cam_enable |= (1 << i); } SONIC_WRITE(SONIC_CDC,16); /* issue Load CAM command */ SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff); SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM); } } if (sonic_debug > 2) printk("sonic_multicast_list: setting RCR=%x\n",rcr); SONIC_WRITE(SONIC_RCR,rcr); }
static int __devinit macsonic_init(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); if ((lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", dev_name(lp->device)); return -ENOMEM; } lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->netdev_ops = &macsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; SONIC_WRITE(SONIC_CRCT, 0xffff); SONIC_WRITE(SONIC_FAET, 0xffff); SONIC_WRITE(SONIC_MPT, 0xffff); return 0; }
/* * Close the SONIC device */ static int sonic_close(struct net_device *dev) { unsigned int base_addr = dev->base_addr; if (sonic_debug > 2) printk ("sonic_close\n"); dev->tbusy = 1; dev->start = 0; /* * stop the SONIC, disable interrupts */ SONIC_WRITE(SONIC_ISR,0x7fff); SONIC_WRITE(SONIC_IMR,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); sonic_free_irq(dev->irq, dev); /* release the IRQ */ return 0; }
/* * We have a good packet(s), get it/them out of the buffers. */ static void sonic_rx(struct net_device *dev) { unsigned int base_addr = dev->base_addr; struct sonic_local *lp = (struct sonic_local *)dev->priv; sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK]; int status; while (rd->in_use == 0) { struct sk_buff *skb; int pkt_len; unsigned char *pkt_ptr; status = rd->rx_status; if (sonic_debug > 3) printk ("status %x, cur_rx %d, cur_rra %x\n",status,lp->cur_rx,lp->cur_rra); if (status & SONIC_RCR_PRX) { pkt_len = rd->rx_pktlen; pkt_ptr = (char *)sonic_chiptomem((rd->rx_pktptr_h << 16) + rd->rx_pktptr_l); if (sonic_debug > 3) printk ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", pkt_ptr,lp->rba, rd->rx_pktptr_h,rd->rx_pktptr_l, SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0)); /* Malloc up new buffer. */ skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } skb->dev = dev; skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* pass the packet to upper layers */ lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; if (status & SONIC_RCR_FAER) lp->stats.rx_frame_errors++; if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++; } rd->in_use = 1; rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK]; /* now give back the buffer to the receive buffer area */ if (status & SONIC_RCR_LPKT) { /* * this was the last packet out of the current receice buffer * give the buffer back to the SONIC */ lp->cur_rra += sizeof(sonic_rr_t); if (lp->cur_rra > (lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t))) lp->cur_rra = lp->rra_laddr; SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff); } else printk ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",dev->name); } /* * If any worth-while packets have been received, dev_rint() * has done a mark_bh(NET_BH) for us and will work on them * when we get to the bottom-half routine. */ return; }
/* * The typical workload of the driver: * Handle the network interface interrupts. */ static void sonic_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; unsigned int base_addr = dev->base_addr; struct sonic_local *lp; int status; if (dev == NULL) { printk ("sonic_interrupt: irq %d for unknown device.\n", irq); return; } dev->interrupt = 1; lp = (struct sonic_local *)dev->priv; status = SONIC_READ(SONIC_ISR); SONIC_WRITE(SONIC_ISR,0x7fff); /* clear all bits */ if (sonic_debug > 2) printk("sonic_interrupt: ISR=%x\n",status); if (status & SONIC_INT_PKTRX) { sonic_rx(dev); /* got packet(s) */ } if (status & SONIC_INT_TXDN) { int dirty_tx = lp->dirty_tx; while (dirty_tx < lp->cur_tx) { int entry = dirty_tx & SONIC_TDS_MASK; int status = lp->tda[entry].tx_status; if (sonic_debug > 3) printk ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n", status,lp->cur_tx,lp->dirty_tx); if (status == 0) { /* It still hasn't been Txed, kick the sonic again */ SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP); break; } /* put back EOL and free descriptor */ lp->tda[entry].tx_frag_count = 0; lp->tda[entry].tx_status = 0; if (status & 0x0001) lp->stats.tx_packets++; else { lp->stats.tx_errors++; if (status & 0x0642) lp->stats.tx_aborted_errors++; if (status & 0x0180) lp->stats.tx_carrier_errors++; if (status & 0x0020) lp->stats.tx_window_errors++; if (status & 0x0004) lp->stats.tx_fifo_errors++; } /* We must free the original skb */ if (lp->tx_skb[entry]) { dev_kfree_skb(lp->tx_skb[entry]); lp->tx_skb[entry] = 0; } /* and the VDMA address */ vdma_free(lp->tx_laddr[entry]); dirty_tx++; } if (lp->tx_full && dev->tbusy && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; dev->tbusy = 0; mark_bh(NET_BH); } lp->dirty_tx = dirty_tx; } /* * check error conditions */ if (status & SONIC_INT_RFO) { printk ("%s: receive fifo underrun\n",dev->name); lp->stats.rx_fifo_errors++; } if (status & SONIC_INT_RDE) { printk ("%s: receive descriptors exhausted\n",dev->name); lp->stats.rx_dropped++; } if (status & SONIC_INT_RBE) { printk ("%s: receive buffer exhausted\n",dev->name); lp->stats.rx_dropped++; } if (status & SONIC_INT_RBAE) { printk ("%s: receive buffer area exhausted\n",dev->name); lp->stats.rx_dropped++; } /* counter overruns; all counters are 16bit wide */ if (status & SONIC_INT_FAE) lp->stats.rx_frame_errors += 65536; if (status & SONIC_INT_CRC) lp->stats.rx_crc_errors += 65536; if (status & SONIC_INT_MP) lp->stats.rx_missed_errors += 65536; /* transmit error */ if (status & SONIC_INT_TXER) lp->stats.tx_errors++; /* * clear interrupt bits and return */ SONIC_WRITE(SONIC_ISR,status); dev->interrupt = 0; return; }
static int __devinit mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; struct sonic_local* lp = netdev_priv(dev); unsigned long base_addr, prom_addr; u16 sonic_dcr; int id = -1; int reg_offset, dma_bitmode; /* Find the first SONIC that hasn't been initialized already */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev)) != NULL) { /* Have we seen it already? */ if (slots & (1<<ndev->board->slot)) continue; slots |= 1<<ndev->board->slot; /* Is it one of ours? */ if ((id = macsonic_ident(ndev)) != -1) break; } if (ndev == NULL) return -ENODEV; switch (id) { case MACSONIC_DUODOCK: base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 2; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 0; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE16: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNALINK: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNA: base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; default: printk(KERN_ERR "macsonic: WTF, id is %d\n", id); return -ENODEV; } /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = base_addr; lp->reg_offset = reg_offset; lp->dma_bitmode = dma_bitmode; dev->irq = SLOT2IRQ(ndev->board->slot); if (!sonic_version_printed) { printk(KERN_INFO "%s", version); sonic_version_printed = 1; } printk(KERN_INFO "%s: %s in slot %X\n", dev_name(lp->device), ndev->board->name, ndev->board->slot); printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev_name(lp->device), SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset); #if 0 /* This is sometimes useful to find out how MacOS configured the card. */ printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); #endif /* Software reset, then initialize control registers. */ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0)); /* This *must* be written back to in order to restore the * extended programmable output bits, since it may not have been * initialised since the hardware reset. */ SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) return -ENODEV; /* Shared init code */ return macsonic_init(dev); }
static int __devinit mac_onboard_sonic_probe(struct net_device *dev) { struct sonic_local* lp = netdev_priv(dev); int sr; int commslot = 0; if (!MACH_IS_MAC) return -ENODEV; printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); /* Bogus probing, on the models which may or may not have Ethernet (BTW, the Ethernet *is* always at the same address, and nothing else lives there, at least if Apple's documentation is to be believed) */ if (macintosh_config->ident == MAC_MODEL_Q630 || macintosh_config->ident == MAC_MODEL_P588 || macintosh_config->ident == MAC_MODEL_P575 || macintosh_config->ident == MAC_MODEL_C610) { unsigned long flags; int card_present; local_irq_save(flags); card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); local_irq_restore(flags); if (!card_present) { printk("none.\n"); return -ENODEV; } commslot = 1; } printk("yes\n"); /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = ONBOARD_SONIC_REGISTERS; if (via_alt_mapping) dev->irq = IRQ_AUTO_3; else dev->irq = IRQ_NUBUS_9; if (!sonic_version_printed) { printk(KERN_INFO "%s", version); sonic_version_printed = 1; } printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", dev_name(lp->device), dev->base_addr); /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { lp->reg_offset = 0; lp->dma_bitmode = SONIC_BITMODE16; sr = SONIC_READ(SONIC_SR); } else if (commslot) { /* Some of the comm-slot cards are 16 bit. But some of them are not. The 32-bit cards use offset 2 and have known revisions, we try reading the revision register at offset 2, if we don't get a known revision we assume 16 bit at offset 0. */ lp->reg_offset = 2; lp->dma_bitmode = SONIC_BITMODE16; sr = SONIC_READ(SONIC_SR); if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101) /* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */ lp->dma_bitmode = SONIC_BITMODE32; else { lp->dma_bitmode = SONIC_BITMODE16; lp->reg_offset = 0; sr = SONIC_READ(SONIC_SR); } } else { /* All onboard cards are at offset 2 with 32 bit DMA. */ lp->reg_offset = 2; lp->dma_bitmode = SONIC_BITMODE32; sr = SONIC_READ(SONIC_SR); } printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev_name(lp->device), sr, lp->dma_bitmode?32:16, lp->reg_offset); #if 0 /* This is sometimes useful to find out how MacOS configured the card. */ printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); #endif /* Software reset, then initialize control registers. */ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | (lp->dma_bitmode ? SONIC_DCR_DW : 0)); /* This *must* be written back to in order to restore the * extended programmable output bits, as it may not have been * initialised since the hardware reset. */ SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ mac_onboard_sonic_ethernet_addr(dev); /* Shared init code */ return macsonic_init(dev); }
static void __devinit mac_onboard_sonic_ethernet_addr(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; unsigned short val; /* * On NuBus boards we can sometimes look in the ROM resources. * No such luck for comm-slot/onboard. * On the PowerBook 520, the PROM base address is a mystery. */ if (hwreg_present((void *)prom_addr)) { int i; for (i = 0; i < 6; i++) dev->dev_addr[i] = SONIC_READ_PROM(i); if (!INVALID_MAC(dev->dev_addr)) return; /* * Most of the time, the address is bit-reversed. The NetBSD * source has a rather long and detailed historical account of * why this is so. */ bit_reverse_addr(dev->dev_addr); if (!INVALID_MAC(dev->dev_addr)) return; /* * If we still have what seems to be a bogus address, we'll * look in the CAM. The top entry should be ours. */ printk(KERN_WARNING "macsonic: MAC address in PROM seems " "to be invalid, trying CAM\n"); } else { printk(KERN_WARNING "macsonic: cannot read MAC address from " "PROM, trying CAM\n"); } /* This only works if MacOS has already initialized the card. */ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_CEP, 15); val = SONIC_READ(SONIC_CAP2); dev->dev_addr[5] = val >> 8; dev->dev_addr[4] = val & 0xff; val = SONIC_READ(SONIC_CAP1); dev->dev_addr[3] = val >> 8; dev->dev_addr[2] = val & 0xff; val = SONIC_READ(SONIC_CAP0); dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; if (!INVALID_MAC(dev->dev_addr)) return; /* Still nonsense ... messed up someplace! */ printk(KERN_WARNING "macsonic: MAC address in CAM entry 15 " "seems invalid, will use a random MAC\n"); eth_hw_addr_random(dev); }
static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed = 0; unsigned int silicon_revision; struct sonic_local *lp = netdev_priv(dev); unsigned int base_addr = dev->base_addr; int i; int err = 0; if (!request_mem_region(base_addr, 0x100, xtsonic_string)) return -EBUSY; silicon_revision = SONIC_READ(SONIC_SR); if (sonic_debug > 1) printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); i = 0; while ((known_revisions[i] != 0xffff) && (known_revisions[i] != silicon_revision)) i++; if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); return -ENODEV; } if (sonic_debug && version_printed++ == 0) printk(version); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, SONIC_DCR_WC0|SONIC_DCR_DW|SONIC_DCR_LBR|SONIC_DCR_SBUS); SONIC_WRITE(SONIC_CEP,0); SONIC_WRITE(SONIC_IMR,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_CEP,0); for (i=0; i<3; i++) { unsigned int val = SONIC_READ(SONIC_CAP0-i); dev->dev_addr[i*2] = val; dev->dev_addr[i*2+1] = val >> 8; } lp->dma_bitmode = SONIC_BITMODE32; lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL); if (lp->descriptors == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for " " descriptors.\n", dev_name(lp->device)); goto out; } lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->netdev_ops = &xtsonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; SONIC_WRITE(SONIC_CRCT,0xffff); SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); return 0; out: release_region(dev->base_addr, SONIC_MEM_SIZE); return err; }
static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed = 0; unsigned int silicon_revision; struct sonic_local *lp = netdev_priv(dev); unsigned int base_addr = dev->base_addr; int i; int err = 0; if (!request_mem_region(base_addr, 0x100, xtsonic_string)) return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at * the expected location. */ silicon_revision = SONIC_READ(SONIC_SR); if (sonic_debug > 1) printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); i = 0; while ((known_revisions[i] != 0xffff) && (known_revisions[i] != silicon_revision)) i++; if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); return -ENODEV; } if (sonic_debug && version_printed++ == 0) printk(version); /* * Put the sonic into software reset, then retrieve ethernet address. * Note: we are assuming that the boot-loader has initialized the cam. */ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, SONIC_DCR_WC0|SONIC_DCR_DW|SONIC_DCR_LBR|SONIC_DCR_SBUS); SONIC_WRITE(SONIC_CEP,0); SONIC_WRITE(SONIC_IMR,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_CEP,0); for (i=0; i<3; i++) { unsigned int val = SONIC_READ(SONIC_CAP0-i); dev->dev_addr[i*2] = val; dev->dev_addr[i*2+1] = val >> 8; } /* Initialize the device structure. */ lp->dma_bitmode = SONIC_BITMODE32; /* * Allocate local private descriptor areas in uncached space. * The entire structure must be located within the same 64kb segment. * A simple way to ensure this is to allocate twice the * size of the structure -- given that the structure is * much less than 64 kB, at least one of the halves of * the allocated area will be contained entirely in 64 kB. * We also allocate extra space for a pointer to allow freeing * this structure later on (in xtsonic_cleanup_module()). */ lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL); if (lp->descriptors == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for " " descriptors.\n", lp->device->bus_id); goto out; } lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); /* get the virtual dma address */ lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->open = xtsonic_open; dev->stop = xtsonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; dev->tx_timeout = sonic_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ SONIC_WRITE(SONIC_CRCT,0xffff); SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); return 0; out: release_region(dev->base_addr, SONIC_MEM_SIZE); return err; }
static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; unsigned int silicon_revision; unsigned int val; struct sonic_local *lp = netdev_priv(dev); int err = -ENODEV; int i; if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) return -EBUSY; /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at * the expected location. */ silicon_revision = SONIC_READ(SONIC_SR); if (sonic_debug > 1) printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); i = 0; while (known_revisions[i] != 0xffff && known_revisions[i] != silicon_revision) i++; if (known_revisions[i] == 0xffff) { printk("SONIC ethernet controller not found (0x%4x)\n", silicon_revision); goto out; } if (sonic_debug && version_printed++ == 0) printk(version); printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", dev_name(lp->device), dev->base_addr); /* * Put the sonic into software reset, then * retrieve and print the ethernet address. */ SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); SONIC_WRITE(SONIC_CEP,0); for (i=0; i<3; i++) { val = SONIC_READ(SONIC_CAP0-i); dev->dev_addr[i*2] = val; dev->dev_addr[i*2+1] = val >> 8; } err = -ENOMEM; /* Initialize the device structure. */ lp->dma_bitmode = SONIC_BITMODE32; /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ if ((lp->descriptors = dma_alloc_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", dev_name(lp->device)); goto out; } /* Now set up the pointers to point to the appropriate places */ lp->cda = lp->descriptors; lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->cda_laddr = lp->descriptors_laddr; lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->netdev_ops = &sonic_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ SONIC_WRITE(SONIC_CRCT,0xffff); SONIC_WRITE(SONIC_FAET,0xffff); SONIC_WRITE(SONIC_MPT,0xffff); return 0; out: release_region(dev->base_addr, SONIC_MEM_SIZE); return err; }
static int __devinit mac_nubus_sonic_probe(struct net_device *dev) { static int slots; struct nubus_dev* ndev = NULL; struct sonic_local* lp = netdev_priv(dev); unsigned long base_addr, prom_addr; u16 sonic_dcr; int id = -1; int reg_offset, dma_bitmode; while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev)) != NULL) { if (slots & (1<<ndev->board->slot)) continue; slots |= 1<<ndev->board->slot; if ((id = macsonic_ident(ndev)) != -1) break; } if (ndev == NULL) return -ENODEV; switch (id) { case MACSONIC_DUODOCK: base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 2; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 0; dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE16: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNALINK: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNA: base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; reg_offset = 0; dma_bitmode = SONIC_BITMODE16; break; default: printk(KERN_ERR "macsonic: WTF, id is %d\n", id); return -ENODEV; } dev->base_addr = base_addr; lp->reg_offset = reg_offset; lp->dma_bitmode = dma_bitmode; dev->irq = SLOT2IRQ(ndev->board->slot); if (!sonic_version_printed) { printk(KERN_INFO "%s", version); sonic_version_printed = 1; } printk(KERN_INFO "%s: %s in slot %X\n", dev_name(lp->device), ndev->board->name, ndev->board->slot); printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev_name(lp->device), SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset); #if 0 printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); #endif SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0)); SONIC_WRITE(SONIC_DCR2, 0); SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) return -ENODEV; return macsonic_init(dev); }
static int __devinit mac_onboard_sonic_probe(struct net_device *dev) { static int once_is_more_than_enough; struct sonic_local* lp = netdev_priv(dev); int sr; int commslot = 0; if (once_is_more_than_enough) return -ENODEV; once_is_more_than_enough = 1; if (!MACH_IS_MAC) return -ENODEV; if (macintosh_config->ether_type != MAC_ETHER_SONIC) return -ENODEV; printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); if (macintosh_config->ident == MAC_MODEL_Q630 || macintosh_config->ident == MAC_MODEL_P588 || macintosh_config->ident == MAC_MODEL_P575 || macintosh_config->ident == MAC_MODEL_C610) { unsigned long flags; int card_present; local_irq_save(flags); card_present = hwreg_present((void*)ONBOARD_SONIC_REGISTERS); local_irq_restore(flags); if (!card_present) { printk("none.\n"); return -ENODEV; } commslot = 1; } printk("yes\n"); dev->base_addr = ONBOARD_SONIC_REGISTERS; if (via_alt_mapping) dev->irq = IRQ_AUTO_3; else dev->irq = IRQ_NUBUS_9; if (!sonic_version_printed) { printk(KERN_INFO "%s", version); sonic_version_printed = 1; } printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", dev_name(lp->device), dev->base_addr); if (macintosh_config->ident == MAC_MODEL_PB520) { lp->reg_offset = 0; lp->dma_bitmode = SONIC_BITMODE16; sr = SONIC_READ(SONIC_SR); } else if (commslot) { lp->reg_offset = 2; lp->dma_bitmode = SONIC_BITMODE16; sr = SONIC_READ(SONIC_SR); if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101) lp->dma_bitmode = SONIC_BITMODE32; else { lp->dma_bitmode = SONIC_BITMODE16; lp->reg_offset = 0; sr = SONIC_READ(SONIC_SR); } } else { lp->reg_offset = 2; lp->dma_bitmode = SONIC_BITMODE32; sr = SONIC_READ(SONIC_SR); } printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", dev_name(lp->device), sr, lp->dma_bitmode?32:16, lp->reg_offset); #if 0 printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", dev_name(lp->device), SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); #endif SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | (lp->dma_bitmode ? SONIC_DCR_DW : 0)); SONIC_WRITE(SONIC_DCR2, 0); SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, 0x7fff); mac_onboard_sonic_ethernet_addr(dev); return macsonic_init(dev); }
/* * Initialize the SONIC ethernet controller. */ static int sonic_init(struct net_device *dev) { unsigned int base_addr = dev->base_addr; unsigned int cmd; struct sonic_local *lp = (struct sonic_local *)dev->priv; unsigned int rra_start; unsigned int rra_end; int i; /* * put the Sonic into software-reset mode and * disable all interrupts */ SONIC_WRITE(SONIC_ISR,0x7fff); SONIC_WRITE(SONIC_IMR,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RST); /* * clear software reset flag, disable receiver, clear and * enable interrupts, then completely initialize the SONIC */ SONIC_WRITE(SONIC_CMD,0); SONIC_WRITE(SONIC_CMD,SONIC_CR_RXDIS); /* * initialize the receive resource area */ if (sonic_debug > 2) printk ("sonic_init: initialize receive resource area\n"); rra_start = lp->rra_laddr & 0xffff; rra_end = (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff; for (i = 0; i < SONIC_NUM_RRS; i++) { lp->rra[i].rx_bufadr_l = (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff; lp->rra[i].rx_bufadr_h = (lp->rba_laddr + i * SONIC_RBSIZE) >> 16; lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1; lp->rra[i].rx_bufsize_h = 0; } /* initialize all RRA registers */ SONIC_WRITE(SONIC_RSA,rra_start); SONIC_WRITE(SONIC_REA,rra_end); SONIC_WRITE(SONIC_RRP,rra_start); SONIC_WRITE(SONIC_RWP,rra_end); SONIC_WRITE(SONIC_URRA,lp->rra_laddr >> 16); SONIC_WRITE(SONIC_EOBC,(SONIC_RBSIZE-2) >> 1); lp->cur_rra = lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t); /* load the resource pointers */ if (sonic_debug > 3) printk("sonic_init: issueing RRRA command\n"); SONIC_WRITE(SONIC_CMD,SONIC_CR_RRRA); i = 0; while (i++ < 100) { if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA) break; } if (sonic_debug > 2) printk("sonic_init: status=%x\n",SONIC_READ(SONIC_CMD)); /* * Initialize the receive descriptors so that they * become a circular linked list, ie. let the last * descriptor point to the first again. */ if (sonic_debug > 2) printk ("sonic_init: initialize receive descriptors\n"); for (i=0; i<SONIC_NUM_RDS; i++) { lp->rda[i].rx_status = 0; lp->rda[i].rx_pktlen = 0; lp->rda[i].rx_pktptr_l = 0; lp->rda[i].rx_pktptr_h = 0; lp->rda[i].rx_seqno = 0; lp->rda[i].in_use = 1; lp->rda[i].link = lp->rda_laddr + (i+1) * sizeof (sonic_rd_t); } /* fix last descriptor */ lp->rda[SONIC_NUM_RDS-1].link = lp->rda_laddr; lp->cur_rx = 0; SONIC_WRITE(SONIC_URDA,lp->rda_laddr >> 16); SONIC_WRITE(SONIC_CRDA,lp->rda_laddr & 0xffff); /* * initialize transmit descriptors */ if (sonic_debug > 2) printk ("sonic_init: initialize transmit descriptors\n"); for (i = 0; i < SONIC_NUM_TDS; i++) { lp->tda[i].tx_status = 0; lp->tda[i].tx_config = 0; lp->tda[i].tx_pktsize = 0; lp->tda[i].tx_frag_count = 0; lp->tda[i].link = (lp->tda_laddr + (i+1) * sizeof (sonic_td_t)) | SONIC_END_OF_LINKS; } lp->tda[SONIC_NUM_TDS-1].link = (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS; SONIC_WRITE(SONIC_UTDA,lp->tda_laddr >> 16); SONIC_WRITE(SONIC_CTDA,lp->tda_laddr & 0xffff); lp->cur_tx = lp->dirty_tx = 0; /* * put our own address to CAM desc[0] */ lp->cda.cam_desc[0].cam_cap0 = dev->dev_addr[1] << 8 | dev->dev_addr[0]; lp->cda.cam_desc[0].cam_cap1 = dev->dev_addr[3] << 8 | dev->dev_addr[2]; lp->cda.cam_desc[0].cam_cap2 = dev->dev_addr[5] << 8 | dev->dev_addr[4]; lp->cda.cam_enable = 1; for (i=0; i < 16; i++) lp->cda.cam_desc[i].cam_entry_pointer = i; /* * initialize CAM registers */ SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff); SONIC_WRITE(SONIC_CDC,16); /* * load the CAM */ SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM); i = 0; while (i++ < 100) { if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD) break; } if (sonic_debug > 2) { printk("sonic_init: CMD=%x, ISR=%x\n", SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR)); } /* * enable receiver, disable loopback * and enable all interrupts */ SONIC_WRITE(SONIC_CMD,SONIC_CR_RXEN | SONIC_CR_STP); SONIC_WRITE(SONIC_RCR,SONIC_RCR_DEFAULT); SONIC_WRITE(SONIC_TCR,SONIC_TCR_DEFAULT); SONIC_WRITE(SONIC_ISR,0x7fff); SONIC_WRITE(SONIC_IMR,SONIC_IMR_DEFAULT); cmd = SONIC_READ(SONIC_CMD); if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0) printk("sonic_init: failed, status=%x\n",cmd); if (sonic_debug > 2) printk("sonic_init: new status=%x\n",SONIC_READ(SONIC_CMD)); return(0); }
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); dma_addr_t laddr; int length; int entry = lp->next_tx; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK; length = ETH_ZLEN; } /* * Map the packet data into the logical DMA address space */ laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); if (!laddr) { printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); return NETDEV_TX_BUSY; } sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff); sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16); sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length); sonic_tda_put(dev, entry, SONIC_TD_LINK, sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); /* * Must set tx_skb[entry] only after clearing status, and * before clearing EOL and before stopping queue */ wmb(); lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; lp->tx_skb[entry] = skb; wmb(); sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK, sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL); lp->eol_tx = entry; lp->next_tx = (entry + 1) & SONIC_TDS_MASK; if (lp->tx_skb[lp->next_tx] != NULL) { /* The ring is full, the ISR has yet to process the next TD. */ if (sonic_debug > 3) printk("%s: stopping queue\n", dev->name); netif_stop_queue(dev); /* after this packet, wait for ISR to free up some TDAs */ } else netif_start_queue(dev); if (sonic_debug > 2) printk("sonic_send_packet: issuing Tx command\n"); SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); return NETDEV_TX_OK; }
/* * transmit packet */ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) { struct sonic_local *lp = (struct sonic_local *)dev->priv; unsigned int base_addr = dev->base_addr; unsigned int laddr; int entry,length; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n",skb,dev); if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ if (sonic_debug > 1) printk("sonic_send_packet: called with dev->tbusy = 1 !\n"); if (tickssofar < 5) return 1; printk("%s: transmit timed out.\n", dev->name); /* Try to restart the adaptor. */ sonic_init(dev); dev->tbusy=0; dev->trans_start = jiffies; } /* * Block a timer-based transmit from overlapping. This could better be * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); return 1; } /* * Map the packet data into the logical DMA address space */ if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) { printk("%s: no VDMA entry for transmit available.\n",dev->name); dev_kfree_skb(skb); dev->tbusy = 0; return 1; } entry = lp->cur_tx & SONIC_TDS_MASK; lp->tx_laddr[entry] = laddr; lp->tx_skb[entry] = skb; length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; flush_cache_all(); /* * Setup the transmit descriptor and issue the transmit command. */ lp->tda[entry].tx_status = 0; /* clear status */ lp->tda[entry].tx_frag_count = 1; /* single fragment */ lp->tda[entry].tx_pktsize = length; /* length of packet */ lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff; lp->tda[entry].tx_frag_ptr_h = laddr >> 16; lp->tda[entry].tx_frag_size = length; lp->cur_tx++; lp->stats.tx_bytes += length; if (sonic_debug > 2) printk("sonic_send_packet: issueing Tx command\n"); SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP); dev->trans_start = jiffies; if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS) dev->tbusy = 0; else lp->tx_full = 1; return 0; }
/* * The typical workload of the driver: * Handle the network interface interrupts. */ static irqreturn_t sonic_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct sonic_local *lp = netdev_priv(dev); int status; if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) return IRQ_NONE; do { if (status & SONIC_INT_PKTRX) { if (sonic_debug > 2) printk("%s: packet rx\n", dev->name); sonic_rx(dev); /* got packet(s) */ SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */ } if (status & SONIC_INT_TXDN) { int entry = lp->cur_tx; int td_status; int freed_some = 0; /* At this point, cur_tx is the index of a TD that is one of: * unallocated/freed (status set & tx_skb[entry] clear) * allocated and sent (status set & tx_skb[entry] set ) * allocated and not yet sent (status clear & tx_skb[entry] set ) * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) */ if (sonic_debug > 2) printk("%s: tx done\n", dev->name); while (lp->tx_skb[entry] != NULL) { if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0) break; if (td_status & 0x0001) { lp->stats.tx_packets++; lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE); } else { lp->stats.tx_errors++; if (td_status & 0x0642) lp->stats.tx_aborted_errors++; if (td_status & 0x0180) lp->stats.tx_carrier_errors++; if (td_status & 0x0020) lp->stats.tx_window_errors++; if (td_status & 0x0004) lp->stats.tx_fifo_errors++; } /* We must free the original skb */ dev_kfree_skb_irq(lp->tx_skb[entry]); lp->tx_skb[entry] = NULL; /* and unmap DMA buffer */ dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE); lp->tx_laddr[entry] = (dma_addr_t)0; freed_some = 1; if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) { entry = (entry + 1) & SONIC_TDS_MASK; break; } entry = (entry + 1) & SONIC_TDS_MASK; } if (freed_some || lp->tx_skb[entry] == NULL) netif_wake_queue(dev); /* The ring is no longer full */ lp->cur_tx = entry; SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */ } /* * check error conditions */ if (status & SONIC_INT_RFO) { if (sonic_debug > 1) printk("%s: rx fifo overrun\n", dev->name); lp->stats.rx_fifo_errors++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */ } if (status & SONIC_INT_RDE) { if (sonic_debug > 1) printk("%s: rx descriptors exhausted\n", dev->name); lp->stats.rx_dropped++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */ } if (status & SONIC_INT_RBAE) { if (sonic_debug > 1) printk("%s: rx buffer area exceeded\n", dev->name); lp->stats.rx_dropped++; SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */ } /* counter overruns; all counters are 16bit wide */ if (status & SONIC_INT_FAE) { lp->stats.rx_frame_errors += 65536; SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */ } if (status & SONIC_INT_CRC) { lp->stats.rx_crc_errors += 65536; SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */ } if (status & SONIC_INT_MP) { lp->stats.rx_missed_errors += 65536; SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */ } /* transmit error */ if (status & SONIC_INT_TXER) { if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2)) printk(KERN_ERR "%s: tx fifo underrun\n", dev->name); SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */ } /* bus retry */ if (status & SONIC_INT_BR) { printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n", dev->name); /* ... to help debug DMA problems causing endless interrupts. */ /* Bounce the eth interface to turn on the interrupt again. */ SONIC_WRITE(SONIC_IMR, 0); SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */ } /* load CAM done */ if (status & SONIC_INT_LCD) SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); return IRQ_HANDLED; }