⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtl_3c59x.c

📁 最新rtlinux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
  }    /* RTOS and statistic??? Let's disable stats. */  outw(StatsDisable, ioaddr + EL3_CMD);  EL3WINDOW(6);  for (i = 0; i < 10; i++)    inb(ioaddr + i);  inw(ioaddr + 10);  inw(ioaddr + 12);  /* New: On the Vortex we must also clear the BadSSD counter. */  EL3WINDOW(4);  inb(ioaddr + 12);    /* Switch to register set 7 for normal use. */  EL3WINDOW(7);    if (private_data.full_bus_master_rx) { /* Boomerang bus master. */    private_data.cur_rx = private_data.dirty_rx = private_data.cur_tx = 0;    outl(private_data.rx_ring_dma, ioaddr + UpListPtr);  }  if (private_data.full_bus_master_tx) { 		/* Boomerang bus master Tx. */    private_data.cur_tx = private_data.dirty_tx = 0;    if (private_data.drv_flags & IS_BOOMERANG)      outb(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 */      private_data.rx_ring[i].status = 0;    outl(0, ioaddr + DownListPtr);  }  /* Set receiver mode: presumably accept b-case and phys addr only. */  rtl_3COM905C_set_rx_mode();  outw(StatsDisable, ioaddr + EL3_CMD);   /* Turn off statistics ASAP. */    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */  outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */  /* Allow status bits to be seen. */  private_data.status_enable = SetStatusEnb |     (private_data.full_bus_master_rx ? UpComplete : RxComplete) | DownComplete;  private_data.intr_enable = SetIntrEnb | UpComplete | DownComplete;  outw(private_data.status_enable, ioaddr + EL3_CMD);  /* Ack all pending events, and set active indicator mask. */  outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,       ioaddr + EL3_CMD);  outw(private_data.intr_enable, ioaddr + EL3_CMD);  if (private_data.cb_fn_base)	    writel(0x8000, private_data.cb_fn_base + 4);}/***************************************************************************************//* This function is used to issue commands to the card and wait till the command has   *//* been successfuly carried out.                                                       *//***************************************************************************************/static voidrtl_3COM905C_issue_and_wait(int cmd){  int i;  outw(cmd, private_data.ioaddr + EL3_CMD);  for (i = 0; i < 2000; i++) {    if (!(inw(private_data.ioaddr + EL3_STATUS) & CmdInProgress))      return;  }    /* OK, that didn't work.  Do it the slow way.  One second */  for (i = 0; i < 100000; i++) {    if (!(inw(private_data.ioaddr + EL3_STATUS) & CmdInProgress)) {      return;    }    usleep(10);  }  printk(KERN_ERR ": command 0x%04x did not complete! Status=0x%x\n",	  cmd, inw(private_data.ioaddr + EL3_STATUS));}/***************************************************************************************//* This functions sets the receive mode of the card.                                   *//* Pre-Cyclone chips have no documented multicast filter, so the only                  *//* multicast setting is to receive all multicast frames.  At least                     *//* the chip has a very clean way to set the mode, unlike many others.                  *//***************************************************************************************/static void rtl_3COM905C_set_rx_mode(void){  long ioaddr = private_data.ioaddr;  int new_mode;    new_mode = SetRxFilter|RxStation|RxBroadcast;//RxMulticast|RxBroadcast;		  outw(new_mode, ioaddr + EL3_CMD);}/***************************************************************************************//* This function is used to release the card. It is called from the close call.        *//***************************************************************************************/static void vortex_down(struct pci_dev *dev){  long ioaddr = private_data.ioaddr;    /* Turn off statistics ASAP.  We update private_data->stats below. */  outw(StatsDisable, ioaddr + EL3_CMD);    /* Disable the receiver and transmitter. */  outw(RxDisable, ioaddr + EL3_CMD);  outw(TxDisable, ioaddr + EL3_CMD);    if (private_data.if_port == XCVR_10base2)    /* Turn off thinnet power.  Green! */    outw(StopCoax, ioaddr + EL3_CMD);    outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);    if (private_data.full_bus_master_rx)    outl(0, ioaddr + UpListPtr);  if (private_data.full_bus_master_tx)    outl(0, ioaddr + DownListPtr);    if (private_data.pdev && private_data.enable_wol) {    rt_pci_save_state(private_data.pdev, private_data.power_state);    rtl_3COM905C_acpi_set_WOL();  }}/***************************************************************************************//* This function is used to release the card.                                          *//***************************************************************************************/static int eth_close(struct pci_dev *dev){  int i;    vortex_down(dev);  if(private_data.must_free_irq){    rtl_free_irq(dev->irq);    private_data.must_free_irq = 0;  }    if (private_data.full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */    for (i = 0; i < RX_RING_SIZE; i++)      if (private_data.rx_skbuff[i]) {	rtl_free(private_data.rx_skbuff[i]);      }  }  if (private_data.full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */    for (i = 0; i < TX_RING_SIZE; i++)      if (private_data.tx_skbuff[i]) {	rtl_free(private_data.tx_skbuff[i]);      }  }  return 0;}/***************************************************************************************//* This function is never called, but it is intended to solve errors in the card.      *//* Handle uncommon interrupt sources.  This is a separate routine to minimize          */ /* the cache impact.                                                                   *//***************************************************************************************/ static void vortex_error(struct pci_dev *dev, int status){  long ioaddr = private_data.ioaddr;  int do_tx_reset = 0, reset_mask = 0;    if (status & RxEarly) {				/* Rx early is unused. */    outw(AckIntr | RxEarly, ioaddr + EL3_CMD);  }  if (status & StatsFull) {			/* Empty statistics. */    static int DoneDidThat;    printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);    /* HACK: Disable statistics as an interrupt source. */    /* This occurs when we have the wrong media type! */    if (DoneDidThat == 0  &&	inw(ioaddr + EL3_STATUS) & StatsFull) {      printk(KERN_WARNING "%s: Updating statistics failed, disabling "	     "stats as an interrupt source.\n", dev->name);      EL3WINDOW(5);      outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);      private_data.intr_enable &= ~StatsFull;      EL3WINDOW(7);      DoneDidThat++;    }  }  if (status & IntReq) {		/* Restore all interrupt sources.  */    outw(private_data.status_enable, ioaddr + EL3_CMD);    outw(private_data.intr_enable, ioaddr + EL3_CMD);  }  if (status & HostError) {    u16 fifo_diag;    EL3WINDOW(4);    fifo_diag = inw(ioaddr + Wn4_FIFODiag);    printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",	   dev->name, fifo_diag);    /* Adapter failure requires Tx/Rx reset and reinit. */    if (private_data.full_bus_master_tx) {      int bus_status = inl(ioaddr + PktStatus);      /* 0x80000000 PCI master abort. */      /* 0x40000000 PCI target abort. */            printk(KERN_ERR "%s: PCI bus error, bus status %8.8x\n", dev->name, bus_status);            /* In this case, blow the card away */      vortex_down(dev);      rtl_3COM905C_issue_and_wait(TotalReset | 0xff);      vortex_up(dev);		/* AKPM: bug.  vortex_up() assumes that the rx ring is full. It may not be. */    } else if (fifo_diag & 0x0400)      do_tx_reset = 1;    if (fifo_diag & 0x3000) {      /* Reset Rx fifo and upload logic */      rtl_3COM905C_issue_and_wait(RxReset|0x07);      /* Set the Rx filter to the current state. */      rtl_3COM905C_set_rx_mode();      outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */      outw(AckIntr | HostError, ioaddr + EL3_CMD);    }  }    if (do_tx_reset) {    rtl_3COM905C_issue_and_wait(TxReset|reset_mask);    outw(TxEnable, ioaddr + EL3_CMD);  }}/***************************************************************************************//* This function is called during the release phase. It is mainly used to update pci   *//* stuff.                                                                              *//***************************************************************************************/static void eth_remove_one (struct pci_dev *pdev){    outw(TotalReset|0x14, private_data.ioaddr + EL3_CMD);    if (private_data.pdev && private_data.enable_wol) {    rt_pci_set_power_state(private_data.pdev, 0);	/* Go active */    if (private_data.pm_state_valid)      pci_restore_state(private_data.pdev, private_data.power_state);  }    pci_free_consistent(pdev,		      sizeof(struct boom_rx_desc) * RX_RING_SIZE,		      private_data.rx_ring,		      private_data.rx_ring_dma);  pci_free_consistent(pdev,		      sizeof(struct boom_tx_desc) * TX_RING_SIZE,		      private_data.tx_ring,		      private_data.tx_ring_dma);  if (private_data.must_free_region){    release_region(private_data.ioaddr, private_data.io_size);    private_data.must_free_region = 0;  }}/***************************************************************************************//* This function is used to send a packet. It writes into the internal buffers of the  *//* card.                                                                               *//***************************************************************************************/static int rt_eth_send_packet(const char *buffer, size_t size){  long ioaddr = private_data.ioaddr;  unsigned char *buff;  int entry = private_data.cur_tx % TX_RING_SIZE;  int previous = (private_data.cur_tx + TX_RING_SIZE - 1) % TX_RING_SIZE;  struct boom_tx_desc *actual = &private_data.tx_ring[entry];  rt_3c905c_writting = 1;  /* Wait for the stall to complete. */  rtl_3COM905C_issue_and_wait(DownStall);    buff = private_data.tx_skbuff[entry];    if(buff)    memcpy(buff, buffer, size);    actual->length = cpu_to_le32(size | LAST_FRAG);    if (inl(ioaddr + DownListPtr) == 0) {    outl(private_data.tx_ring_dma + entry * sizeof(struct boom_tx_desc), ioaddr + DownListPtr);    {      int tmp = previous;      while((private_data.tx_ring[tmp].next != 0) && (tmp != entry)){	private_data.tx_ring[tmp].next = 0;	tmp = (tmp + TX_RING_SIZE - 1) % TX_RING_SIZE;      }    }    private_data.queued_packet++;  }else    private_data.tx_ring[previous].next = cpu_to_le32(private_data.tx_ring_dma + sizeof(struct boom_tx_desc) * entry);          outw(DownUnstall, ioaddr + EL3_CMD);    private_data.cur_tx++;    rt_3c905c_writting = 0;  return size;}/* 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. */#define rtl_3COM905C_mdio_delay() inl(mdio_addr)#define MDIO_SHIFT_CLK	0x01#define MDIO_DIR_WRITE	0x04#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)#define MDIO_DATA_READ	0x02#define MDIO_ENB_IN		0x00/***************************************************************************************//* Generate the preamble required for initial synchronization and a few older          *//* transceivers.                                                                       *//***************************************************************************************/static void rtl_3COM905C_mdio_sync(long ioaddr, int bits){	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	/* Establish sync by sending at least 32 logic ones. */	while (-- bits >= 0) {		outw(MDIO_DATA_WRITE1, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}}/***************************************************************************************/static int rtl_3COM905C_mdio_read(int phy_id, int location){	int i;	long ioaddr = private_data.ioaddr;	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;	unsigned int retval = 0;	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	if (mii_preamble_required)		rtl_3COM905C_mdio_sync(ioaddr, 32);	/* Shift the read command bits out. */	for (i = 14; i >= 0; i--) {		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		rtl_3COM905C_mdio_delay();		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;}/***************************************************************************************/static void rtl_3COM905C_mdio_write(int phy_id, int location, int value){	long ioaddr = private_data.ioaddr;	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;	int i;	if (mii_preamble_required)		rtl_3COM905C_mdio_sync(ioaddr, 32);	/* Shift the command bits out. */	for (i = 31; i >= 0; i--) {		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;		outw(dataval, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	/* Leave the interface idle. */	for (i = 1; i >= 0; i--) {		outw(MDIO_ENB_IN, mdio_addr);		rtl_3COM905C_mdio_delay();		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);		rtl_3COM905C_mdio_delay();	}	return;}

⌨️ 快捷键说明

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