📄 smsc9118.c
字号:
MODULE_PARM_DESC(rx_Csum,"Enable Rx Hardware Checksum Offload");
/* The three parameters below are used for the new unkonw chip before we formally add them in the driver
So that in the future we can just immediately support chips with new IDs by passing the new id and timing at load time.
But we still need to add the supported new Chip id and the flow control parameters formally later.
*/
DWORD id_reg=0x0UL;
MODULE_PARM(id_reg,"i");
MODULE_PARM_DESC(id_reg,"Chip Id");
DWORD bus_timing=0UL;
MODULE_PARM(bus_timing,"i");
MODULE_PARM_DESC(bus_timing,"bus timing");
BOOLEAN Csum_Support=FALSE;
MODULE_PARM(Csum_Support,"i");
MODULE_PARM_DESC(Csum_Support,"The chip has the ability of Checksum offload");
MODULE_LICENSE("GPL");
int Smsc9118_init_module(void);
void Smsc9118_cleanup_module(void);
int Smsc9118_init(struct net_device *dev);
int Smsc9118_open(struct net_device *dev);
int Smsc9118_stop(struct net_device *dev);
int Smsc9118_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
struct net_device_stats * Smsc9118_get_stats(struct net_device *dev);
void Smsc9118_set_multicast_list(struct net_device *dev);
int Smsc9118_private_ioctl(PPRIVATE_DATA privateData,void *useraddr);
int Smsc9118_ethtool_ioctl(PPRIVATE_DATA privateData, void * userAddr);
int Smsc9118_do_ioctl(struct net_device *dev, struct ifreq *ifr,int cmd);
irqreturn_t Smsc9118_ISR(int irq,void *dev_id,struct pt_regs *regs);
#ifdef USING_LINT
struct net_device SMSC9118;
#else //not USING_LINT
struct net_device SMSC9118 = {init: Smsc9118_init,};
#endif //not USING_LINT
int Smsc9118_init_module(void)
{
int result=0;
int device_present=0;
SMSC_TRACE("--> init_module()");
SMSC_TRACE("Driver Version = %lX.%02lX",
(DRIVER_VERSION>>8),(DRIVER_VERSION&0xFFUL));
SMSC_TRACE("Compiled: %s, %s",__DATE__,__TIME__);
SMSC_TRACE("Platform: %s",PLATFORM_NAME);
SMSC_TRACE("Date Code: %s",date_code);
SMSC_TRACE("Driver Parameters");
if(lan_base==0UL) {
SMSC_TRACE(" lan_base = 0x%08lX, driver will decide",lan_base);
} else {
SMSC_TRACE(" lan_base = 0x%08lX",lan_base);
}
if((bus_width==16UL)||(bus_width==32UL)) {
SMSC_TRACE(" bus_width = %ld",bus_width);
} else {
SMSC_TRACE(" bus_width = %ld, driver will autodetect",bus_width);
}
if(link_mode>0x7FUL) {
SMSC_WARNING(" link_mode = %ld, Unknown",link_mode);
link_mode=0x7FUL;
SMSC_WARNING(" resetting link_mode to %ld, 100FD,100HD,10FD,10HD,ASYMP,SYMP,ANEG",link_mode);
} else if(link_mode==0UL) {
SMSC_TRACE(" link_mode = %ld, LINK_OFF",link_mode);
} else {
SMSC_TRACE(" link_mode = 0x%lX, %s,%s,%s,%s,%s,%s,%s",
link_mode,
(link_mode&LINK_SPEED_10HD)?"10HD":"",
(link_mode&LINK_SPEED_10FD)?"10FD":"",
(link_mode&LINK_SPEED_100HD)?"100HD":"",
(link_mode&LINK_SPEED_100FD)?"100FD":"",
(link_mode&LINK_ASYMMETRIC_PAUSE)?"ASYMP":"",
(link_mode&LINK_SYMMETRIC_PAUSE)?"SYMP":"",
(link_mode&LINK_AUTO_NEGOTIATE)?"ANEG":"");
}
SMSC_TRACE( " irq = %ld",irq);
if(int_deas!=0xFFFFFFFFUL) {
if(int_deas>0xFFUL) {
SMSC_WARNING(" int_deas = %ld, too high",int_deas);
int_deas=0xFFFFFFFFUL;
SMSC_WARNING(" resetting int_deas to %ld",int_deas);
}
}
if(int_deas==0xFFFFFFFFUL) {
SMSC_TRACE( " int_deas = 0x%08lX, use platform default",int_deas);
} else {
SMSC_TRACE( " int_deas = %ld, %lduS",int_deas,10UL*int_deas);
}
if(irq_pol) {
SMSC_TRACE(" irq_pol = %ld, IRQ output is active high",irq_pol);
} else {
SMSC_TRACE(" irq_pol = %ld, IRQ output is active low",irq_pol);
}
if(irq_type) {
SMSC_TRACE(" irq_type = %ld, IRQ output is Push-Pull driver",irq_type);
} else {
SMSC_TRACE(" irq_type = %ld, IRQ output is Open-Drain buffer",irq_type);
}
if(rx_dma<TRANSFER_REQUEST_DMA) {
if(Platform_IsValidDmaChannel(rx_dma)) {
SMSC_TRACE(
" rx_dma = %ld, DMA Channel %ld",rx_dma,rx_dma);
} else {
SMSC_WARNING(" rx_dma = %ld, Invalid Dma Channel",rx_dma);
rx_dma=TRANSFER_PIO;
SMSC_WARNING(" resetting rx_dma to %ld, RX will use PIO",rx_dma);
}
} else if(rx_dma==TRANSFER_REQUEST_DMA) {
SMSC_TRACE(" rx_dma = %ld, RX will try to find available channel",rx_dma);
} else {
SMSC_TRACE(" rx_dma = %ld, RX will use PIO",rx_dma);
}
if(tx_dma<TRANSFER_REQUEST_DMA) {
if(Platform_IsValidDmaChannel(tx_dma)) {
if(tx_dma!=rx_dma) {
SMSC_TRACE(
" tx_dma = %ld, DMA Channel %ld",tx_dma,tx_dma);
} else {
SMSC_WARNING(" tx_dma == rx_dma");
tx_dma=TRANSFER_PIO;
SMSC_WARNING(" resetting tx_dma to %ld, TX will use PIO",tx_dma);
}
} else {
SMSC_WARNING(" tx_dma = %ld, Invalid Dma Channel",tx_dma);
tx_dma=TRANSFER_PIO;
SMSC_WARNING(" resetting tx_dma to %ld, TX will use PIO",tx_dma);
}
} else if(tx_dma==TRANSFER_REQUEST_DMA) {
SMSC_TRACE(" tx_dma = %ld, TX will try to find available channel",tx_dma);
} else {
SMSC_TRACE(" tx_dma = %ld, TX will use PIO",tx_dma);
}
SMSC_TRACE( " dma_threshold = %ld",dma_threshold);
if(mac_addr_hi16==0xFFFFFFFFUL) {
SMSC_TRACE(" mac_addr_hi16 = 0x%08lX, will attempt to read from LAN9118",mac_addr_hi16);
SMSC_TRACE(" mac_addr_lo32 = 0x%08lX, will attempt to read from LAN9118",mac_addr_lo32);
} else {
if(mac_addr_hi16&0xFFFF0000UL) {
//The high word is reserved
SMSC_WARNING(" mac_addr_hi16 = 0x%08lX, reserved bits are high.",mac_addr_hi16);
mac_addr_hi16&=0x0000FFFFUL;
SMSC_WARNING(" reseting to mac_addr_hi16 = 0x%08lX",mac_addr_hi16);
}
if(mac_addr_lo32&0x00000001UL) {
//bit 0 is the I/G bit
SMSC_WARNING(" mac_addr_lo32 = 0x%08lX, I/G bit is set.",mac_addr_lo32);
mac_addr_lo32&=0xFFFFFFFEUL;
SMSC_WARNING(" reseting to mac_addr_lo32 = 0x%08lX",mac_addr_lo32);
}
SMSC_TRACE(" mac_addr_hi16 = 0x%08lX",mac_addr_hi16);
SMSC_TRACE(" mac_addr_lo32 = 0x%08lX",mac_addr_lo32);
}
SMSC_TRACE( " debug_mode = 0x%08lX",debug_mode);
if(tx_fif_sz&(~HW_CFG_TX_FIF_SZ_)) {
SMSC_WARNING("tx_fif_sz = 0x%08lX is invalid",tx_fif_sz);
tx_fif_sz&=HW_CFG_TX_FIF_SZ_;
SMSC_WARNING(" resetting tx_fif_sz to 0x%08lX",tx_fif_sz);
}
if(tx_fif_sz>0x000E0000UL) {
SMSC_WARNING("tx_fif_sz = 0x%08lX is too high",tx_fif_sz);
tx_fif_sz=0x000E0000UL;
SMSC_WARNING(" resetting tx_fif_sz to 0x%08lX",tx_fif_sz);
}
if(tx_fif_sz<0x00020000UL) {
SMSC_WARNING("tx_fif_sz = 0x%08lX is too low",tx_fif_sz);
tx_fif_sz=0x00020000UL;
SMSC_WARNING(" resetting tx_fif_sz to 0x%08lX",tx_fif_sz);
}
SMSC_TRACE( " tx_fif_sz = 0x%08lX",tx_fif_sz);
if(afc_cfg==0xFFFFFFFFUL) {
SMSC_TRACE(" afc_cfg = 0x%08lX, driver will decide",afc_cfg);
} else {
if(afc_cfg&0xFF000000UL) {
SMSC_WARNING("afc_cfg = 0x%08lX is invalid",afc_cfg);
afc_cfg&=0xFFFFFFFFUL;
SMSC_WARNING(" resetting to afc_cfg = 0x%08lX, driver will decide",afc_cfg);
} else {
SMSC_TRACE(
" afc_cfg = 0x%08lX",afc_cfg);
}
}
if(rx_mode==PROCESSING_MODE_TASKLET) {
SMSC_TRACE(" rx_mode = 0x%08lX, Tasklets enabled",rx_mode);
} else if(rx_mode==PROCESSING_MODE_NAPI) {
#ifndef LINUX_2_6_OR_NEWER
SMSC_WARNING(" rx_mode = 0x%08lX requires Linux 2.6 or newer", rx_mode);
rx_mode=PROCESSING_MODE_TASKLET;
SMSC_WARNING(" resetting to rx_mode = 0x%08lX, Tasklets enabled", rx_mode);
#else
SMSC_TRACE(" rx_mode = 0x%08lX, NAPI enabled",rx_mode);
#endif
} else {
SMSC_TRACE(" rx_mode = 0, use ISR");
}
#ifdef LINUX_2_6_OR_NEWER
SMSC_TRACE(" napi_weight = %lu",napi_weight);
#endif
if(phy_addr==0xFFFFFFFFUL) {
SMSC_TRACE(" phy_addr = 0xFFFFFFFF, Use internal phy");
} else if(phy_addr<=31UL) {
SMSC_TRACE(" phy_addr = 0x%08lX, use this address for external phy",phy_addr);
} else {
SMSC_TRACE(" phy_addr = 0x%08lX, auto detect external phy",phy_addr);
}
if(max_throughput) {
SMSC_TRACE(" max_throughput = 0x%08lX, Use platform default",max_throughput);
} else {
SMSC_TRACE(" max_throughput = 0x%08lX",max_throughput);
}
if(max_packet_count) {
SMSC_TRACE(" max_packet_count = 0x%08lX, Use platform default",max_packet_count);
} else {
SMSC_TRACE(" max_packet_count = 0x%08lX",max_packet_count);
}
if(packet_cost) {
SMSC_TRACE(" packet_cost = 0x%08lX, Use platform default",packet_cost);
} else {
SMSC_TRACE(" packet_cost = 0x%08lX",packet_cost);
}
if(burst_period) {
SMSC_TRACE(" burst_period = 0x%08lX, Use platform default",burst_period);
} else {
SMSC_TRACE(" burst_period = 0x%08lX",burst_period);
}
if(max_work_load) {
SMSC_TRACE(" max_work_load = 0x%08lX, Use platform default",max_work_load);
} else {
SMSC_TRACE(" max_work_load = 0x%08lX",max_work_load);
}
strcpy(SMSC9118.name,"eth%d");
result=register_netdev(&SMSC9118);
if(result) {
SMSC_WARNING("error %i registering device",result);
} else {
device_present=1;
SMSC_TRACE(" Interface Name = \"%s\"",SMSC9118.name);
}
result=result;//make lint happy
SMSC_TRACE("<-- init_module()");
return device_present ? 0 : -ENODEV;
}
void Smsc9118_cleanup_module(void)
{
SMSC_TRACE("--> cleanup_module()");
if(SMSC9118.priv!=NULL) {
PPRIVATE_DATA privateData=(PPRIVATE_DATA)SMSC9118.priv;
PPLATFORM_DATA platformData=(PPLATFORM_DATA)&(privateData->PlatformData);
Platform_CleanUp(platformData);
kfree(SMSC9118.priv);
SMSC9118.priv=NULL;
}
unregister_netdev(&SMSC9118);
SMSC_TRACE("<-- cleanup_module()");
}
int Smsc9118_init(struct net_device *dev)
{
DWORD dwLanBase=0UL;
DWORD dwIdRev=0UL;
DWORD dwFpgaRev=0UL;
// WORD SpecialCtrlSts=0U;
PPRIVATE_DATA privateData=NULL;
PPLATFORM_DATA platformData=NULL;
BOOLEAN platformInitialized=FALSE;
int result=-ENODEV;
SMSC_TRACE("-->Smsc9118_init(dev=0x%08lX)",(DWORD)dev);
if(dev==NULL) {
SMSC_WARNING("Smsc9118_init(dev==NULL)");
result=-EFAULT;
goto DONE;
}
if(dev->priv!=NULL) {
SMSC_WARNING("dev->priv!=NULL, going to overwrite pointer");
}
dev->priv=kmalloc(sizeof(PRIVATE_DATA),GFP_KERNEL);
if(dev->priv==NULL) {
SMSC_WARNING("Unable to allocate PRIVATE_DATA");
result=-ENOMEM;
goto DONE;
}
memset(dev->priv,0,sizeof(PRIVATE_DATA));
privateData=(PPRIVATE_DATA)(dev->priv);
platformData=&(privateData->PlatformData);
dwLanBase=Platform_Initialize(
platformData,
lan_base,bus_width);
if(dwLanBase==0UL) {
SMSC_WARNING("dwLanBase==0x00000000");
result=-ENODEV;
goto DONE;
}
platformInitialized=TRUE;
SMSC_TRACE("dwLanBase=0x%08lX",dwLanBase);
if(check_mem_region(dwLanBase,LAN_REGISTER_EXTENT)!=0) {
SMSC_WARNING(" Memory Region specified (0x%08lX to 0x%08lX) is not available.",
dwLanBase,dwLanBase+LAN_REGISTER_EXTENT-1UL);
result=-ENOMEM;
goto DONE;
}
privateData->dwLanBase=dwLanBase;
dwIdRev=Lan_GetRegDW(ID_REV);
if(HIWORD(dwIdRev)==LOWORD(dwIdRev)) {
//this may mean the chip is set for 32 bit
// while the bus is reading as 16 bit
UNKNOWN_CHIP:
SMSC_WARNING(" LAN9118 Family NOT Identified, dwIdRev==0x%08lX",dwIdRev);
result=-ENODEV;
goto DONE;
}
switch(dwIdRev&0xFFFF0000UL) {
case 0x93120000UL:
if (Scatter_gather | tx_Csum | rx_Csum)
SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
privateData->UseScatterGather=FALSE;
privateData->UseTxCsum=FALSE;
privateData->UseRxCsum=FALSE;
switch(dwIdRev&0x0000FFFFUL) {
case 1UL:
SMSC_TRACE(" Hydra identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=3;
break;
default:
SMSC_TRACE(" Hydra identified (NEW), dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=3;
break;
};break;
case 0x01180000UL:
if (Scatter_gather | tx_Csum | rx_Csum)
SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
privateData->UseScatterGather=FALSE;
privateData->UseTxCsum=FALSE;
privateData->UseRxCsum=FALSE;
switch(dwIdRev&0x0000FFFFUL) {
case 0UL:
SMSC_TRACE(" LAN9118 Beacon identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=0;
break;
case 1UL:
SMSC_TRACE(" LAN9118 Concord A0 identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=1;
break;
case 2UL:
SMSC_TRACE(" LAN9118 Concord A1 identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=2;
break;
default:
SMSC_TRACE(" LAN9118 Concord A1 identified (NEW), dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=2;
break;
};break;
case 0x01170000UL:
if (Scatter_gather | tx_Csum | rx_Csum)
SMSC_TRACE("This chip doesn't support checksum offload!!! Will use nonchecksum offload by default");
privateData->UseScatterGather=FALSE;
privateData->UseTxCsum=FALSE;
privateData->UseRxCsum=FALSE;
switch(dwIdRev&0x0000FFFFUL) {
case 0UL:
SMSC_TRACE(" LAN9117 Beacon identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=0;
break;
case 1UL:
SMSC_TRACE(" LAN9117 Concord A0 identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=1;
break;
case 2UL:
SMSC_TRACE(" LAN9117 Concord A1 identified, dwIdRev==0x%08lX",dwIdRev);
privateData->dwGeneration=2;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -