diff options
Diffstat (limited to 'drivers/net/ibmveth.c')
-rw-r--r-- | drivers/net/ibmveth.c | 211 |
1 files changed, 168 insertions, 43 deletions
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 52d01027d9e7..71c74fb048dd 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -96,6 +96,7 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); | |||
96 | static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); | 96 | static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); |
97 | static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); | 97 | static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs); |
98 | static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); | 98 | static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); |
99 | static struct kobj_type ktype_veth_pool; | ||
99 | 100 | ||
100 | #ifdef CONFIG_PROC_FS | 101 | #ifdef CONFIG_PROC_FS |
101 | #define IBMVETH_PROC_DIR "net/ibmveth" | 102 | #define IBMVETH_PROC_DIR "net/ibmveth" |
@@ -133,12 +134,13 @@ static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter) | |||
133 | } | 134 | } |
134 | 135 | ||
135 | /* setup the initial settings for a buffer pool */ | 136 | /* setup the initial settings for a buffer pool */ |
136 | static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size) | 137 | static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active) |
137 | { | 138 | { |
138 | pool->size = pool_size; | 139 | pool->size = pool_size; |
139 | pool->index = pool_index; | 140 | pool->index = pool_index; |
140 | pool->buff_size = buff_size; | 141 | pool->buff_size = buff_size; |
141 | pool->threshold = pool_size / 2; | 142 | pool->threshold = pool_size / 2; |
143 | pool->active = pool_active; | ||
142 | } | 144 | } |
143 | 145 | ||
144 | /* allocate and setup an buffer pool - called during open */ | 146 | /* allocate and setup an buffer pool - called during open */ |
@@ -180,7 +182,6 @@ static int ibmveth_alloc_buffer_pool(struct ibmveth_buff_pool *pool) | |||
180 | atomic_set(&pool->available, 0); | 182 | atomic_set(&pool->available, 0); |
181 | pool->producer_index = 0; | 183 | pool->producer_index = 0; |
182 | pool->consumer_index = 0; | 184 | pool->consumer_index = 0; |
183 | pool->active = 0; | ||
184 | 185 | ||
185 | return 0; | 186 | return 0; |
186 | } | 187 | } |
@@ -301,7 +302,6 @@ static void ibmveth_free_buffer_pool(struct ibmveth_adapter *adapter, struct ibm | |||
301 | kfree(pool->skbuff); | 302 | kfree(pool->skbuff); |
302 | pool->skbuff = NULL; | 303 | pool->skbuff = NULL; |
303 | } | 304 | } |
304 | pool->active = 0; | ||
305 | } | 305 | } |
306 | 306 | ||
307 | /* remove a buffer from a pool */ | 307 | /* remove a buffer from a pool */ |
@@ -433,7 +433,9 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) | |||
433 | } | 433 | } |
434 | 434 | ||
435 | for(i = 0; i<IbmVethNumBufferPools; i++) | 435 | for(i = 0; i<IbmVethNumBufferPools; i++) |
436 | ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[i]); | 436 | if (adapter->rx_buff_pool[i].active) |
437 | ibmveth_free_buffer_pool(adapter, | ||
438 | &adapter->rx_buff_pool[i]); | ||
437 | } | 439 | } |
438 | 440 | ||
439 | static int ibmveth_open(struct net_device *netdev) | 441 | static int ibmveth_open(struct net_device *netdev) |
@@ -489,9 +491,6 @@ static int ibmveth_open(struct net_device *netdev) | |||
489 | adapter->rx_queue.num_slots = rxq_entries; | 491 | adapter->rx_queue.num_slots = rxq_entries; |
490 | adapter->rx_queue.toggle = 1; | 492 | adapter->rx_queue.toggle = 1; |
491 | 493 | ||
492 | /* call change_mtu to init the buffer pools based in initial mtu */ | ||
493 | ibmveth_change_mtu(netdev, netdev->mtu); | ||
494 | |||
495 | memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); | 494 | memcpy(&mac_address, netdev->dev_addr, netdev->addr_len); |
496 | mac_address = mac_address >> 16; | 495 | mac_address = mac_address >> 16; |
497 | 496 | ||
@@ -522,6 +521,17 @@ static int ibmveth_open(struct net_device *netdev) | |||
522 | return -ENONET; | 521 | return -ENONET; |
523 | } | 522 | } |
524 | 523 | ||
524 | for(i = 0; i<IbmVethNumBufferPools; i++) { | ||
525 | if(!adapter->rx_buff_pool[i].active) | ||
526 | continue; | ||
527 | if (ibmveth_alloc_buffer_pool(&adapter->rx_buff_pool[i])) { | ||
528 | ibmveth_error_printk("unable to alloc pool\n"); | ||
529 | adapter->rx_buff_pool[i].active = 0; | ||
530 | ibmveth_cleanup(adapter); | ||
531 | return -ENOMEM ; | ||
532 | } | ||
533 | } | ||
534 | |||
525 | ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); | 535 | ibmveth_debug_printk("registering irq 0x%x\n", netdev->irq); |
526 | if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { | 536 | if((rc = request_irq(netdev->irq, &ibmveth_interrupt, 0, netdev->name, netdev)) != 0) { |
527 | ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); | 537 | ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); |
@@ -550,7 +560,8 @@ static int ibmveth_close(struct net_device *netdev) | |||
550 | 560 | ||
551 | ibmveth_debug_printk("close starting\n"); | 561 | ibmveth_debug_printk("close starting\n"); |
552 | 562 | ||
553 | netif_stop_queue(netdev); | 563 | if (!adapter->pool_config) |
564 | netif_stop_queue(netdev); | ||
554 | 565 | ||
555 | free_irq(netdev->irq, netdev); | 566 | free_irq(netdev->irq, netdev); |
556 | 567 | ||
@@ -876,46 +887,22 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) | |||
876 | static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) | 887 | static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) |
877 | { | 888 | { |
878 | struct ibmveth_adapter *adapter = dev->priv; | 889 | struct ibmveth_adapter *adapter = dev->priv; |
890 | int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; | ||
879 | int i; | 891 | int i; |
880 | int prev_smaller = 1; | ||
881 | 892 | ||
882 | if ((new_mtu < 68) || | 893 | if (new_mtu < IBMVETH_MAX_MTU) |
883 | (new_mtu > (pool_size[IbmVethNumBufferPools-1]) - IBMVETH_BUFF_OH)) | ||
884 | return -EINVAL; | 894 | return -EINVAL; |
885 | 895 | ||
896 | /* Look for an active buffer pool that can hold the new MTU */ | ||
886 | for(i = 0; i<IbmVethNumBufferPools; i++) { | 897 | for(i = 0; i<IbmVethNumBufferPools; i++) { |
887 | int activate = 0; | 898 | if (!adapter->rx_buff_pool[i].active) |
888 | if (new_mtu > (pool_size[i] - IBMVETH_BUFF_OH)) { | 899 | continue; |
889 | activate = 1; | 900 | if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) { |
890 | prev_smaller= 1; | 901 | dev->mtu = new_mtu; |
891 | } else { | 902 | return 0; |
892 | if (prev_smaller) | ||
893 | activate = 1; | ||
894 | prev_smaller= 0; | ||
895 | } | 903 | } |
896 | |||
897 | if (activate && !adapter->rx_buff_pool[i].active) { | ||
898 | struct ibmveth_buff_pool *pool = | ||
899 | &adapter->rx_buff_pool[i]; | ||
900 | if(ibmveth_alloc_buffer_pool(pool)) { | ||
901 | ibmveth_error_printk("unable to alloc pool\n"); | ||
902 | return -ENOMEM; | ||
903 | } | ||
904 | adapter->rx_buff_pool[i].active = 1; | ||
905 | } else if (!activate && adapter->rx_buff_pool[i].active) { | ||
906 | adapter->rx_buff_pool[i].active = 0; | ||
907 | h_free_logical_lan_buffer(adapter->vdev->unit_address, | ||
908 | (u64)pool_size[i]); | ||
909 | } | ||
910 | |||
911 | } | 904 | } |
912 | 905 | return -EINVAL; | |
913 | /* kick the interrupt handler so that the new buffer pools get | ||
914 | replenished or deallocated */ | ||
915 | ibmveth_interrupt(dev->irq, dev, NULL); | ||
916 | |||
917 | dev->mtu = new_mtu; | ||
918 | return 0; | ||
919 | } | 906 | } |
920 | 907 | ||
921 | static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) | 908 | static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) |
@@ -960,6 +947,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
960 | adapter->vdev = dev; | 947 | adapter->vdev = dev; |
961 | adapter->netdev = netdev; | 948 | adapter->netdev = netdev; |
962 | adapter->mcastFilterSize= *mcastFilterSize_p; | 949 | adapter->mcastFilterSize= *mcastFilterSize_p; |
950 | adapter->pool_config = 0; | ||
963 | 951 | ||
964 | /* Some older boxes running PHYP non-natively have an OF that | 952 | /* Some older boxes running PHYP non-natively have an OF that |
965 | returns a 8-byte local-mac-address field (and the first | 953 | returns a 8-byte local-mac-address field (and the first |
@@ -994,9 +982,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
994 | 982 | ||
995 | memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); | 983 | memcpy(&netdev->dev_addr, &adapter->mac_addr, netdev->addr_len); |
996 | 984 | ||
997 | for(i = 0; i<IbmVethNumBufferPools; i++) | 985 | for(i = 0; i<IbmVethNumBufferPools; i++) { |
986 | struct kobject *kobj = &adapter->rx_buff_pool[i].kobj; | ||
998 | ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, | 987 | ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, |
999 | pool_count[i], pool_size[i]); | 988 | pool_count[i], pool_size[i], |
989 | pool_active[i]); | ||
990 | kobj->parent = &dev->dev.kobj; | ||
991 | sprintf(kobj->name, "pool%d", i); | ||
992 | kobj->ktype = &ktype_veth_pool; | ||
993 | kobject_register(kobj); | ||
994 | } | ||
1000 | 995 | ||
1001 | ibmveth_debug_printk("adapter @ 0x%p\n", adapter); | 996 | ibmveth_debug_printk("adapter @ 0x%p\n", adapter); |
1002 | 997 | ||
@@ -1025,6 +1020,10 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) | |||
1025 | { | 1020 | { |
1026 | struct net_device *netdev = dev->dev.driver_data; | 1021 | struct net_device *netdev = dev->dev.driver_data; |
1027 | struct ibmveth_adapter *adapter = netdev->priv; | 1022 | struct ibmveth_adapter *adapter = netdev->priv; |
1023 | int i; | ||
1024 | |||
1025 | for(i = 0; i<IbmVethNumBufferPools; i++) | ||
1026 | kobject_unregister(&adapter->rx_buff_pool[i].kobj); | ||
1028 | 1027 | ||
1029 | unregister_netdev(netdev); | 1028 | unregister_netdev(netdev); |
1030 | 1029 | ||
@@ -1169,6 +1168,132 @@ static void ibmveth_proc_unregister_driver(void) | |||
1169 | } | 1168 | } |
1170 | #endif /* CONFIG_PROC_FS */ | 1169 | #endif /* CONFIG_PROC_FS */ |
1171 | 1170 | ||
1171 | static struct attribute veth_active_attr; | ||
1172 | static struct attribute veth_num_attr; | ||
1173 | static struct attribute veth_size_attr; | ||
1174 | |||
1175 | static ssize_t veth_pool_show(struct kobject * kobj, | ||
1176 | struct attribute * attr, char * buf) | ||
1177 | { | ||
1178 | struct ibmveth_buff_pool *pool = container_of(kobj, | ||
1179 | struct ibmveth_buff_pool, | ||
1180 | kobj); | ||
1181 | |||
1182 | if (attr == &veth_active_attr) | ||
1183 | return sprintf(buf, "%d\n", pool->active); | ||
1184 | else if (attr == &veth_num_attr) | ||
1185 | return sprintf(buf, "%d\n", pool->size); | ||
1186 | else if (attr == &veth_size_attr) | ||
1187 | return sprintf(buf, "%d\n", pool->buff_size); | ||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | static ssize_t veth_pool_store(struct kobject * kobj, struct attribute * attr, | ||
1192 | const char * buf, size_t count) | ||
1193 | { | ||
1194 | struct ibmveth_buff_pool *pool = container_of(kobj, | ||
1195 | struct ibmveth_buff_pool, | ||
1196 | kobj); | ||
1197 | struct net_device *netdev = | ||
1198 | container_of(kobj->parent, struct device, kobj)->driver_data; | ||
1199 | struct ibmveth_adapter *adapter = netdev->priv; | ||
1200 | long value = simple_strtol(buf, NULL, 10); | ||
1201 | long rc; | ||
1202 | |||
1203 | if (attr == &veth_active_attr) { | ||
1204 | if (value && !pool->active) { | ||
1205 | if(ibmveth_alloc_buffer_pool(pool)) { | ||
1206 | ibmveth_error_printk("unable to alloc pool\n"); | ||
1207 | return -ENOMEM; | ||
1208 | } | ||
1209 | pool->active = 1; | ||
1210 | adapter->pool_config = 1; | ||
1211 | ibmveth_close(netdev); | ||
1212 | adapter->pool_config = 0; | ||
1213 | if ((rc = ibmveth_open(netdev))) | ||
1214 | return rc; | ||
1215 | } else if (!value && pool->active) { | ||
1216 | int mtu = netdev->mtu + IBMVETH_BUFF_OH; | ||
1217 | int i; | ||
1218 | /* Make sure there is a buffer pool with buffers that | ||
1219 | can hold a packet of the size of the MTU */ | ||
1220 | for(i = 0; i<IbmVethNumBufferPools; i++) { | ||
1221 | if (pool == &adapter->rx_buff_pool[i]) | ||
1222 | continue; | ||
1223 | if (!adapter->rx_buff_pool[i].active) | ||
1224 | continue; | ||
1225 | if (mtu < adapter->rx_buff_pool[i].buff_size) { | ||
1226 | pool->active = 0; | ||
1227 | h_free_logical_lan_buffer(adapter-> | ||
1228 | vdev-> | ||
1229 | unit_address, | ||
1230 | pool-> | ||
1231 | buff_size); | ||
1232 | } | ||
1233 | } | ||
1234 | if (pool->active) { | ||
1235 | ibmveth_error_printk("no active pool >= MTU\n"); | ||
1236 | return -EPERM; | ||
1237 | } | ||
1238 | } | ||
1239 | } else if (attr == &veth_num_attr) { | ||
1240 | if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT) | ||
1241 | return -EINVAL; | ||
1242 | else { | ||
1243 | adapter->pool_config = 1; | ||
1244 | ibmveth_close(netdev); | ||
1245 | adapter->pool_config = 0; | ||
1246 | pool->size = value; | ||
1247 | if ((rc = ibmveth_open(netdev))) | ||
1248 | return rc; | ||
1249 | } | ||
1250 | } else if (attr == &veth_size_attr) { | ||
1251 | if (value <= IBMVETH_BUFF_OH || value > IBMVETH_MAX_BUF_SIZE) | ||
1252 | return -EINVAL; | ||
1253 | else { | ||
1254 | adapter->pool_config = 1; | ||
1255 | ibmveth_close(netdev); | ||
1256 | adapter->pool_config = 0; | ||
1257 | pool->buff_size = value; | ||
1258 | if ((rc = ibmveth_open(netdev))) | ||
1259 | return rc; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | /* kick the interrupt handler to allocate/deallocate pools */ | ||
1264 | ibmveth_interrupt(netdev->irq, netdev, NULL); | ||
1265 | return count; | ||
1266 | } | ||
1267 | |||
1268 | |||
1269 | #define ATTR(_name, _mode) \ | ||
1270 | struct attribute veth_##_name##_attr = { \ | ||
1271 | .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \ | ||
1272 | }; | ||
1273 | |||
1274 | static ATTR(active, 0644); | ||
1275 | static ATTR(num, 0644); | ||
1276 | static ATTR(size, 0644); | ||
1277 | |||
1278 | static struct attribute * veth_pool_attrs[] = { | ||
1279 | &veth_active_attr, | ||
1280 | &veth_num_attr, | ||
1281 | &veth_size_attr, | ||
1282 | NULL, | ||
1283 | }; | ||
1284 | |||
1285 | static struct sysfs_ops veth_pool_ops = { | ||
1286 | .show = veth_pool_show, | ||
1287 | .store = veth_pool_store, | ||
1288 | }; | ||
1289 | |||
1290 | static struct kobj_type ktype_veth_pool = { | ||
1291 | .release = NULL, | ||
1292 | .sysfs_ops = &veth_pool_ops, | ||
1293 | .default_attrs = veth_pool_attrs, | ||
1294 | }; | ||
1295 | |||
1296 | |||
1172 | static struct vio_device_id ibmveth_device_table[] __devinitdata= { | 1297 | static struct vio_device_id ibmveth_device_table[] __devinitdata= { |
1173 | { "network", "IBM,l-lan"}, | 1298 | { "network", "IBM,l-lan"}, |
1174 | { "", "" } | 1299 | { "", "" } |