📄 3c59x.c
字号:
#include <bios/netdev.h>#include <bios/pci.h>#include <bios/stdio.h>#include <bios/malloc.h>#include <bios/timer.h>#include <bios/string.h>#include <bios/debug.h>#include <bios/if_ether.h>#define virt_to_bus(x) ((int)(x) + 0x10000000)struct netdev net_dev_3com_3c59x;extern const struct trans_ops eth_trans_ops;#define inb(x) pci_io_read_byte(nd->io_base + (x))#define outb(w,x) pci_io_write_byte((w), nd->io_base + (x))#define inw(x) pci_io_read_word(nd->io_base + (x))#define outw(w,x) pci_io_write_word((w), nd->io_base + (x))#define inl(x) pci_io_read_long(nd->io_base + (x))#define outl(w,x) pci_io_write_long((w), nd->io_base + (x))#define Command 14#define Command_SelectRegisterWindow(x) (0x0800 | (x))#define Command_EnableDcConverter (0x1000)#define Command_RxDisable (0x1800)#define Command_RxEnable (0x2000)#define Command_RxReset(mask) (0x2800|(mask))#define Command_UpStall (0x3000)#define Command_UpUnstall (0x3001)#define Command_DownStall (0x3002)#define Command_DownUnstall (0x3003)#define Command_TxDone (0x3800)#define Command_RxDiscard (0x4000)#define Command_TxEnable (0x4800)#define Command_TxDisable (0x5000)#define Command_TxReset(mask) (0x5800|(mask))#define Command_RequestInterrupt (0x6000)#define Command_AcknowledgeInterrupt(m) (0x6800|(m))#define Command_SetInterruptEnable(m) (0x7000|(m))#define Command_SetIndicationEnable(m) (0x7800|(m))#define Command_SetRxFilter(m) (0x8000|(m))#define Command_SetRxEarlyThresh(t) (0x8800|(t))#define Command_SetTxAvailableThresh(t) (0x9000|(t))#define Command_SetTxStartThresh(t) (0x9800|(t))#define Command_StartDma(mode) (0xa000|(mode))#define Command_StatisticsEnable (0xa800)#define Command_StatisticsDisable (0xb000)#define Command_DisableDcConverter (0xb800)#define IntStatus 14#define IntStatus_interruptLatch (1 << 0)#define IntStatus_hostError (1 << 1)#define IntStatus_txComplete (1 << 2)#define IntStatus_txAvailable (1 << 3)#define IntStatus_rxComplete (1 << 4)#define IntStatus_rxEarly (1 << 5)#define IntStatus_intRequested (1 << 6)#define IntStatus_updateStats (1 << 7)#define IntStatus_transferInt (1 << 8)#define IntStatus_busMasterInProgress (1 << 11)#define IntStatus_commandInProgress (1 << 12)#define IntStatus_windowNumber (7 << 13)/* Bank 1 (at +0x10) */#define RxData 0x10 + 0#define TxData 0x10 + 0#define RxStatus 0x10 + 8#define RxStatus_rxBytes (0x1fff)#define RxStatus_rxError (1 << 14)#define RxStatus_rxIncomplete (1 << 15)#define TxFree 0x10 + 12/* Bank 3 */#define InternalConfig 0#define InternalConfig_autoSelect (1 << 24)#define InternalConfig_xcvrSelect(x) ((x) << 20)#define InternalConfig_xcvr10bt InternalConfig_xcvrSelect(0)#define InternalConfig_xcvr10b5 InternalConfig_xcvrSelect(1)#define InternalConfig_xcvr10b2 InternalConfig_xcvrSelect(3)#define InternalConfig_xcvr100btx InternalConfig_xcvrSelect(4)#define InternalConfig_xcvr100bfx InternalConfig_xcvrSelect(5)#define InternalConfig_xcvrmii InternalConfig_xcvrSelect(6)#define InternalConfig_xcvrnway InternalConfig_xcvrSelect(8)#define MacControl 6#define MacControl_fullDuplexEnable (1 << 5)#define ResetOptions 8#define ResetOptions_100bT4available (1 << 0)#define ResetOptions_100bTXavailable (1 << 1)#define ResetOptions_100bFXavailable (1 << 2)#define ResetOptions_10bTavailable (1 << 3)#define ResetOptions_10b2available (1 << 4)#define ResetOptions_10b5available (1 << 5)#define ResetOptions_miiavailable (1 << 6)/* Bank 4 */#define MediaStatus 10#define MediaStatus_dataRate100 (1 << 1) /* ro */#define MediaStatus_crcStripDisable (1 << 2) /* rw */#define MediaStatus_enableSqeStats (1 << 3) /* ro */#define MediaStatus_collisionDetect (1 << 4) /* ro */#define MediaStatus_carrierSense (1 << 5) /* ro */#define MediaStatus_jabberGuardEnable (1 << 6) /* rw */#define MediaStatus_linkBeatEnable (1 << 7) /* rw */#define MediaStatus_jabberDetect (1 << 9) /* ro */#define MediaStatus_polarityReversed (1 << 10) /* ro */#define MediaStatus_linkBeatDetect (1 << 11) /* ro */#define MediaStatus_txInProg (1 << 12) /* ro */#define MediaStatus_dcConverterEnabled (1 << 14) /* ro */#define MediaStatus_auiDisable (1 << 15) /* ro */#define PhysicalMgmt 8#define PhysicalMgmt_clk (1 << 0)#define PhysicalMgmt_data (1 << 1)#define PhysicalMgmt_dir (1 << 2)/* Boomerang BM regs */#define PacketStatus 0x20#define TxDownListPtr 0x24#define TxFreeThreshold 0x2f#define RxUpPacketStatus 0x30#define RxUpListPtr 0x38struct tx_desc { volatile u32 next; volatile u32 status;#define DownComplete 0x00010000 volatile u32 addr; volatile u32 length;#define LastFrag 0x80000000};struct rx_desc { volatile u32 next; volatile u32 status;#define RxComplete 0x00008000#define RxError 0x00004000 volatile u32 addr; volatile u32 length;};static int eeprom_read(struct netdev *nd, int offset){ outw(Command_SelectRegisterWindow(0), Command); while ((inw(10) & 1 << 15) != 0); outw(0x0080 | (offset & 0x3f), 10); while ((inw(10) & 1 << 15) != 0); return inw(12);}#if 0static int mdio_sync(struct netdev *nd){ int i; outw(Command_SelectRegisterWindow(4), Command); // reg window 4 for (i = 0; i < 32; i++) { outw(PhysicalMgmt_dir | PhysicalMgmt_data, PhysicalMgmt); inw(PhysicalMgmt); outw(PhysicalMgmt_dir | PhysicalMgmt_data | PhysicalMgmt_clk, PhysicalMgmt); inw(PhysicalMgmt); }}static int mdio_read(struct netdev *nd, int id, int loc){ int cmd = 0x3d800 | id << 5 | loc; int i, ret = 0; /* * 14-10 = cmd * 9-5 = id * 4-0 = loc */ mdio_sync(nd); for (i = 14; i >= 0; i--) { int data; data = cmd & 1 << i ? PhysicalMgmt_data : 0; outw(PhysicalMgmt_dir | data, PhysicalMgmt); inw(PhysicalMgmt); outw(PhysicalMgmt_dir | data | PhysicalMgmt_clk, PhysicalMgmt); inw(PhysicalMgmt); } for (i = 19; i > 0; i--) { outw(0, PhysicalMgmt); inw(PhysicalMgmt); ret <<= 1; ret |= inw(PhysicalMgmt) & PhysicalMgmt_data ? 1 : 0; outw(PhysicalMgmt_clk, PhysicalMgmt); inw(PhysicalMgmt); } return ret & 0x0000 ? 0xffff : (ret >> 1 & 0xffff);}static void mdio_write(struct netdev *nd, int id, int loc, int val){ int cmd = 0x50020000 | id << 23 | loc << 18 | val; int i; /* * 31-29 = cmd * 28-23 = id * 22-18 = loc * 17-0 = val */ mdio_sync(nd); for (i = 31; i >= 0; i--) { int data; data = cmd & 1 << i ? PhysicalMgmt_data : 0; outw(PhysicalMgmt_dir | data, PhysicalMgmt); inw(PhysicalMgmt); outw(PhysicalMgmt_dir | data | PhysicalMgmt_clk, PhysicalMgmt); inw(PhysicalMgmt); } for (i = 1; i > 0; i--) { outw(0, PhysicalMgmt); inw(PhysicalMgmt); outw(PhysicalMgmt_clk, PhysicalMgmt); inw(PhysicalMgmt); }}#endifstatic inline void wait_cmd(struct netdev *nd){ while ((inw(IntStatus) & IntStatus_commandInProgress) != 0);}static void send_and_wait_cmd(struct netdev *nd, int cmd){ outw(cmd, Command); wait_cmd(nd);}static struct id { unsigned int id; const char *name; int flags;#define TXDMA 1#define RXDMA 2} nd_3c59x_ids[] = { { 0x5900, "3c590 10Combo", 0 }, { 0x5950, "3c595 Vortex 100TX", 0 }, { 0x5951, "3c595 Vortex 100T4", 0 }, { 0x5952, "3c595 Vortex 100MII", 0 }, { 0x9200, "3c905C Tornado", TXDMA|RXDMA }, { 0x0000, NULL, 0 }};static int nd_3c59x_probe(void){ struct netdev *nd = &net_dev_3com_3c59x; struct pci_dev *dev = NULL; struct id *id; int i; int resetoptions, intcfg; char *def_media; for (i = 0, id = nd_3c59x_ids; id->id; i++, id++) { dev = pci_lookup_vendor_device(NULL, 0x10b7, id->id); if (dev) break; } if (!dev) return -1; if (pci_enable(dev)) return -1; if (id->flags & (TXDMA | RXDMA) && pci_set_master(dev)) return -1; /* * Ok, we have a 3c59x card. Now, read the base register. */ nd->io_base = dev->bar[0] & ~3; if (!nd->io_base) return -1; nd->driver = id->flags; printf(" net: %s at 0x%04x, ether address", id->name, nd->io_base); /* * and the EEPROM */ for (i = 0; i < 3; i++) { int addr; /* * Note that the ether address is stored in * eeprom offset 0x10 */ addr = eeprom_read(nd, i + 10); nd->hw_addr[i * 2] = addr >> 8; nd->hw_addr[i * 2 + 1] = addr; printf("%c%02x:%02x", i == 0 ? ' ' : ':', addr >> 8, addr & 255); } outw(Command_SelectRegisterWindow(3), Command); // Reg window 3 resetoptions = inw(ResetOptions); intcfg = inl(InternalConfig); switch (intcfg & (15 << 20)) { case InternalConfig_xcvr10bt: nd->default_media = media_10bt; def_media = "10baseT"; break; case InternalConfig_xcvr10b5: nd->default_media = media_aui; def_media = "AUI"; break; case InternalConfig_xcvr10b2: nd->default_media = media_10b2; def_media = "10base2"; break; case InternalConfig_xcvr100btx: nd->default_media = media_100btx; def_media = "100baseTX"; break; case InternalConfig_xcvr100bfx: nd->default_media = media_100bfx; def_media = "100baseFX"; break; case InternalConfig_xcvrmii: nd->default_media = media_mii; def_media = "MII"; break; case InternalConfig_xcvrnway: nd->default_media = media_nway; def_media = "NWAY"; break; default: nd->default_media = media_10bt; def_media = "?"; break; } printf(", media %s\n Supported media: ", def_media); if (resetoptions & ResetOptions_100bT4available) printf("100baseT4 "); if (resetoptions & ResetOptions_100bTXavailable) printf("100baseTX "); if (resetoptions & ResetOptions_100bFXavailable) printf("100baseFX "); if (resetoptions & ResetOptions_10bTavailable) printf("10baseT "); if (resetoptions & ResetOptions_10b2available) printf("10base2 "); if (resetoptions & ResetOptions_10b5available) printf("AUI "); if (resetoptions & ResetOptions_miiavailable) printf("MII"); printf("\n"); nd->media = nd->default_media; /* * Setup the net device */ eth_setup(nd); return 0;}static int nd_3c59x_setmedia(struct netdev *nd, media_t media){ unsigned int intcfg, medstat, macctrl; /* * Read internal config and media status registers */ outw(Command_SelectRegisterWindow(3), Command); intcfg = inl(InternalConfig); macctrl = inw(MacControl); outw(Command_SelectRegisterWindow(4), Command); medstat = inw(MediaStatus); intcfg &= ~InternalConfig_xcvrSelect(15); medstat &= ~(MediaStatus_jabberGuardEnable | MediaStatus_linkBeatEnable | MediaStatus_enableSqeStats); macctrl = 0; switch (media) { case media_10bt: medstat |= MediaStatus_jabberGuardEnable | MediaStatus_linkBeatEnable;// macctrl = MacControl_fullDuplexEnable; break; case media_100btx: intcfg |= InternalConfig_xcvr100btx; medstat |= MediaStatus_linkBeatEnable; break; case media_100bfx: intcfg |= InternalConfig_xcvr100bfx; medstat |= MediaStatus_linkBeatEnable; break; case media_nway: intcfg |= InternalConfig_xcvrnway; break; case media_mii: intcfg |= InternalConfig_xcvrmii; break; case media_10b2: intcfg |= InternalConfig_xcvr10b2; break; case media_aui: intcfg |= InternalConfig_xcvr10b5; medstat |= MediaStatus_enableSqeStats; break; default: return -1; } /* * Write internal config and media status registers back */ outw(Command_SelectRegisterWindow(3), Command); outw(macctrl, MacControl); outl(intcfg, InternalConfig); send_and_wait_cmd(nd, Command_TxReset(0)); // Tx Reset send_and_wait_cmd(nd, Command_RxReset(0)); // Rx Reset /* * Don't write the mediastatus register * when we are using NWAY */ if (media != media_nway) { outw(Command_SelectRegisterWindow(4), Command); outw(medstat, MediaStatus); } return 0;}static int nd_3c59x_checkmedia(struct netdev *nd){ return 0;}static int nd_3c59x_open(struct netdev *nd){ nd_3c59x_setmedia(nd, nd->media); outw(Command_SetRxFilter(5), Command); // SetRxFilter outw(Command_SelectRegisterWindow(2), Command); // Reg window 2 outw(nd->hw_addr[0] | nd->hw_addr[1] << 8, 0); outw(nd->hw_addr[2] | nd->hw_addr[3] << 8, 2); outw(nd->hw_addr[4] | nd->hw_addr[5] << 8, 4); outw(0, 6); // StationMask outw(0, 8); outw(0, 10); if (nd->driver & TXDMA) { nd->ptr1 = malloc(sizeof(struct tx_desc)); memset(nd->ptr1, 0, sizeof(struct tx_desc)); outb(1536 >> 8, TxFreeThreshold); outl(0, TxDownListPtr); } if (nd->driver & RXDMA) { struct rx_desc *rx; rx = nd->ptr2 = malloc(sizeof(struct rx_desc) + 1536); memset(rx, 0, sizeof(struct rx_desc)); rx->next = virt_to_bus((u32)rx); rx->addr = virt_to_bus((u32)(rx + 1)); rx->length = 1536 | LastFrag; outw(Command_SetRxEarlyThresh(1536 >> 2), Command); outl(0x0020, PacketStatus); outl(virt_to_bus((u32)rx), RxUpListPtr); } outw(Command_TxEnable, Command); // TxEnable outw(Command_RxEnable, Command); // RxEnable outw(Command_SetIndicationEnable(0x7ff), Command);// SetIndicationEnable outw(Command_StatisticsEnable, Command); // StatisticsEnable return 0;}static int nd_3c59x_close(struct netdev *nd){ outw(Command_TxDisable, Command); outw(Command_RxDisable, Command); return 0;}static int nd_3c59x_status(struct netdev *nd){ return 0;}static int nd_3c59x_send(struct netdev *nd, void *buffer, int size){ if (nd->driver & TXDMA) { struct tx_desc *tx = nd->ptr1; int count; tx->next = 0; tx->addr = virt_to_bus((u32)buffer); tx->length = size | LastFrag; tx->status = size; send_and_wait_cmd(nd, Command_DownStall); outl(virt_to_bus((u32)tx), TxDownListPtr); send_and_wait_cmd(nd, Command_DownUnstall); count = 0; while ((tx->status & DownComplete) == 0) { count++; wait_cs(1); if (count > 500) { printf("tx timed out: status %04x\n", inw(IntStatus)); break; } } } else { unsigned long *frame = (unsigned long *)buffer; while (inw(TxFree) < size); outl(size, TxData); while (size > 0) { outl(*frame++, TxData); size -= 4; } } return 0;}static int nd_3c59x_recv(struct netdev *nd, void *buf){ int length = 0; if (nd->driver & RXDMA) { struct rx_desc *rx = nd->ptr2; if (!(rx->status & RxComplete)) goto no_packet; if (!(rx->status & RxError)) { length = rx->status & 0x1fff; memcpy(buf, rx + 1, length); } rx->status = 0; outw(Command_UpUnstall, Command); } else { unsigned long *frame = (unsigned long *)buf; int rxstat; if (!(inw(IntStatus) & IntStatus_rxComplete)) goto no_packet; rxstat = inw(RxStatus); if (!(rxstat & RxStatus_rxError)) { int i = length = rxstat & RxStatus_rxBytes; while (i > 0) { i -= 4; *frame++ = inl(RxData); } } outw(Command_RxDiscard, Command); } return length;no_packet: return 0;}static const struct netdev_ops nd_3c59x_ops = { nd_3c59x_probe, nd_3c59x_open, nd_3c59x_close, nd_3c59x_status, nd_3c59x_setmedia, nd_3c59x_checkmedia, nd_3c59x_send, nd_3c59x_recv,};struct netdev net_dev_3com_3c59x = { &nd_3c59x_ops, ð_trans_ops,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -