📄 xircom_cb.c
字号:
must be called with the lock held and interrupts disabled.*/static void enable_receive_interrupt(struct xircom_private *card){ unsigned int val; enter(); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | (1 << 6); /* enable the receive interrupt */ outl(val, card->io_port + CSR7); leave();}/*enable_link_interrupt enables the link status change interruptmust be called with the lock held and interrupts disabled.*/static void enable_link_interrupt(struct xircom_private *card){ unsigned int val; enter(); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val = val | LinkStatusBit; /* enable the link status chage interrupt */ outl(val, card->io_port + CSR7); leave();}/*disable_all_interrupts disables all interruptsmust be called with the lock held and interrupts disabled.*/static void disable_all_interrupts(struct xircom_private *card){ unsigned int val; enter(); val = 0; /* disable all interrupts */ outl(val, card->io_port + CSR7); leave();}/*enable_common_interrupts enables several weird interruptsmust be called with the lock held and interrupts disabled.*/static void enable_common_interrupts(struct xircom_private *card){ unsigned int val; enter(); val = inl(card->io_port + CSR7); /* Interrupt enable register */ val |= (1<<16); /* Normal Interrupt Summary */ val |= (1<<15); /* Abnormal Interrupt Summary */ val |= (1<<13); /* Fatal bus error */ val |= (1<<8); /* Receive Process Stopped */ val |= (1<<7); /* Receive Buffer Unavailable */ val |= (1<<5); /* Transmit Underflow */ val |= (1<<2); /* Transmit Buffer Unavailable */ val |= (1<<1); /* Transmit Process Stopped */ outl(val, card->io_port + CSR7); leave();}/*enable_promisc starts promisc modemust be called with the lock held and interrupts disabled.*/static inline void enable_promisc(struct xircom_private *card){ unsigned int val; enter(); val = inl(card->io_port + CSR6); val = val | PromiscBit; /* Bit 6 */ outl(val, card->io_port + CSR6); printk(KERN_INFO "xircom_cb: enabling promiscuous mode \n"); leave();}/* link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.Must be called in locked state with interrupts disabled*/static inline unsigned int link_status(struct xircom_private *card){ unsigned int val; enter(); val = inb(card->io_port + CSR12); if (!(val&(1<<2))) /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */ return 10; if (!(val&(1<<1))) /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */ return 100; /* If we get here -> no link at all */ leave(); return 0;}/* set_half_duplex() sets the card to half duplex mode. In order to do this,set_half_duplex() has to deactivate the transmitter and receiver first. Itwill re-enable the transmitter and receiver if those were active from thebeginning.Update: the above is not enough. It doesn't touch the MII, in fact it ensuresthe main chipset and the MII are never in sync if a full-duplex connectionis negotiated. The proper fix is to tell the MII to force a half-duplexconnection. -IonMust be called in locked state*/static void set_half_duplex(struct xircom_private *card){ unsigned int val; int rx,tx,tmp; enter(); rx=receive_active(card); tx=transmit_active(card); deactivate_transmitter(card); deactivate_receiver(card); val = inb(card->io_port + CSR6); val &= ~(1<<9); outb(val,card->io_port + CSR6); /* tell the MII not to advertise 10/100FDX */ tmp = mdio_read(card, 0, 4); printk("xircom_cb: capabilities changed from %#x to %#x\n", tmp, tmp & ~0x140); tmp &= ~0x140; mdio_write(card, 0, 4, tmp); /* restart autonegotiation */ tmp = mdio_read(card, 0, 0); mdio_write(card, 0, 0, tmp | 0x1200); if (rx) activate_receiver(card); if (tx) activate_transmitter(card); leave();}/* read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure. This function will take the spinlock itself and can, as a result, not be called with the lock helt. */static void read_mac_address(struct xircom_private *card){ unsigned char j, tuple, link, data_id, data_count; unsigned long flags; int i; enter(); spin_lock_irqsave(&card->lock, flags); outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */ for (i = 0x100; i < 0x1f7; i += link + 2) { outl(i, card->io_port + CSR10); tuple = inl(card->io_port + CSR9) & 0xff; outl(i + 1, card->io_port + CSR10); link = inl(card->io_port + CSR9) & 0xff; outl(i + 2, card->io_port + CSR10); data_id = inl(card->io_port + CSR9) & 0xff; outl(i + 3, card->io_port + CSR10); data_count = inl(card->io_port + CSR9) & 0xff; if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) { /* * This is it. We have the data we want. */ for (j = 0; j < 6; j++) { outl(i + j + 4, card->io_port + CSR10); card->dev->dev_addr[j] = inl(card->io_port + CSR9) & 0xff; } break; } else if (link == 0) { break; } } spin_unlock_irqrestore(&card->lock, flags);#ifdef DEBUG for (i = 0; i < 6; i++) printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]); printk("\n");#endif leave();}/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. *//* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK 0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN 0x40000#define MDIO_DATA_READ 0x80000static int mdio_read(struct xircom_private *card, int phy_id, int location){ int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long mdio_addr = card->io_port + CSR9; /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return (retval>>1) & 0xffff;}static void mdio_write(struct xircom_private *card, int phy_id, int location, int value){ int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long mdio_addr = card->io_port + CSR9; /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); }}/* tranceiver_voodoo() enables the external UTP plug thingy. it's called voodoo as I stole this code and cannot cross-reference it with the specification. */static void tranceiver_voodoo(struct xircom_private *card){ unsigned long flags; u32 tmp32; enter(); /* disable all powermanagement */ pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32); tmp32 &= ~PowerMgmtBits; pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32); setup_descriptors(card); spin_lock_irqsave(&card->lock, flags); outl(0x0008, card->io_port + CSR15); udelay(25); outl(0xa8050000, card->io_port + CSR15); udelay(25); outl(0xa00f0000, card->io_port + CSR15); udelay(25); spin_unlock_irqrestore(&card->lock, flags); netif_start_queue(card->dev); leave();}static void xircom_up(struct xircom_private *card){ unsigned long flags; int i; u32 tmp32; enter(); /* disable all powermanagement */ pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32); tmp32 &= ~PowerMgmtBits; pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32); setup_descriptors(card); spin_lock_irqsave(&card->lock, flags); enable_link_interrupt(card); enable_transmit_interrupt(card); enable_receive_interrupt(card); enable_common_interrupts(card); enable_promisc(card); /* The card can have received packets already, read them away now */ for (i=0;i<NUMDESCRIPTORS;i++) investigate_rx_descriptor(card->dev,card,i,bufferoffsets[i]); set_half_duplex(card); spin_unlock_irqrestore(&card->lock, flags); trigger_receive(card); trigger_transmit(card); netif_start_queue(card->dev); leave();}static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset){ int status; enter(); status = card->rx_desc[descnr].status; if ((status > 0)) { /* packet received */ /* TODO: discard error packets */ short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */ struct sk_buff *skb; if (pkt_len > 1518) { printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len); pkt_len = 1518; } skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) { card->stats.rx_dropped++; goto out; } skb->dev = dev; skb_reserve(skb, 2); eth_copy_and_sum(skb, &card->rx_buffer[bufferoffset], pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += pkt_len; out: /* give the buffer back to the card */ card->rx_desc[descnr].status = DescOwnedCard; trigger_receive(card); } leave();}/* Returns 1 if the descriptor is free or became free */static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset){ int status,retval = 0; enter(); status = card->tx_desc[descnr].status; if (status == DescOwnedDriver) return 1;#if 0 if (status & 0x8000) { /* Major error */ printk(KERN_ERR "Major transmit error status %x \n", status); card->tx_desc[descnr].status = 0; netif_wake_queue (dev); }#endif if (status > 0) { /* bit 31 is 0 when done */ card->stats.tx_packets++; if (card->tx_skb[descnr]!=NULL) { card->stats.tx_bytes += card->tx_skb[descnr]->len; dev_kfree_skb_irq(card->tx_skb[descnr]); } card->tx_skb[descnr] = NULL; /* Bit 8 in the status field is 1 if there was a collision */ if (status & CollisionBit) card->stats.collisions++; card->tx_desc[descnr].status = DescOwnedDriver; /* descriptor is free again */ retval = 1; } leave(); return retval; }static int __init xircom_init(void){ pci_register_driver(&xircom_ops); return 0;}static void __exit xircom_exit(void){ pci_unregister_driver(&xircom_ops);} module_init(xircom_init) module_exit(xircom_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -