Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: mhi: Add protocol support

MHI can transport different protocols, some are handled at upper level,
like IP and QMAP(rmnet/netlink), but others will need to be inside MHI
net driver, like mbim. This change adds support for protocol rx and
tx_fixup callbacks registration, that can be used to encode/decode the
targeted protocol.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Loic Poulain and committed by
David S. Miller
ddeb9bfa 24a1720a

+57 -12
+57 -12
drivers/net/mhi_net.c
··· 34 34 struct net_device *ndev; 35 35 struct sk_buff *skbagg_head; 36 36 struct sk_buff *skbagg_tail; 37 + const struct mhi_net_proto *proto; 38 + void *proto_data; 37 39 struct delayed_work rx_refill; 38 40 struct mhi_net_stats stats; 39 41 u32 rx_queue_sz; 42 + }; 43 + 44 + struct mhi_net_proto { 45 + int (*init)(struct mhi_net_dev *mhi_netdev); 46 + struct sk_buff * (*tx_fixup)(struct mhi_net_dev *mhi_netdev, struct sk_buff *skb); 47 + void (*rx)(struct mhi_net_dev *mhi_netdev, struct sk_buff *skb); 48 + }; 49 + 50 + struct mhi_device_info { 51 + const char *netname; 52 + const struct mhi_net_proto *proto; 40 53 }; 41 54 42 55 static int mhi_ndo_open(struct net_device *ndev) ··· 81 68 static int mhi_ndo_xmit(struct sk_buff *skb, struct net_device *ndev) 82 69 { 83 70 struct mhi_net_dev *mhi_netdev = netdev_priv(ndev); 71 + const struct mhi_net_proto *proto = mhi_netdev->proto; 84 72 struct mhi_device *mdev = mhi_netdev->mdev; 85 73 int err; 74 + 75 + if (proto && proto->tx_fixup) { 76 + skb = proto->tx_fixup(mhi_netdev, skb); 77 + if (unlikely(!skb)) 78 + goto exit_drop; 79 + } 86 80 87 81 err = mhi_queue_skb(mdev, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); 88 82 if (unlikely(err)) { 89 83 net_err_ratelimited("%s: Failed to queue TX buf (%d)\n", 90 84 ndev->name, err); 91 - 92 - u64_stats_update_begin(&mhi_netdev->stats.tx_syncp); 93 - u64_stats_inc(&mhi_netdev->stats.tx_dropped); 94 - u64_stats_update_end(&mhi_netdev->stats.tx_syncp); 95 - 96 - /* drop the packet */ 97 85 dev_kfree_skb_any(skb); 86 + goto exit_drop; 98 87 } 99 88 100 89 if (mhi_queue_is_full(mdev, DMA_TO_DEVICE)) 101 90 netif_stop_queue(ndev); 91 + 92 + return NETDEV_TX_OK; 93 + 94 + exit_drop: 95 + u64_stats_update_begin(&mhi_netdev->stats.tx_syncp); 96 + u64_stats_inc(&mhi_netdev->stats.tx_dropped); 97 + u64_stats_update_end(&mhi_netdev->stats.tx_syncp); 102 98 103 99 return NETDEV_TX_OK; 104 100 } ··· 186 164 struct mhi_result *mhi_res) 187 165 { 188 166 struct mhi_net_dev *mhi_netdev = dev_get_drvdata(&mhi_dev->dev); 167 + const struct mhi_net_proto *proto = mhi_netdev->proto; 189 168 struct sk_buff *skb = mhi_res->buf_addr; 190 169 int free_desc_count; 191 170 ··· 243 220 break; 244 221 } 245 222 246 - netif_rx(skb); 223 + if (proto && proto->rx) 224 + proto->rx(mhi_netdev, skb); 225 + else 226 + netif_rx(skb); 247 227 } 248 228 249 229 /* Refill if RX buffers queue becomes low */ ··· 328 302 static int mhi_net_probe(struct mhi_device *mhi_dev, 329 303 const struct mhi_device_id *id) 330 304 { 331 - const char *netname = (char *)id->driver_data; 305 + const struct mhi_device_info *info = (struct mhi_device_info *)id->driver_data; 332 306 struct device *dev = &mhi_dev->dev; 333 307 struct mhi_net_dev *mhi_netdev; 334 308 struct net_device *ndev; 335 309 int err; 336 310 337 - ndev = alloc_netdev(sizeof(*mhi_netdev), netname, NET_NAME_PREDICTABLE, 338 - mhi_net_setup); 311 + ndev = alloc_netdev(sizeof(*mhi_netdev), info->netname, 312 + NET_NAME_PREDICTABLE, mhi_net_setup); 339 313 if (!ndev) 340 314 return -ENOMEM; 341 315 ··· 344 318 mhi_netdev->ndev = ndev; 345 319 mhi_netdev->mdev = mhi_dev; 346 320 mhi_netdev->skbagg_head = NULL; 321 + mhi_netdev->proto = info->proto; 347 322 SET_NETDEV_DEV(ndev, &mhi_dev->dev); 348 323 SET_NETDEV_DEVTYPE(ndev, &wwan_type); 349 324 ··· 364 337 if (err) 365 338 goto out_err; 366 339 340 + if (mhi_netdev->proto) { 341 + err = mhi_netdev->proto->init(mhi_netdev); 342 + if (err) 343 + goto out_err_proto; 344 + } 345 + 367 346 return 0; 368 347 348 + out_err_proto: 349 + unregister_netdev(ndev); 369 350 out_err: 370 351 free_netdev(ndev); 371 352 return err; ··· 393 358 free_netdev(mhi_netdev->ndev); 394 359 } 395 360 361 + static const struct mhi_device_info mhi_hwip0 = { 362 + .netname = "mhi_hwip%d", 363 + }; 364 + 365 + static const struct mhi_device_info mhi_swip0 = { 366 + .netname = "mhi_swip%d", 367 + }; 368 + 396 369 static const struct mhi_device_id mhi_net_id_table[] = { 397 - { .chan = "IP_HW0", .driver_data = (kernel_ulong_t)"mhi_hwip%d" }, 398 - { .chan = "IP_SW0", .driver_data = (kernel_ulong_t)"mhi_swip%d" }, 370 + /* Hardware accelerated data PATH (to modem IPA), protocol agnostic */ 371 + { .chan = "IP_HW0", .driver_data = (kernel_ulong_t)&mhi_hwip0 }, 372 + /* Software data PATH (to modem CPU) */ 373 + { .chan = "IP_SW0", .driver_data = (kernel_ulong_t)&mhi_swip0 }, 399 374 {} 400 375 }; 401 376 MODULE_DEVICE_TABLE(mhi, mhi_net_id_table);