bcm570x.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603
  1. /*
  2. * Broadcom BCM570x Ethernet Driver for U-Boot.
  3. * Support 5701, 5702, 5703, and 5704. Single instance driver.
  4. * Copyright (C) 2002 James F. Dougherty (jfd@broadcom.com)
  5. */
  6. #include <common.h>
  7. #if defined(CONFIG_CMD_NET) \
  8. && (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x)
  9. #ifdef CONFIG_BMW
  10. #include <mpc824x.h>
  11. #endif
  12. #include <net.h>
  13. #include "bcm570x_mm.h"
  14. #include "bcm570x_autoneg.h"
  15. #include <pci.h>
  16. #include <malloc.h>
  17. /*
  18. * PCI Registers and definitions.
  19. */
  20. #define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */
  21. #define PCI_ANY_ID (~0)
  22. /*
  23. * PCI memory base for Ethernet device as well as device Interrupt.
  24. */
  25. #define BCM570X_MBAR 0x80100000
  26. #define BCM570X_ILINE 1
  27. #define SECOND_USEC 1000000
  28. #define MAX_PACKET_SIZE 1600
  29. #define MAX_UNITS 4
  30. /* Globals to this module */
  31. int initialized = 0;
  32. unsigned int ioBase = 0;
  33. volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */
  34. volatile PUM_DEVICE_BLOCK pUmDevice = NULL;
  35. /* Used to pass the full-duplex flag, etc. */
  36. int line_speed[MAX_UNITS] = { 0, 0, 0, 0 };
  37. static int full_duplex[MAX_UNITS] = { 1, 1, 1, 1 };
  38. static int rx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
  39. static int tx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
  40. static int auto_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };
  41. static int tx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
  42. static int rx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };
  43. static int auto_speed[MAX_UNITS] = { 1, 1, 1, 1 };
  44. #if JUMBO_FRAMES
  45. /* Jumbo MTU for interfaces. */
  46. static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };
  47. #endif
  48. /* Turn on Wake-on lan for a device unit */
  49. static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };
  50. #define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT
  51. static unsigned int tx_pkt_desc_cnt[MAX_UNITS] =
  52. { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };
  53. #define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT
  54. static unsigned int rx_std_desc_cnt[MAX_UNITS] =
  55. { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };
  56. static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };
  57. #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
  58. #define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT
  59. static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] =
  60. { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };
  61. #endif
  62. #define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS
  63. static unsigned int rx_coalesce_ticks[MAX_UNITS] =
  64. { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };
  65. #define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES
  66. static unsigned int rx_max_coalesce_frames[MAX_UNITS] =
  67. { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };
  68. #define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS
  69. static unsigned int tx_coalesce_ticks[MAX_UNITS] =
  70. { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };
  71. #define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES
  72. static unsigned int tx_max_coalesce_frames[MAX_UNITS] =
  73. { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };
  74. #define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS
  75. static unsigned int stats_coalesce_ticks[MAX_UNITS] =
  76. { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };
  77. /*
  78. * Legitimate values for BCM570x device types
  79. */
  80. typedef enum {
  81. BCM5700VIGIL = 0,
  82. BCM5700A6,
  83. BCM5700T6,
  84. BCM5700A9,
  85. BCM5700T9,
  86. BCM5700,
  87. BCM5701A5,
  88. BCM5701T1,
  89. BCM5701T8,
  90. BCM5701A7,
  91. BCM5701A10,
  92. BCM5701A12,
  93. BCM5701,
  94. BCM5702,
  95. BCM5703,
  96. BCM5703A31,
  97. TC996T,
  98. TC996ST,
  99. TC996SSX,
  100. TC996SX,
  101. TC996BT,
  102. TC997T,
  103. TC997SX,
  104. TC1000T,
  105. TC940BR01,
  106. TC942BR01,
  107. NC6770,
  108. NC7760,
  109. NC7770,
  110. NC7780
  111. } board_t;
  112. /* Chip-Rev names for each device-type */
  113. static struct {
  114. char *name;
  115. } chip_rev[] = {
  116. {
  117. "BCM5700VIGIL"}, {
  118. "BCM5700A6"}, {
  119. "BCM5700T6"}, {
  120. "BCM5700A9"}, {
  121. "BCM5700T9"}, {
  122. "BCM5700"}, {
  123. "BCM5701A5"}, {
  124. "BCM5701T1"}, {
  125. "BCM5701T8"}, {
  126. "BCM5701A7"}, {
  127. "BCM5701A10"}, {
  128. "BCM5701A12"}, {
  129. "BCM5701"}, {
  130. "BCM5702"}, {
  131. "BCM5703"}, {
  132. "BCM5703A31"}, {
  133. "TC996T"}, {
  134. "TC996ST"}, {
  135. "TC996SSX"}, {
  136. "TC996SX"}, {
  137. "TC996BT"}, {
  138. "TC997T"}, {
  139. "TC997SX"}, {
  140. "TC1000T"}, {
  141. "TC940BR01"}, {
  142. "TC942BR01"}, {
  143. "NC6770"}, {
  144. "NC7760"}, {
  145. "NC7770"}, {
  146. "NC7780"}, {
  147. 0}
  148. };
  149. /* indexed by board_t, above */
  150. static struct {
  151. char *name;
  152. } board_info[] = {
  153. {
  154. "Broadcom Vigil B5700 1000Base-T"}, {
  155. "Broadcom BCM5700 1000Base-T"}, {
  156. "Broadcom BCM5700 1000Base-SX"}, {
  157. "Broadcom BCM5700 1000Base-SX"}, {
  158. "Broadcom BCM5700 1000Base-T"}, {
  159. "Broadcom BCM5700"}, {
  160. "Broadcom BCM5701 1000Base-T"}, {
  161. "Broadcom BCM5701 1000Base-T"}, {
  162. "Broadcom BCM5701 1000Base-T"}, {
  163. "Broadcom BCM5701 1000Base-SX"}, {
  164. "Broadcom BCM5701 1000Base-T"}, {
  165. "Broadcom BCM5701 1000Base-T"}, {
  166. "Broadcom BCM5701"}, {
  167. "Broadcom BCM5702 1000Base-T"}, {
  168. "Broadcom BCM5703 1000Base-T"}, {
  169. "Broadcom BCM5703 1000Base-SX"}, {
  170. "3Com 3C996 10/100/1000 Server NIC"}, {
  171. "3Com 3C996 10/100/1000 Server NIC"}, {
  172. "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
  173. "3Com 3C996 Gigabit Fiber-SX Server NIC"}, {
  174. "3Com 3C996B Gigabit Server NIC"}, {
  175. "3Com 3C997 Gigabit Server NIC"}, {
  176. "3Com 3C997 Gigabit Fiber-SX Server NIC"}, {
  177. "3Com 3C1000 Gigabit NIC"}, {
  178. "3Com 3C940 Gigabit LOM (21X21)"}, {
  179. "3Com 3C942 Gigabit LOM (31X31)"}, {
  180. "Compaq NC6770 Gigabit Server Adapter"}, {
  181. "Compaq NC7760 Gigabit Server Adapter"}, {
  182. "Compaq NC7770 Gigabit Server Adapter"}, {
  183. "Compaq NC7780 Gigabit Server Adapter"}, {
  184. 0},};
  185. /* PCI Devices which use the 570x chipset */
  186. struct pci_device_table {
  187. unsigned short vendor_id, device_id; /* Vendor/DeviceID */
  188. unsigned short subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
  189. unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
  190. unsigned long board_id; /* Data private to the driver */
  191. int io_size, min_latency;
  192. } bcm570xDevices[] = {
  193. {
  194. 0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL, 128, 32}, {
  195. 0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6, 128, 32}, {
  196. 0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6, 128, 32}, {
  197. 0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9, 128, 32}, {
  198. 0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9, 128, 32}, {
  199. 0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700, 128, 32}, {
  200. 0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700, 128, 32}, {
  201. 0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700, 128, 32}, {
  202. 0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700, 128, 32}, {
  203. 0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T, 128, 32}, {
  204. 0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST, 128, 32}, {
  205. 0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX, 128, 32}, {
  206. 0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T, 128, 32}, {
  207. 0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX, 128, 32}, {
  208. 0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01, 128, 32}, {
  209. 0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700, 128, 32}, {
  210. 0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5, 128, 32}, {
  211. 0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1, 128, 32}, {
  212. 0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8, 128, 32}, {
  213. 0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7, 128, 32}, {
  214. 0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10, 128, 32}, {
  215. 0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12, 128, 32}, {
  216. 0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770, 128, 32}, {
  217. 0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770, 128, 32}, {
  218. 0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780, 128, 32}, {
  219. 0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701, 128, 32}, {
  220. 0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX, 128, 32}, {
  221. 0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT, 128, 32}, {
  222. 0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T, 128, 32}, {
  223. 0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01, 128, 32}, {
  224. 0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701, 128, 32}, {
  225. 0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
  226. 0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
  227. 0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
  228. 0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, {
  229. 0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, {
  230. 0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, {
  231. 0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
  232. 0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
  233. 0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
  234. 0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
  235. 0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
  236. 0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
  237. 0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}, {
  238. 0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, {
  239. 0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, {
  240. 0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, {
  241. 0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, {
  242. 0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, {
  243. 0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, {
  244. 0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}
  245. };
  246. #define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))
  247. /*
  248. * Allocate a packet buffer from the bcm570x packet pool.
  249. */
  250. void *bcm570xPktAlloc (int u, int pksize)
  251. {
  252. return malloc (pksize);
  253. }
  254. /*
  255. * Free a packet previously allocated from the bcm570x packet
  256. * buffer pool.
  257. */
  258. void bcm570xPktFree (int u, void *p)
  259. {
  260. free (p);
  261. }
  262. int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice)
  263. {
  264. PLM_PACKET pPacket;
  265. PUM_PACKET pUmPacket;
  266. void *skb;
  267. int queue_rx = 0;
  268. int ret = 0;
  269. while ((pUmPacket = (PUM_PACKET)
  270. QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) {
  271. pPacket = (PLM_PACKET) pUmPacket;
  272. /* reuse an old skb */
  273. if (pUmPacket->skbuff) {
  274. QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
  275. pPacket);
  276. queue_rx = 1;
  277. continue;
  278. }
  279. if ((skb = bcm570xPktAlloc (pUmDevice->index,
  280. pPacket->u.Rx.RxBufferSize + 2)) ==
  281. 0) {
  282. QQ_PushHead (&pUmDevice->rx_out_of_buf_q.Container,
  283. pPacket);
  284. printf ("NOTICE: Out of RX memory.\n");
  285. ret = 1;
  286. break;
  287. }
  288. pUmPacket->skbuff = skb;
  289. QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
  290. queue_rx = 1;
  291. }
  292. if (queue_rx) {
  293. LM_QueueRxPackets (pDevice);
  294. }
  295. return ret;
  296. }
  297. /*
  298. * Probe, Map, and Init 570x device.
  299. */
  300. int eth_init (bd_t * bis)
  301. {
  302. int i, rv, devFound = FALSE;
  303. pci_dev_t devbusfn;
  304. unsigned short status;
  305. /* Find PCI device, if it exists, configure ... */
  306. for (i = 0; i < n570xDevices; i++) {
  307. devbusfn = pci_find_device (bcm570xDevices[i].vendor_id,
  308. bcm570xDevices[i].device_id, 0);
  309. if (devbusfn == -1) {
  310. continue; /* No device of that vendor/device ID */
  311. } else {
  312. /* Set ILINE */
  313. pci_write_config_byte (devbusfn,
  314. PCI_INTERRUPT_LINE,
  315. BCM570X_ILINE);
  316. /*
  317. * 0x10 - 0x14 define one 64-bit MBAR.
  318. * 0x14 is the higher-order address bits of the BAR.
  319. */
  320. pci_write_config_dword (devbusfn,
  321. PCI_BASE_ADDRESS_1, 0);
  322. ioBase = BCM570X_MBAR;
  323. pci_write_config_dword (devbusfn,
  324. PCI_BASE_ADDRESS_0, ioBase);
  325. /*
  326. * Enable PCI memory, IO, and Master -- don't
  327. * reset any status bits in doing so.
  328. */
  329. pci_read_config_word (devbusfn, PCI_COMMAND, &status);
  330. status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
  331. pci_write_config_word (devbusfn, PCI_COMMAND, status);
  332. printf
  333. ("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n",
  334. board_info[bcm570xDevices[i].board_id].name,
  335. PCI_BUS (devbusfn), PCI_DEV (devbusfn),
  336. PCI_FUNC (devbusfn), ioBase);
  337. /* Allocate once, but always clear on init */
  338. if (!pDevice) {
  339. pDevice = malloc (sizeof (UM_DEVICE_BLOCK));
  340. pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  341. memset (pDevice, 0x0, sizeof (UM_DEVICE_BLOCK));
  342. }
  343. /* Configure pci dev structure */
  344. pUmDevice->pdev = devbusfn;
  345. pUmDevice->index = 0;
  346. pUmDevice->tx_pkt = 0;
  347. pUmDevice->rx_pkt = 0;
  348. devFound = TRUE;
  349. break;
  350. }
  351. }
  352. if (!devFound) {
  353. printf
  354. ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n");
  355. return -1;
  356. }
  357. /* Setup defaults for chip */
  358. pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
  359. if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) {
  360. pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE;
  361. } else {
  362. if (rx_checksum[i]) {
  363. pDevice->TaskToOffload |=
  364. LM_TASK_OFFLOAD_RX_TCP_CHECKSUM |
  365. LM_TASK_OFFLOAD_RX_UDP_CHECKSUM;
  366. }
  367. if (tx_checksum[i]) {
  368. pDevice->TaskToOffload |=
  369. LM_TASK_OFFLOAD_TX_TCP_CHECKSUM |
  370. LM_TASK_OFFLOAD_TX_UDP_CHECKSUM;
  371. pDevice->NoTxPseudoHdrChksum = TRUE;
  372. }
  373. }
  374. /* Set Device PCI Memory base address */
  375. pDevice->pMappedMemBase = (PLM_UINT8) ioBase;
  376. /* Pull down adapter info */
  377. if ((rv = LM_GetAdapterInfo (pDevice)) != LM_STATUS_SUCCESS) {
  378. printf ("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv);
  379. return -2;
  380. }
  381. /* Lock not needed */
  382. pUmDevice->do_global_lock = 0;
  383. if (T3_ASIC_REV (pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) {
  384. /* The 5700 chip works best without interleaved register */
  385. /* accesses on certain machines. */
  386. pUmDevice->do_global_lock = 1;
  387. }
  388. /* Setup timer delays */
  389. if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
  390. pDevice->UseTaggedStatus = TRUE;
  391. pUmDevice->timer_interval = CFG_HZ;
  392. } else {
  393. pUmDevice->timer_interval = CFG_HZ / 50;
  394. }
  395. /* Grab name .... */
  396. pUmDevice->name =
  397. (char *)malloc (strlen (board_info[bcm570xDevices[i].board_id].name)
  398. + 1);
  399. strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name);
  400. memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6);
  401. LM_SetMacAddress (pDevice, bis->bi_enetaddr);
  402. /* Init queues .. */
  403. QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container,
  404. MAX_RX_PACKET_DESC_COUNT);
  405. pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0;
  406. /* delay for 4 seconds */
  407. pUmDevice->delayed_link_ind = (4 * CFG_HZ) / pUmDevice->timer_interval;
  408. pUmDevice->adaptive_expiry = CFG_HZ / pUmDevice->timer_interval;
  409. /* Sometimes we get spurious ints. after reset when link is down. */
  410. /* This field tells the isr to service the int. even if there is */
  411. /* no status block update. */
  412. pUmDevice->adapter_just_inited =
  413. (3 * CFG_HZ) / pUmDevice->timer_interval;
  414. /* Initialize 570x */
  415. if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) {
  416. printf ("ERROR: Adapter initialization failed.\n");
  417. return ERROR;
  418. }
  419. /* Enable chip ISR */
  420. LM_EnableInterrupt (pDevice);
  421. /* Clear MC table */
  422. LM_MulticastClear (pDevice);
  423. /* Enable Multicast */
  424. LM_SetReceiveMask (pDevice,
  425. pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST);
  426. pUmDevice->opened = 1;
  427. pUmDevice->tx_full = 0;
  428. pUmDevice->tx_pkt = 0;
  429. pUmDevice->rx_pkt = 0;
  430. printf ("eth%d: %s @0x%lx,",
  431. pDevice->index, pUmDevice->name, (unsigned long)ioBase);
  432. printf ("node addr ");
  433. for (i = 0; i < 6; i++) {
  434. printf ("%2.2x", pDevice->NodeAddress[i]);
  435. }
  436. printf ("\n");
  437. printf ("eth%d: ", pDevice->index);
  438. printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name);
  439. if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID)
  440. printf ("Broadcom BCM5400 Copper ");
  441. else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID)
  442. printf ("Broadcom BCM5401 Copper ");
  443. else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)
  444. printf ("Broadcom BCM5411 Copper ");
  445. else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID)
  446. printf ("Broadcom BCM5701 Integrated Copper ");
  447. else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID)
  448. printf ("Broadcom BCM5703 Integrated Copper ");
  449. else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID)
  450. printf ("Broadcom BCM8002 SerDes ");
  451. else if (pDevice->EnableTbi)
  452. printf ("Agilent HDMP-1636 SerDes ");
  453. else
  454. printf ("Unknown ");
  455. printf ("transceiver found\n");
  456. printf ("eth%d: %s, MTU: %d,",
  457. pDevice->index, pDevice->BusSpeedStr, 1500);
  458. if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && rx_checksum[i])
  459. printf ("Rx Checksum ON\n");
  460. else
  461. printf ("Rx Checksum OFF\n");
  462. initialized++;
  463. return 0;
  464. }
  465. /* Ethernet Interrupt service routine */
  466. void eth_isr (void)
  467. {
  468. LM_UINT32 oldtag, newtag;
  469. int i;
  470. pUmDevice->interrupt = 1;
  471. if (pDevice->UseTaggedStatus) {
  472. if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) ||
  473. pUmDevice->adapter_just_inited) {
  474. MB_REG_WR (pDevice, Mailbox.Interrupt[0].Low, 1);
  475. oldtag = pDevice->pStatusBlkVirt->StatusTag;
  476. for (i = 0;; i++) {
  477. pDevice->pStatusBlkVirt->Status &=
  478. ~STATUS_BLOCK_UPDATED;
  479. LM_ServiceInterrupts (pDevice);
  480. newtag = pDevice->pStatusBlkVirt->StatusTag;
  481. if ((newtag == oldtag) || (i > 50)) {
  482. MB_REG_WR (pDevice,
  483. Mailbox.Interrupt[0].Low,
  484. newtag << 24);
  485. if (pDevice->UndiFix) {
  486. REG_WR (pDevice, Grc.LocalCtrl,
  487. pDevice->
  488. GrcLocalCtrl | 0x2);
  489. }
  490. break;
  491. }
  492. oldtag = newtag;
  493. }
  494. }
  495. } else {
  496. while (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) {
  497. unsigned int dummy;
  498. pDevice->pMemView->Mailbox.Interrupt[0].Low = 1;
  499. pDevice->pStatusBlkVirt->Status &=
  500. ~STATUS_BLOCK_UPDATED;
  501. LM_ServiceInterrupts (pDevice);
  502. pDevice->pMemView->Mailbox.Interrupt[0].Low = 0;
  503. dummy = pDevice->pMemView->Mailbox.Interrupt[0].Low;
  504. }
  505. }
  506. /* Allocate new RX buffers */
  507. if (QQ_GetEntryCnt (&pUmDevice->rx_out_of_buf_q.Container)) {
  508. bcm570xReplenishRxBuffers (pUmDevice);
  509. }
  510. /* Queue packets */
  511. if (QQ_GetEntryCnt (&pDevice->RxPacketFreeQ.Container)) {
  512. LM_QueueRxPackets (pDevice);
  513. }
  514. if (pUmDevice->tx_queued) {
  515. pUmDevice->tx_queued = 0;
  516. }
  517. if (pUmDevice->tx_full) {
  518. if (pDevice->LinkStatus != LM_STATUS_LINK_DOWN) {
  519. printf
  520. ("NOTICE: tx was previously blocked, restarting MUX\n");
  521. pUmDevice->tx_full = 0;
  522. }
  523. }
  524. pUmDevice->interrupt = 0;
  525. }
  526. int eth_send (volatile void *packet, int length)
  527. {
  528. int status = 0;
  529. #if ET_DEBUG
  530. unsigned char *ptr = (unsigned char *)packet;
  531. #endif
  532. PLM_PACKET pPacket;
  533. PUM_PACKET pUmPacket;
  534. /* Link down, return */
  535. while (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) {
  536. #if 0
  537. printf ("eth%d: link down - check cable or link partner.\n",
  538. pUmDevice->index);
  539. #endif
  540. eth_isr ();
  541. /* Wait to see link for one-half a second before sending ... */
  542. udelay (1500000);
  543. }
  544. /* Clear sent flag */
  545. pUmDevice->tx_pkt = 0;
  546. /* Previously blocked */
  547. if (pUmDevice->tx_full) {
  548. printf ("eth%d: tx blocked.\n", pUmDevice->index);
  549. return 0;
  550. }
  551. pPacket = (PLM_PACKET)
  552. QQ_PopHead (&pDevice->TxPacketFreeQ.Container);
  553. if (pPacket == 0) {
  554. pUmDevice->tx_full = 1;
  555. printf ("bcm570xEndSend: TX full!\n");
  556. return 0;
  557. }
  558. if (pDevice->SendBdLeft.counter == 0) {
  559. pUmDevice->tx_full = 1;
  560. printf ("bcm570xEndSend: no more TX descriptors!\n");
  561. QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
  562. return 0;
  563. }
  564. if (length <= 0) {
  565. printf ("eth: bad packet size: %d\n", length);
  566. goto out;
  567. }
  568. /* Get packet buffers and fragment list */
  569. pUmPacket = (PUM_PACKET) pPacket;
  570. /* Single DMA Descriptor transmit.
  571. * Fragments may be provided, but one DMA descriptor max is
  572. * used to send the packet.
  573. */
  574. if (MM_CoalesceTxBuffer (pDevice, pPacket) != LM_STATUS_SUCCESS) {
  575. if (pUmPacket->skbuff == NULL) {
  576. /* Packet was discarded */
  577. printf ("TX: failed (1)\n");
  578. status = 1;
  579. } else {
  580. printf ("TX: failed (2)\n");
  581. status = 2;
  582. }
  583. QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
  584. return status;
  585. }
  586. /* Copy packet to DMA buffer */
  587. memset (pUmPacket->skbuff, 0x0, MAX_PACKET_SIZE);
  588. memcpy ((void *)pUmPacket->skbuff, (void *)packet, length);
  589. pPacket->PacketSize = length;
  590. pPacket->Flags |= SND_BD_FLAG_END | SND_BD_FLAG_COAL_NOW;
  591. pPacket->u.Tx.FragCount = 1;
  592. /* We've already provided a frame ready for transmission */
  593. pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM;
  594. if (LM_SendPacket (pDevice, pPacket) == LM_STATUS_FAILURE) {
  595. /*
  596. * A lower level send failure will push the packet descriptor back
  597. * in the free queue, so just deal with the VxWorks clusters.
  598. */
  599. if (pUmPacket->skbuff == NULL) {
  600. printf ("TX failed (1)!\n");
  601. /* Packet was discarded */
  602. status = 3;
  603. } else {
  604. /* A resource problem ... */
  605. printf ("TX failed (2)!\n");
  606. status = 4;
  607. }
  608. if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) == 0) {
  609. printf ("TX: emptyQ!\n");
  610. pUmDevice->tx_full = 1;
  611. }
  612. }
  613. while (pUmDevice->tx_pkt == 0) {
  614. /* Service TX */
  615. eth_isr ();
  616. }
  617. #if ET_DEBUG
  618. printf ("eth_send: 0x%x, %d bytes\n"
  619. "[%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x] ...\n",
  620. (int)pPacket, length,
  621. ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5],
  622. ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11], ptr[12],
  623. ptr[13], ptr[14], ptr[15]);
  624. #endif
  625. pUmDevice->tx_pkt = 0;
  626. QQ_PushHead (&pDevice->TxPacketFreeQ.Container, pPacket);
  627. /* Done with send */
  628. out:
  629. return status;
  630. }
  631. /* Ethernet receive */
  632. int eth_rx (void)
  633. {
  634. PLM_PACKET pPacket = NULL;
  635. PUM_PACKET pUmPacket = NULL;
  636. void *skb;
  637. int size = 0;
  638. while (TRUE) {
  639. bcm570x_service_isr:
  640. /* Pull down packet if it is there */
  641. eth_isr ();
  642. /* Indicate RX packets called */
  643. if (pUmDevice->rx_pkt) {
  644. /* printf("eth_rx: got a packet...\n"); */
  645. pUmDevice->rx_pkt = 0;
  646. } else {
  647. /* printf("eth_rx: waiting for packet...\n"); */
  648. goto bcm570x_service_isr;
  649. }
  650. pPacket = (PLM_PACKET)
  651. QQ_PopHead (&pDevice->RxPacketReceivedQ.Container);
  652. if (pPacket == 0) {
  653. printf ("eth_rx: empty packet!\n");
  654. goto bcm570x_service_isr;
  655. }
  656. pUmPacket = (PUM_PACKET) pPacket;
  657. #if ET_DEBUG
  658. printf ("eth_rx: packet @0x%x\n", (int)pPacket);
  659. #endif
  660. /* If the packet generated an error, reuse buffer */
  661. if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) ||
  662. ((size = pPacket->PacketSize) > pDevice->RxMtu)) {
  663. /* reuse skb */
  664. QQ_PushTail (&pDevice->RxPacketFreeQ.Container,
  665. pPacket);
  666. printf ("eth_rx: error in packet dma!\n");
  667. goto bcm570x_service_isr;
  668. }
  669. /* Set size and address */
  670. skb = pUmPacket->skbuff;
  671. size = pPacket->PacketSize;
  672. /* Pass the packet up to the protocol
  673. * layers.
  674. */
  675. NetReceive (skb, size);
  676. /* Free packet buffer */
  677. bcm570xPktFree (pUmDevice->index, skb);
  678. pUmPacket->skbuff = NULL;
  679. /* Reuse SKB */
  680. QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
  681. return 0; /* Got a packet, bail ... */
  682. }
  683. return size;
  684. }
  685. /* Shut down device */
  686. void eth_halt (void)
  687. {
  688. int i;
  689. if (initialized)
  690. if (pDevice && pUmDevice && pUmDevice->opened) {
  691. printf ("\neth%d:%s,", pUmDevice->index,
  692. pUmDevice->name);
  693. printf ("HALT,");
  694. /* stop device */
  695. LM_Halt (pDevice);
  696. printf ("POWER DOWN,");
  697. LM_SetPowerState (pDevice, LM_POWER_STATE_D3);
  698. /* Free the memory allocated by the device in tigon3 */
  699. for (i = 0; i < pUmDevice->mem_list_num; i++) {
  700. if (pUmDevice->mem_list[i]) {
  701. /* sanity check */
  702. if (pUmDevice->dma_list[i]) { /* cache-safe memory */
  703. free (pUmDevice->mem_list[i]);
  704. } else {
  705. free (pUmDevice->mem_list[i]); /* normal memory */
  706. }
  707. }
  708. }
  709. pUmDevice->opened = 0;
  710. free (pDevice);
  711. pDevice = NULL;
  712. pUmDevice = NULL;
  713. initialized = 0;
  714. printf ("done - offline.\n");
  715. }
  716. }
  717. /*
  718. *
  719. * Middle Module: Interface between the HW driver (tigon3 modules) and
  720. * the native (SENS) driver. These routines implement the system
  721. * interface for tigon3 on VxWorks.
  722. */
  723. /* Middle module dependency - size of a packet descriptor */
  724. int MM_Packet_Desc_Size = sizeof (UM_PACKET);
  725. LM_STATUS
  726. MM_ReadConfig32 (PLM_DEVICE_BLOCK pDevice,
  727. LM_UINT32 Offset, LM_UINT32 * pValue32)
  728. {
  729. UM_DEVICE_BLOCK *pUmDevice;
  730. pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
  731. pci_read_config_dword (pUmDevice->pdev, Offset, (u32 *) pValue32);
  732. return LM_STATUS_SUCCESS;
  733. }
  734. LM_STATUS
  735. MM_WriteConfig32 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT32 Value32)
  736. {
  737. UM_DEVICE_BLOCK *pUmDevice;
  738. pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
  739. pci_write_config_dword (pUmDevice->pdev, Offset, Value32);
  740. return LM_STATUS_SUCCESS;
  741. }
  742. LM_STATUS
  743. MM_ReadConfig16 (PLM_DEVICE_BLOCK pDevice,
  744. LM_UINT32 Offset, LM_UINT16 * pValue16)
  745. {
  746. UM_DEVICE_BLOCK *pUmDevice;
  747. pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
  748. pci_read_config_word (pUmDevice->pdev, Offset, (u16 *) pValue16);
  749. return LM_STATUS_SUCCESS;
  750. }
  751. LM_STATUS
  752. MM_WriteConfig16 (PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, LM_UINT16 Value16)
  753. {
  754. UM_DEVICE_BLOCK *pUmDevice;
  755. pUmDevice = (UM_DEVICE_BLOCK *) pDevice;
  756. pci_write_config_word (pUmDevice->pdev, Offset, Value16);
  757. return LM_STATUS_SUCCESS;
  758. }
  759. LM_STATUS
  760. MM_AllocateSharedMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
  761. PLM_VOID * pMemoryBlockVirt,
  762. PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, LM_BOOL Cached)
  763. {
  764. PLM_VOID pvirt;
  765. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  766. dma_addr_t mapping;
  767. pvirt = malloc (BlockSize);
  768. mapping = (dma_addr_t) (pvirt);
  769. if (!pvirt)
  770. return LM_STATUS_FAILURE;
  771. pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
  772. pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping;
  773. pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
  774. memset (pvirt, 0, BlockSize);
  775. *pMemoryBlockVirt = (PLM_VOID) pvirt;
  776. MM_SetAddr (pMemoryBlockPhy, (dma_addr_t) mapping);
  777. return LM_STATUS_SUCCESS;
  778. }
  779. LM_STATUS
  780. MM_AllocateMemory (PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize,
  781. PLM_VOID * pMemoryBlockVirt)
  782. {
  783. PLM_VOID pvirt;
  784. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  785. pvirt = malloc (BlockSize);
  786. if (!pvirt)
  787. return LM_STATUS_FAILURE;
  788. pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt;
  789. pUmDevice->dma_list[pUmDevice->mem_list_num] = 0;
  790. pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize;
  791. memset (pvirt, 0, BlockSize);
  792. *pMemoryBlockVirt = pvirt;
  793. return LM_STATUS_SUCCESS;
  794. }
  795. LM_STATUS MM_MapMemBase (PLM_DEVICE_BLOCK pDevice)
  796. {
  797. printf ("BCM570x PCI Memory base address @0x%x\n",
  798. (unsigned int)pDevice->pMappedMemBase);
  799. return LM_STATUS_SUCCESS;
  800. }
  801. LM_STATUS MM_InitializeUmPackets (PLM_DEVICE_BLOCK pDevice)
  802. {
  803. int i;
  804. void *skb;
  805. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  806. PUM_PACKET pUmPacket = NULL;
  807. PLM_PACKET pPacket = NULL;
  808. for (i = 0; i < pDevice->RxPacketDescCnt; i++) {
  809. pPacket = QQ_PopHead (&pDevice->RxPacketFreeQ.Container);
  810. pUmPacket = (PUM_PACKET) pPacket;
  811. if (pPacket == 0) {
  812. printf ("MM_InitializeUmPackets: Bad RxPacketFreeQ\n");
  813. }
  814. skb = bcm570xPktAlloc (pUmDevice->index,
  815. pPacket->u.Rx.RxBufferSize + 2);
  816. if (skb == 0) {
  817. pUmPacket->skbuff = 0;
  818. QQ_PushTail (&pUmDevice->rx_out_of_buf_q.Container,
  819. pPacket);
  820. printf ("MM_InitializeUmPackets: out of buffer.\n");
  821. continue;
  822. }
  823. pUmPacket->skbuff = skb;
  824. QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket);
  825. }
  826. pUmDevice->rx_low_buf_thresh = pDevice->RxPacketDescCnt / 8;
  827. return LM_STATUS_SUCCESS;
  828. }
  829. LM_STATUS MM_GetConfig (PLM_DEVICE_BLOCK pDevice)
  830. {
  831. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  832. int index = pDevice->index;
  833. if (auto_speed[index] == 0)
  834. pDevice->DisableAutoNeg = TRUE;
  835. else
  836. pDevice->DisableAutoNeg = FALSE;
  837. if (line_speed[index] == 0) {
  838. pDevice->RequestedMediaType = LM_REQUESTED_MEDIA_TYPE_AUTO;
  839. pDevice->DisableAutoNeg = FALSE;
  840. } else {
  841. if (line_speed[index] == 1000) {
  842. if (pDevice->EnableTbi) {
  843. pDevice->RequestedMediaType =
  844. LM_REQUESTED_MEDIA_TYPE_FIBER_1000MBPS_FULL_DUPLEX;
  845. } else if (full_duplex[index]) {
  846. pDevice->RequestedMediaType =
  847. LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS_FULL_DUPLEX;
  848. } else {
  849. pDevice->RequestedMediaType =
  850. LM_REQUESTED_MEDIA_TYPE_UTP_1000MBPS;
  851. }
  852. if (!pDevice->EnableTbi)
  853. pDevice->DisableAutoNeg = FALSE;
  854. } else if (line_speed[index] == 100) {
  855. if (full_duplex[index]) {
  856. pDevice->RequestedMediaType =
  857. LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS_FULL_DUPLEX;
  858. } else {
  859. pDevice->RequestedMediaType =
  860. LM_REQUESTED_MEDIA_TYPE_UTP_100MBPS;
  861. }
  862. } else if (line_speed[index] == 10) {
  863. if (full_duplex[index]) {
  864. pDevice->RequestedMediaType =
  865. LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS_FULL_DUPLEX;
  866. } else {
  867. pDevice->RequestedMediaType =
  868. LM_REQUESTED_MEDIA_TYPE_UTP_10MBPS;
  869. }
  870. } else {
  871. pDevice->RequestedMediaType =
  872. LM_REQUESTED_MEDIA_TYPE_AUTO;
  873. pDevice->DisableAutoNeg = FALSE;
  874. }
  875. }
  876. pDevice->FlowControlCap = 0;
  877. if (rx_flow_control[index] != 0) {
  878. pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE;
  879. }
  880. if (tx_flow_control[index] != 0) {
  881. pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE;
  882. }
  883. if ((auto_flow_control[index] != 0) &&
  884. (pDevice->DisableAutoNeg == FALSE)) {
  885. pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE;
  886. if ((tx_flow_control[index] == 0) &&
  887. (rx_flow_control[index] == 0)) {
  888. pDevice->FlowControlCap |=
  889. LM_FLOW_CONTROL_TRANSMIT_PAUSE |
  890. LM_FLOW_CONTROL_RECEIVE_PAUSE;
  891. }
  892. }
  893. /* Default MTU for now */
  894. pUmDevice->mtu = 1500;
  895. #if T3_JUMBO_RCV_RCB_ENTRY_COUNT
  896. if (pUmDevice->mtu > 1500) {
  897. pDevice->RxMtu = pUmDevice->mtu;
  898. pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT;
  899. } else {
  900. pDevice->RxJumboDescCnt = 0;
  901. }
  902. pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index];
  903. #else
  904. pDevice->RxMtu = pUmDevice->mtu;
  905. #endif
  906. if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) {
  907. pDevice->UseTaggedStatus = TRUE;
  908. pUmDevice->timer_interval = CFG_HZ;
  909. } else {
  910. pUmDevice->timer_interval = CFG_HZ / 50;
  911. }
  912. pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index];
  913. pDevice->RxStdDescCnt = rx_std_desc_cnt[index];
  914. /* Note: adaptive coalescence really isn't adaptive in this driver */
  915. pUmDevice->rx_adaptive_coalesce = rx_adaptive_coalesce[index];
  916. if (!pUmDevice->rx_adaptive_coalesce) {
  917. pDevice->RxCoalescingTicks = rx_coalesce_ticks[index];
  918. if (pDevice->RxCoalescingTicks > MAX_RX_COALESCING_TICKS)
  919. pDevice->RxCoalescingTicks = MAX_RX_COALESCING_TICKS;
  920. pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks;
  921. pDevice->RxMaxCoalescedFrames = rx_max_coalesce_frames[index];
  922. if (pDevice->RxMaxCoalescedFrames > MAX_RX_MAX_COALESCED_FRAMES)
  923. pDevice->RxMaxCoalescedFrames =
  924. MAX_RX_MAX_COALESCED_FRAMES;
  925. pUmDevice->rx_curr_coalesce_frames =
  926. pDevice->RxMaxCoalescedFrames;
  927. pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index];
  928. if (pDevice->StatsCoalescingTicks > MAX_STATS_COALESCING_TICKS)
  929. pDevice->StatsCoalescingTicks =
  930. MAX_STATS_COALESCING_TICKS;
  931. } else {
  932. pUmDevice->rx_curr_coalesce_frames =
  933. DEFAULT_RX_MAX_COALESCED_FRAMES;
  934. pUmDevice->rx_curr_coalesce_ticks = DEFAULT_RX_COALESCING_TICKS;
  935. }
  936. pDevice->TxCoalescingTicks = tx_coalesce_ticks[index];
  937. if (pDevice->TxCoalescingTicks > MAX_TX_COALESCING_TICKS)
  938. pDevice->TxCoalescingTicks = MAX_TX_COALESCING_TICKS;
  939. pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index];
  940. if (pDevice->TxMaxCoalescedFrames > MAX_TX_MAX_COALESCED_FRAMES)
  941. pDevice->TxMaxCoalescedFrames = MAX_TX_MAX_COALESCED_FRAMES;
  942. if (enable_wol[index]) {
  943. pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET;
  944. pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET;
  945. }
  946. pDevice->NicSendBd = TRUE;
  947. /* Don't update status blocks during interrupt */
  948. pDevice->RxCoalescingTicksDuringInt = 0;
  949. pDevice->TxCoalescingTicksDuringInt = 0;
  950. return LM_STATUS_SUCCESS;
  951. }
  952. LM_STATUS MM_StartTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
  953. {
  954. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  955. printf ("Start TX DMA: dev=%d packet @0x%x\n",
  956. (int)pUmDevice->index, (unsigned int)pPacket);
  957. return LM_STATUS_SUCCESS;
  958. }
  959. LM_STATUS MM_CompleteTxDma (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
  960. {
  961. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  962. printf ("Complete TX DMA: dev=%d packet @0x%x\n",
  963. (int)pUmDevice->index, (unsigned int)pPacket);
  964. return LM_STATUS_SUCCESS;
  965. }
  966. LM_STATUS MM_IndicateStatus (PLM_DEVICE_BLOCK pDevice, LM_STATUS Status)
  967. {
  968. char buf[128];
  969. char lcd[4];
  970. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  971. LM_FLOW_CONTROL flow_control;
  972. pUmDevice->delayed_link_ind = 0;
  973. memset (lcd, 0x0, 4);
  974. if (Status == LM_STATUS_LINK_DOWN) {
  975. sprintf (buf, "eth%d: %s: NIC Link is down\n",
  976. pUmDevice->index, pUmDevice->name);
  977. lcd[0] = 'L';
  978. lcd[1] = 'N';
  979. lcd[2] = 'K';
  980. lcd[3] = '?';
  981. } else if (Status == LM_STATUS_LINK_ACTIVE) {
  982. sprintf (buf, "eth%d:%s: ", pUmDevice->index, pUmDevice->name);
  983. if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) {
  984. strcat (buf, "1000 Mbps ");
  985. lcd[0] = '1';
  986. lcd[1] = 'G';
  987. lcd[2] = 'B';
  988. } else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) {
  989. strcat (buf, "100 Mbps ");
  990. lcd[0] = '1';
  991. lcd[1] = '0';
  992. lcd[2] = '0';
  993. } else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) {
  994. strcat (buf, "10 Mbps ");
  995. lcd[0] = '1';
  996. lcd[1] = '0';
  997. lcd[2] = ' ';
  998. }
  999. if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) {
  1000. strcat (buf, "full duplex");
  1001. lcd[3] = 'F';
  1002. } else {
  1003. strcat (buf, "half duplex");
  1004. lcd[3] = 'H';
  1005. }
  1006. strcat (buf, " link up");
  1007. flow_control = pDevice->FlowControl &
  1008. (LM_FLOW_CONTROL_RECEIVE_PAUSE |
  1009. LM_FLOW_CONTROL_TRANSMIT_PAUSE);
  1010. if (flow_control) {
  1011. if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) {
  1012. strcat (buf, ", receive ");
  1013. if (flow_control &
  1014. LM_FLOW_CONTROL_TRANSMIT_PAUSE)
  1015. strcat (buf, " & transmit ");
  1016. } else {
  1017. strcat (buf, ", transmit ");
  1018. }
  1019. strcat (buf, "flow control ON");
  1020. } else {
  1021. strcat (buf, ", flow control OFF");
  1022. }
  1023. strcat (buf, "\n");
  1024. printf ("%s", buf);
  1025. }
  1026. #if 0
  1027. sysLedDsply (lcd[0], lcd[1], lcd[2], lcd[3]);
  1028. #endif
  1029. return LM_STATUS_SUCCESS;
  1030. }
  1031. LM_STATUS MM_FreeRxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
  1032. {
  1033. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  1034. PUM_PACKET pUmPacket;
  1035. void *skb;
  1036. pUmPacket = (PUM_PACKET) pPacket;
  1037. if ((skb = pUmPacket->skbuff))
  1038. bcm570xPktFree (pUmDevice->index, skb);
  1039. pUmPacket->skbuff = 0;
  1040. return LM_STATUS_SUCCESS;
  1041. }
  1042. unsigned long MM_AnGetCurrentTime_us (PAN_STATE_INFO pAnInfo)
  1043. {
  1044. return get_timer (0);
  1045. }
  1046. /*
  1047. * Transform an MBUF chain into a single MBUF.
  1048. * This routine will fail if the amount of data in the
  1049. * chain overflows a transmit buffer. In that case,
  1050. * the incoming MBUF chain will be freed. This routine can
  1051. * also fail by not being able to allocate a new MBUF (including
  1052. * cluster and mbuf headers). In that case the failure is
  1053. * non-fatal. The incoming cluster chain is not freed, giving
  1054. * the caller the choice of whether to try a retransmit later.
  1055. */
  1056. LM_STATUS MM_CoalesceTxBuffer (PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket)
  1057. {
  1058. PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
  1059. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  1060. void *skbnew;
  1061. int len = 0;
  1062. if (len == 0)
  1063. return (LM_STATUS_SUCCESS);
  1064. if (len > MAX_PACKET_SIZE) {
  1065. printf ("eth%d: xmit frame discarded, too big!, size = %d\n",
  1066. pUmDevice->index, len);
  1067. return (LM_STATUS_FAILURE);
  1068. }
  1069. skbnew = bcm570xPktAlloc (pUmDevice->index, MAX_PACKET_SIZE);
  1070. if (skbnew == NULL) {
  1071. pUmDevice->tx_full = 1;
  1072. printf ("eth%d: out of transmit buffers", pUmDevice->index);
  1073. return (LM_STATUS_FAILURE);
  1074. }
  1075. /* New packet values */
  1076. pUmPacket->skbuff = skbnew;
  1077. pUmPacket->lm_packet.u.Tx.FragCount = 1;
  1078. return (LM_STATUS_SUCCESS);
  1079. }
  1080. LM_STATUS MM_IndicateRxPackets (PLM_DEVICE_BLOCK pDevice)
  1081. {
  1082. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  1083. pUmDevice->rx_pkt = 1;
  1084. return LM_STATUS_SUCCESS;
  1085. }
  1086. LM_STATUS MM_IndicateTxPackets (PLM_DEVICE_BLOCK pDevice)
  1087. {
  1088. PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice;
  1089. PLM_PACKET pPacket;
  1090. PUM_PACKET pUmPacket;
  1091. void *skb;
  1092. while (TRUE) {
  1093. pPacket = (PLM_PACKET)
  1094. QQ_PopHead (&pDevice->TxPacketXmittedQ.Container);
  1095. if (pPacket == 0)
  1096. break;
  1097. pUmPacket = (PUM_PACKET) pPacket;
  1098. skb = (void *)pUmPacket->skbuff;
  1099. /*
  1100. * Free MBLK if we transmitted a fragmented packet or a
  1101. * non-fragmented packet straight from the VxWorks
  1102. * buffer pool. If packet was copied to a local transmit
  1103. * buffer, then there's no MBUF to free, just free
  1104. * the transmit buffer back to the cluster pool.
  1105. */
  1106. if (skb)
  1107. bcm570xPktFree (pUmDevice->index, skb);
  1108. pUmPacket->skbuff = 0;
  1109. QQ_PushTail (&pDevice->TxPacketFreeQ.Container, pPacket);
  1110. pUmDevice->tx_pkt = 1;
  1111. }
  1112. if (pUmDevice->tx_full) {
  1113. if (QQ_GetEntryCnt (&pDevice->TxPacketFreeQ.Container) >=
  1114. (QQ_GetSize (&pDevice->TxPacketFreeQ.Container) >> 1))
  1115. pUmDevice->tx_full = 0;
  1116. }
  1117. return LM_STATUS_SUCCESS;
  1118. }
  1119. /*
  1120. * Scan an MBUF chain until we reach fragment number "frag"
  1121. * Return its length and physical address.
  1122. */
  1123. void MM_MapTxDma
  1124. (PLM_DEVICE_BLOCK pDevice,
  1125. struct _LM_PACKET *pPacket,
  1126. T3_64BIT_HOST_ADDR * paddr, LM_UINT32 * len, int frag) {
  1127. PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
  1128. *len = pPacket->PacketSize;
  1129. MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
  1130. }
  1131. /*
  1132. * Convert an mbuf address, a CPU local virtual address,
  1133. * to a physical address as seen from a PCI device. Store the
  1134. * result at paddr.
  1135. */
  1136. void MM_MapRxDma (PLM_DEVICE_BLOCK pDevice,
  1137. struct _LM_PACKET *pPacket, T3_64BIT_HOST_ADDR * paddr)
  1138. {
  1139. PUM_PACKET pUmPacket = (PUM_PACKET) pPacket;
  1140. MM_SetT3Addr (paddr, (dma_addr_t) pUmPacket->skbuff);
  1141. }
  1142. void MM_SetAddr (LM_PHYSICAL_ADDRESS * paddr, dma_addr_t addr)
  1143. {
  1144. #if (BITS_PER_LONG == 64)
  1145. paddr->High = ((unsigned long)addr) >> 32;
  1146. paddr->Low = ((unsigned long)addr) & 0xffffffff;
  1147. #else
  1148. paddr->High = 0;
  1149. paddr->Low = (unsigned long)addr;
  1150. #endif
  1151. }
  1152. void MM_SetT3Addr (T3_64BIT_HOST_ADDR * paddr, dma_addr_t addr)
  1153. {
  1154. unsigned long baddr = (unsigned long)addr;
  1155. #if (BITS_PER_LONG == 64)
  1156. set_64bit_addr (paddr, baddr & 0xffffffff, baddr >> 32);
  1157. #else
  1158. set_64bit_addr (paddr, baddr, 0);
  1159. #endif
  1160. }
  1161. /*
  1162. * This combination of `inline' and `extern' has almost the effect of a
  1163. * macro. The way to use it is to put a function definition in a header
  1164. * file with these keywords, and put another copy of the definition
  1165. * (lacking `inline' and `extern') in a library file. The definition in
  1166. * the header file will cause most calls to the function to be inlined.
  1167. * If any uses of the function remain, they will refer to the single copy
  1168. * in the library.
  1169. */
  1170. void atomic_set (atomic_t * entry, int val)
  1171. {
  1172. entry->counter = val;
  1173. }
  1174. int atomic_read (atomic_t * entry)
  1175. {
  1176. return entry->counter;
  1177. }
  1178. void atomic_inc (atomic_t * entry)
  1179. {
  1180. if (entry)
  1181. entry->counter++;
  1182. }
  1183. void atomic_dec (atomic_t * entry)
  1184. {
  1185. if (entry)
  1186. entry->counter--;
  1187. }
  1188. void atomic_sub (int a, atomic_t * entry)
  1189. {
  1190. if (entry)
  1191. entry->counter -= a;
  1192. }
  1193. void atomic_add (int a, atomic_t * entry)
  1194. {
  1195. if (entry)
  1196. entry->counter += a;
  1197. }
  1198. /******************************************************************************/
  1199. /* Description: */
  1200. /* */
  1201. /* Return: */
  1202. /******************************************************************************/
  1203. void QQ_InitQueue (PQQ_CONTAINER pQueue, unsigned int QueueSize)
  1204. {
  1205. pQueue->Head = 0;
  1206. pQueue->Tail = 0;
  1207. pQueue->Size = QueueSize + 1;
  1208. atomic_set (&pQueue->EntryCnt, 0);
  1209. } /* QQ_InitQueue */
  1210. /******************************************************************************/
  1211. /* Description: */
  1212. /* */
  1213. /* Return: */
  1214. /******************************************************************************/
  1215. char QQ_Full (PQQ_CONTAINER pQueue)
  1216. {
  1217. unsigned int NewHead;
  1218. NewHead = (pQueue->Head + 1) % pQueue->Size;
  1219. return (NewHead == pQueue->Tail);
  1220. } /* QQ_Full */
  1221. /******************************************************************************/
  1222. /* Description: */
  1223. /* */
  1224. /* Return: */
  1225. /******************************************************************************/
  1226. char QQ_Empty (PQQ_CONTAINER pQueue)
  1227. {
  1228. return (pQueue->Head == pQueue->Tail);
  1229. } /* QQ_Empty */
  1230. /******************************************************************************/
  1231. /* Description: */
  1232. /* */
  1233. /* Return: */
  1234. /******************************************************************************/
  1235. unsigned int QQ_GetSize (PQQ_CONTAINER pQueue)
  1236. {
  1237. return pQueue->Size;
  1238. } /* QQ_GetSize */
  1239. /******************************************************************************/
  1240. /* Description: */
  1241. /* */
  1242. /* Return: */
  1243. /******************************************************************************/
  1244. unsigned int QQ_GetEntryCnt (PQQ_CONTAINER pQueue)
  1245. {
  1246. return atomic_read (&pQueue->EntryCnt);
  1247. } /* QQ_GetEntryCnt */
  1248. /******************************************************************************/
  1249. /* Description: */
  1250. /* */
  1251. /* Return: */
  1252. /* TRUE entry was added successfully. */
  1253. /* FALSE queue is full. */
  1254. /******************************************************************************/
  1255. char QQ_PushHead (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
  1256. {
  1257. unsigned int Head;
  1258. Head = (pQueue->Head + 1) % pQueue->Size;
  1259. #if !defined(QQ_NO_OVERFLOW_CHECK)
  1260. if (Head == pQueue->Tail) {
  1261. return 0;
  1262. } /* if */
  1263. #endif /* QQ_NO_OVERFLOW_CHECK */
  1264. pQueue->Array[pQueue->Head] = pEntry;
  1265. wmb ();
  1266. pQueue->Head = Head;
  1267. atomic_inc (&pQueue->EntryCnt);
  1268. return -1;
  1269. } /* QQ_PushHead */
  1270. /******************************************************************************/
  1271. /* Description: */
  1272. /* */
  1273. /* Return: */
  1274. /* TRUE entry was added successfully. */
  1275. /* FALSE queue is full. */
  1276. /******************************************************************************/
  1277. char QQ_PushTail (PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry)
  1278. {
  1279. unsigned int Tail;
  1280. Tail = pQueue->Tail;
  1281. if (Tail == 0) {
  1282. Tail = pQueue->Size;
  1283. } /* if */
  1284. Tail--;
  1285. #if !defined(QQ_NO_OVERFLOW_CHECK)
  1286. if (Tail == pQueue->Head) {
  1287. return 0;
  1288. } /* if */
  1289. #endif /* QQ_NO_OVERFLOW_CHECK */
  1290. pQueue->Array[Tail] = pEntry;
  1291. wmb ();
  1292. pQueue->Tail = Tail;
  1293. atomic_inc (&pQueue->EntryCnt);
  1294. return -1;
  1295. } /* QQ_PushTail */
  1296. /******************************************************************************/
  1297. /* Description: */
  1298. /* */
  1299. /* Return: */
  1300. /******************************************************************************/
  1301. PQQ_ENTRY QQ_PopHead (PQQ_CONTAINER pQueue)
  1302. {
  1303. unsigned int Head;
  1304. PQQ_ENTRY Entry;
  1305. Head = pQueue->Head;
  1306. #if !defined(QQ_NO_UNDERFLOW_CHECK)
  1307. if (Head == pQueue->Tail) {
  1308. return (PQQ_ENTRY) 0;
  1309. } /* if */
  1310. #endif /* QQ_NO_UNDERFLOW_CHECK */
  1311. if (Head == 0) {
  1312. Head = pQueue->Size;
  1313. } /* if */
  1314. Head--;
  1315. Entry = pQueue->Array[Head];
  1316. membar ();
  1317. pQueue->Head = Head;
  1318. atomic_dec (&pQueue->EntryCnt);
  1319. return Entry;
  1320. } /* QQ_PopHead */
  1321. /******************************************************************************/
  1322. /* Description: */
  1323. /* */
  1324. /* Return: */
  1325. /******************************************************************************/
  1326. PQQ_ENTRY QQ_PopTail (PQQ_CONTAINER pQueue)
  1327. {
  1328. unsigned int Tail;
  1329. PQQ_ENTRY Entry;
  1330. Tail = pQueue->Tail;
  1331. #if !defined(QQ_NO_UNDERFLOW_CHECK)
  1332. if (Tail == pQueue->Head) {
  1333. return (PQQ_ENTRY) 0;
  1334. } /* if */
  1335. #endif /* QQ_NO_UNDERFLOW_CHECK */
  1336. Entry = pQueue->Array[Tail];
  1337. membar ();
  1338. pQueue->Tail = (Tail + 1) % pQueue->Size;
  1339. atomic_dec (&pQueue->EntryCnt);
  1340. return Entry;
  1341. } /* QQ_PopTail */
  1342. /******************************************************************************/
  1343. /* Description: */
  1344. /* */
  1345. /* Return: */
  1346. /******************************************************************************/
  1347. PQQ_ENTRY QQ_GetHead (PQQ_CONTAINER pQueue, unsigned int Idx)
  1348. {
  1349. if (Idx >= atomic_read (&pQueue->EntryCnt)) {
  1350. return (PQQ_ENTRY) 0;
  1351. }
  1352. if (pQueue->Head > Idx) {
  1353. Idx = pQueue->Head - Idx;
  1354. } else {
  1355. Idx = pQueue->Size - (Idx - pQueue->Head);
  1356. }
  1357. Idx--;
  1358. return pQueue->Array[Idx];
  1359. }
  1360. /******************************************************************************/
  1361. /* Description: */
  1362. /* */
  1363. /* Return: */
  1364. /******************************************************************************/
  1365. PQQ_ENTRY QQ_GetTail (PQQ_CONTAINER pQueue, unsigned int Idx)
  1366. {
  1367. if (Idx >= atomic_read (&pQueue->EntryCnt)) {
  1368. return (PQQ_ENTRY) 0;
  1369. }
  1370. Idx += pQueue->Tail;
  1371. if (Idx >= pQueue->Size) {
  1372. Idx = Idx - pQueue->Size;
  1373. }
  1374. return pQueue->Array[Idx];
  1375. }
  1376. #endif