diff options
Diffstat (limited to 'drivers/net/fs_enet/fs_enet-main.c')
-rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 258 |
1 files changed, 241 insertions, 17 deletions
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index 7a0298687875..fc4fda805d44 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
@@ -42,12 +42,18 @@ | |||
42 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | 44 | ||
45 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | ||
46 | #include <asm/of_platform.h> | ||
47 | #endif | ||
48 | |||
45 | #include "fs_enet.h" | 49 | #include "fs_enet.h" |
46 | 50 | ||
47 | /*************************************************/ | 51 | /*************************************************/ |
48 | 52 | ||
53 | #ifndef CONFIG_PPC_CPM_NEW_BINDING | ||
49 | static char version[] __devinitdata = | 54 | static char version[] __devinitdata = |
50 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; | 55 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; |
56 | #endif | ||
51 | 57 | ||
52 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); | 58 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); |
53 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | 59 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); |
@@ -948,6 +954,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
948 | extern int fs_mii_connect(struct net_device *dev); | 954 | extern int fs_mii_connect(struct net_device *dev); |
949 | extern void fs_mii_disconnect(struct net_device *dev); | 955 | extern void fs_mii_disconnect(struct net_device *dev); |
950 | 956 | ||
957 | #ifndef CONFIG_PPC_CPM_NEW_BINDING | ||
951 | static struct net_device *fs_init_instance(struct device *dev, | 958 | static struct net_device *fs_init_instance(struct device *dev, |
952 | struct fs_platform_info *fpi) | 959 | struct fs_platform_info *fpi) |
953 | { | 960 | { |
@@ -1129,6 +1136,7 @@ static int fs_cleanup_instance(struct net_device *ndev) | |||
1129 | 1136 | ||
1130 | return 0; | 1137 | return 0; |
1131 | } | 1138 | } |
1139 | #endif | ||
1132 | 1140 | ||
1133 | /**************************************************************************************/ | 1141 | /**************************************************************************************/ |
1134 | 1142 | ||
@@ -1137,35 +1145,250 @@ void *fs_enet_immap = NULL; | |||
1137 | 1145 | ||
1138 | static int setup_immap(void) | 1146 | static int setup_immap(void) |
1139 | { | 1147 | { |
1140 | phys_addr_t paddr = 0; | ||
1141 | unsigned long size = 0; | ||
1142 | |||
1143 | #ifdef CONFIG_CPM1 | 1148 | #ifdef CONFIG_CPM1 |
1144 | paddr = IMAP_ADDR; | 1149 | fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); |
1145 | size = 0x10000; /* map 64K */ | 1150 | WARN_ON(!fs_enet_immap); |
1146 | #endif | 1151 | #elif defined(CONFIG_CPM2) |
1147 | 1152 | fs_enet_immap = cpm2_immr; | |
1148 | #ifdef CONFIG_CPM2 | ||
1149 | paddr = CPM_MAP_ADDR; | ||
1150 | size = 0x40000; /* map 256 K */ | ||
1151 | #endif | 1153 | #endif |
1152 | fs_enet_immap = ioremap(paddr, size); | ||
1153 | if (fs_enet_immap == NULL) | ||
1154 | return -EBADF; /* XXX ahem; maybe just BUG_ON? */ | ||
1155 | 1154 | ||
1156 | return 0; | 1155 | return 0; |
1157 | } | 1156 | } |
1158 | 1157 | ||
1159 | static void cleanup_immap(void) | 1158 | static void cleanup_immap(void) |
1160 | { | 1159 | { |
1161 | if (fs_enet_immap != NULL) { | 1160 | #if defined(CONFIG_CPM1) |
1162 | iounmap(fs_enet_immap); | 1161 | iounmap(fs_enet_immap); |
1163 | fs_enet_immap = NULL; | 1162 | #endif |
1164 | } | ||
1165 | } | 1163 | } |
1166 | 1164 | ||
1167 | /**************************************************************************************/ | 1165 | /**************************************************************************************/ |
1168 | 1166 | ||
1167 | #ifdef CONFIG_PPC_CPM_NEW_BINDING | ||
1168 | static int __devinit find_phy(struct device_node *np, | ||
1169 | struct fs_platform_info *fpi) | ||
1170 | { | ||
1171 | struct device_node *phynode, *mdionode; | ||
1172 | struct resource res; | ||
1173 | int ret = 0, len; | ||
1174 | |||
1175 | const u32 *data = of_get_property(np, "phy-handle", &len); | ||
1176 | if (!data || len != 4) | ||
1177 | return -EINVAL; | ||
1178 | |||
1179 | phynode = of_find_node_by_phandle(*data); | ||
1180 | if (!phynode) | ||
1181 | return -EINVAL; | ||
1182 | |||
1183 | mdionode = of_get_parent(phynode); | ||
1184 | if (!mdionode) | ||
1185 | goto out_put_phy; | ||
1186 | |||
1187 | ret = of_address_to_resource(mdionode, 0, &res); | ||
1188 | if (ret) | ||
1189 | goto out_put_mdio; | ||
1190 | |||
1191 | data = of_get_property(phynode, "reg", &len); | ||
1192 | if (!data || len != 4) | ||
1193 | goto out_put_mdio; | ||
1194 | |||
1195 | snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data); | ||
1196 | |||
1197 | out_put_mdio: | ||
1198 | of_node_put(mdionode); | ||
1199 | out_put_phy: | ||
1200 | of_node_put(phynode); | ||
1201 | return ret; | ||
1202 | } | ||
1203 | |||
1204 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
1205 | #define IS_FEC(match) ((match)->data == &fs_fec_ops) | ||
1206 | #else | ||
1207 | #define IS_FEC(match) 0 | ||
1208 | #endif | ||
1209 | |||
1210 | static int __devinit fs_enet_probe(struct of_device *ofdev, | ||
1211 | const struct of_device_id *match) | ||
1212 | { | ||
1213 | struct net_device *ndev; | ||
1214 | struct fs_enet_private *fep; | ||
1215 | struct fs_platform_info *fpi; | ||
1216 | const u32 *data; | ||
1217 | const u8 *mac_addr; | ||
1218 | int privsize, len, ret = -ENODEV; | ||
1219 | |||
1220 | fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); | ||
1221 | if (!fpi) | ||
1222 | return -ENOMEM; | ||
1223 | |||
1224 | if (!IS_FEC(match)) { | ||
1225 | data = of_get_property(ofdev->node, "fsl,cpm-command", &len); | ||
1226 | if (!data || len != 4) | ||
1227 | goto out_free_fpi; | ||
1228 | |||
1229 | fpi->cp_command = *data; | ||
1230 | } | ||
1231 | |||
1232 | fpi->rx_ring = 32; | ||
1233 | fpi->tx_ring = 32; | ||
1234 | fpi->rx_copybreak = 240; | ||
1235 | fpi->use_napi = 0; | ||
1236 | fpi->napi_weight = 17; | ||
1237 | |||
1238 | ret = find_phy(ofdev->node, fpi); | ||
1239 | if (ret) | ||
1240 | goto out_free_fpi; | ||
1241 | |||
1242 | privsize = sizeof(*fep) + | ||
1243 | sizeof(struct sk_buff **) * | ||
1244 | (fpi->rx_ring + fpi->tx_ring); | ||
1245 | |||
1246 | ndev = alloc_etherdev(privsize); | ||
1247 | if (!ndev) { | ||
1248 | ret = -ENOMEM; | ||
1249 | goto out_free_fpi; | ||
1250 | } | ||
1251 | |||
1252 | SET_MODULE_OWNER(ndev); | ||
1253 | dev_set_drvdata(&ofdev->dev, ndev); | ||
1254 | |||
1255 | fep = netdev_priv(ndev); | ||
1256 | fep->dev = &ofdev->dev; | ||
1257 | fep->fpi = fpi; | ||
1258 | fep->ops = match->data; | ||
1259 | |||
1260 | ret = fep->ops->setup_data(ndev); | ||
1261 | if (ret) | ||
1262 | goto out_free_dev; | ||
1263 | |||
1264 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | ||
1265 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | ||
1266 | |||
1267 | spin_lock_init(&fep->lock); | ||
1268 | spin_lock_init(&fep->tx_lock); | ||
1269 | |||
1270 | mac_addr = of_get_mac_address(ofdev->node); | ||
1271 | if (mac_addr) | ||
1272 | memcpy(ndev->dev_addr, mac_addr, 6); | ||
1273 | |||
1274 | ret = fep->ops->allocate_bd(ndev); | ||
1275 | if (ret) | ||
1276 | goto out_cleanup_data; | ||
1277 | |||
1278 | fep->rx_bd_base = fep->ring_base; | ||
1279 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | ||
1280 | |||
1281 | fep->tx_ring = fpi->tx_ring; | ||
1282 | fep->rx_ring = fpi->rx_ring; | ||
1283 | |||
1284 | ndev->open = fs_enet_open; | ||
1285 | ndev->hard_start_xmit = fs_enet_start_xmit; | ||
1286 | ndev->tx_timeout = fs_timeout; | ||
1287 | ndev->watchdog_timeo = 2 * HZ; | ||
1288 | ndev->stop = fs_enet_close; | ||
1289 | ndev->get_stats = fs_enet_get_stats; | ||
1290 | ndev->set_multicast_list = fs_set_multicast_list; | ||
1291 | if (fpi->use_napi) { | ||
1292 | ndev->poll = fs_enet_rx_napi; | ||
1293 | ndev->weight = fpi->napi_weight; | ||
1294 | } | ||
1295 | ndev->ethtool_ops = &fs_ethtool_ops; | ||
1296 | ndev->do_ioctl = fs_ioctl; | ||
1297 | |||
1298 | init_timer(&fep->phy_timer_list); | ||
1299 | |||
1300 | netif_carrier_off(ndev); | ||
1301 | |||
1302 | ret = register_netdev(ndev); | ||
1303 | if (ret) | ||
1304 | goto out_free_bd; | ||
1305 | |||
1306 | printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1307 | ndev->name, | ||
1308 | ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], | ||
1309 | ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); | ||
1310 | |||
1311 | return 0; | ||
1312 | |||
1313 | out_free_bd: | ||
1314 | fep->ops->free_bd(ndev); | ||
1315 | out_cleanup_data: | ||
1316 | fep->ops->cleanup_data(ndev); | ||
1317 | out_free_dev: | ||
1318 | free_netdev(ndev); | ||
1319 | dev_set_drvdata(&ofdev->dev, NULL); | ||
1320 | out_free_fpi: | ||
1321 | kfree(fpi); | ||
1322 | return ret; | ||
1323 | } | ||
1324 | |||
1325 | static int fs_enet_remove(struct of_device *ofdev) | ||
1326 | { | ||
1327 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | ||
1328 | struct fs_enet_private *fep = netdev_priv(ndev); | ||
1329 | |||
1330 | unregister_netdev(ndev); | ||
1331 | |||
1332 | fep->ops->free_bd(ndev); | ||
1333 | fep->ops->cleanup_data(ndev); | ||
1334 | dev_set_drvdata(fep->dev, NULL); | ||
1335 | |||
1336 | free_netdev(ndev); | ||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | static struct of_device_id fs_enet_match[] = { | ||
1341 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
1342 | { | ||
1343 | .compatible = "fsl,cpm1-scc-enet", | ||
1344 | .data = (void *)&fs_scc_ops, | ||
1345 | }, | ||
1346 | #endif | ||
1347 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
1348 | { | ||
1349 | .compatible = "fsl,cpm2-fcc-enet", | ||
1350 | .data = (void *)&fs_fcc_ops, | ||
1351 | }, | ||
1352 | #endif | ||
1353 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
1354 | { | ||
1355 | .compatible = "fsl,pq1-fec-enet", | ||
1356 | .data = (void *)&fs_fec_ops, | ||
1357 | }, | ||
1358 | #endif | ||
1359 | {} | ||
1360 | }; | ||
1361 | |||
1362 | static struct of_platform_driver fs_enet_driver = { | ||
1363 | .name = "fs_enet", | ||
1364 | .match_table = fs_enet_match, | ||
1365 | .probe = fs_enet_probe, | ||
1366 | .remove = fs_enet_remove, | ||
1367 | }; | ||
1368 | |||
1369 | static int __init fs_init(void) | ||
1370 | { | ||
1371 | int r = setup_immap(); | ||
1372 | if (r != 0) | ||
1373 | return r; | ||
1374 | |||
1375 | r = of_register_platform_driver(&fs_enet_driver); | ||
1376 | if (r != 0) | ||
1377 | goto out; | ||
1378 | |||
1379 | return 0; | ||
1380 | |||
1381 | out: | ||
1382 | cleanup_immap(); | ||
1383 | return r; | ||
1384 | } | ||
1385 | |||
1386 | static void __exit fs_cleanup(void) | ||
1387 | { | ||
1388 | of_unregister_platform_driver(&fs_enet_driver); | ||
1389 | cleanup_immap(); | ||
1390 | } | ||
1391 | #else | ||
1169 | static int __devinit fs_enet_probe(struct device *dev) | 1392 | static int __devinit fs_enet_probe(struct device *dev) |
1170 | { | 1393 | { |
1171 | struct net_device *ndev; | 1394 | struct net_device *ndev; |
@@ -1279,6 +1502,7 @@ static void __exit fs_cleanup(void) | |||
1279 | driver_unregister(&fs_enet_scc_driver); | 1502 | driver_unregister(&fs_enet_scc_driver); |
1280 | cleanup_immap(); | 1503 | cleanup_immap(); |
1281 | } | 1504 | } |
1505 | #endif | ||
1282 | 1506 | ||
1283 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1507 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1284 | static void fs_enet_netpoll(struct net_device *dev) | 1508 | static void fs_enet_netpoll(struct net_device *dev) |