Message ID | 20240619200552.119080-4-admiyo@os.amperecomputing.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [v2,1/3] mctp pcc: Check before sending MCTP PCC response ACK | expand |
On Wed, 19 Jun 2024 16:05:52 -0400 admiyo@os.amperecomputing.com wrote: > From: Adam Young <admiyo@amperecomputing.com> > > Implementation of DMTF DSP:0292 > Management Control Transport Protocol(MCTP) over > Platform Communication Channel(PCC) network driver. > > MCTP devices are specified by entries in DSDT/SDST and > reference channels specified in the PCCT. > > Communication with other devices use the PCC based > doorbell mechanism. This patch breaks allmodconfig build: drivers/net/mctp/mctp-pcc.c:116:6: warning: unused variable 'rc' [-Wunused-variable] 116 | int rc; | ^~ drivers/net/mctp/mctp-pcc.c:344:3: error: field designator 'owner' does not refer to any field in type 'struct acpi_driver' 344 | .owner = THIS_MODULE, | ~^~~~~~~~~~~~~~~~~~~ In addition, please make sure you don't add new checkpatch warnings, use: ./scripts/checkpatch.pl --strict --max-line-length=80 $patch Please wait with the repost until next week, unless you get a review from Jeremy before that. When reposting start a new thread, don't repost in reply to previous posting. Instead add a lore link to the previous version, like this: https://lore.kernel.org/20240619200552.119080-1-admiyo@os.amperecomputing.com/ See also: https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#changes-requested
On 6/19/24 19:26, Jakub Kicinski wrote: > On Wed, 19 Jun 2024 16:05:52 -0400 admiyo@os.amperecomputing.com wrote: >> From: Adam Young <admiyo@amperecomputing.com> >> >> Implementation of DMTF DSP:0292 >> Management Control Transport Protocol(MCTP) over >> Platform Communication Channel(PCC) network driver. >> >> MCTP devices are specified by entries in DSDT/SDST and >> reference channels specified in the PCCT. >> >> Communication with other devices use the PCC based >> doorbell mechanism. > This patch breaks allmodconfig build: > > drivers/net/mctp/mctp-pcc.c:116:6: warning: unused variable 'rc' [-Wunused-variable] > 116 | int rc; > | ^~ Funny, I see that only when building on x86_64, not on arm64. I will fix. > drivers/net/mctp/mctp-pcc.c:344:3: error: field designator 'owner' does not refer to any field in type 'struct acpi_driver' > 344 | .owner = THIS_MODULE, > | ~^~~~~~~~~~~~~~~~~~~ Not sure how you are getting that last error. I do not, and the v6.9.3 code base has this in include/acpi/acpi_bus.h at line 166 struct acpi_driver { char name[80]; char class[80]; const struct acpi_device_id *ids; /* Supported Hardware IDs */ unsigned int flags; struct acpi_device_ops ops; struct device_driver drv; struct module *owner; }; > In addition, please make sure you don't add new checkpatch warnings, > use: > > ./scripts/checkpatch.pl --strict --max-line-length=80 $patch That runs clean. > > Please wait with the repost until next week, unless you get a review > from Jeremy before that. When reposting start a new thread, don't > repost in reply to previous posting. Instead add a lore link to the > previous version, like this: > > https://lore.kernel.org/20240619200552.119080-1-admiyo@os.amperecomputing.com/ > > See also: > https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#changes-requested
Hi, kernel test robot noticed the following build warnings: [auto build test WARNING on rafael-pm/linux-next] [also build test WARNING on rafael-pm/bleeding-edge linus/master v6.10-rc4 next-20240619] [cannot apply to horms-ipvs/master] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/admiyo-os-amperecomputing-com/mctp-pcc-Check-before-sending-MCTP-PCC-response-ACK/20240620-040816 base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next patch link: https://lore.kernel.org/r/20240619200552.119080-4-admiyo%40os.amperecomputing.com patch subject: [PATCH v2 3/3] mctp pcc: Implement MCTP over PCC Transport config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20240620/202406201832.4oSZmptU-lkp@intel.com/config) compiler: arceb-elf-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240620/202406201832.4oSZmptU-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202406201832.4oSZmptU-lkp@intel.com/ All warnings (new ones prefixed by >>): In file included from drivers/net/mctp/mctp-pcc.c:17: include/acpi/acpi_drivers.h:72:43: warning: 'struct acpi_pci_root' declared inside parameter list will not be visible outside of this definition or declaration 72 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root); | ^~~~~~~~~~~~~ drivers/net/mctp/mctp-pcc.c: In function 'mctp_pcc_tx': >> drivers/net/mctp/mctp-pcc.c:116:13: warning: unused variable 'rc' [-Wunused-variable] 116 | int rc; | ^~ drivers/net/mctp/mctp-pcc.c: In function 'create_mctp_pcc_netdev': drivers/net/mctp/mctp-pcc.c:223:17: error: invalid use of undefined type 'struct acpi_device' 223 | acpi_dev->driver_data = mctp_pcc_dev; | ^~ In file included from include/linux/printk.h:573, from include/asm-generic/bug.h:22, from arch/arc/include/asm/bug.h:30, from include/linux/bug.h:5, from include/linux/thread_info.h:13, from include/asm-generic/preempt.h:5, from ./arch/arc/include/generated/asm/preempt.h:1, from include/linux/preempt.h:79, from include/linux/spinlock.h:56, from include/linux/mmzone.h:8, from include/linux/gfp.h:7, from include/linux/slab.h:16, from include/linux/resource_ext.h:11, from include/linux/acpi.h:13, from drivers/net/mctp/mctp-pcc.c:7: drivers/net/mctp/mctp-pcc.c: In function 'mctp_pcc_driver_add': drivers/net/mctp/mctp-pcc.c:291:22: error: invalid use of undefined type 'struct acpi_device' 291 | dev_dbg(&adev->dev, "Adding mctp_pcc device for HID %s\n", | ^~ include/linux/dynamic_debug.h:224:29: note: in definition of macro '__dynamic_func_call_cls' 224 | func(&id, ##__VA_ARGS__); \ | ^~~~~~~~~~~ include/linux/dynamic_debug.h:250:9: note: in expansion of macro '_dynamic_func_call_cls' 250 | _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__) | ^~~~~~~~~~~~~~~~~~~~~~ include/linux/dynamic_debug.h:273:9: note: in expansion of macro '_dynamic_func_call' 273 | _dynamic_func_call(fmt, __dynamic_dev_dbg, \ | ^~~~~~~~~~~~~~~~~~ include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg' 165 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~~~~~~~~ drivers/net/mctp/mctp-pcc.c:291:9: note: in expansion of macro 'dev_dbg' 291 | dev_dbg(&adev->dev, "Adding mctp_pcc device for HID %s\n", | ^~~~~~~ drivers/net/mctp/mctp-pcc.c:292:17: error: implicit declaration of function 'acpi_device_hid'; did you mean 'acpi_device_dep'? [-Werror=implicit-function-declaration] 292 | acpi_device_hid(adev)); | ^~~~~~~~~~~~~~~ include/linux/dynamic_debug.h:224:29: note: in definition of macro '__dynamic_func_call_cls' 224 | func(&id, ##__VA_ARGS__); \ | ^~~~~~~~~~~ include/linux/dynamic_debug.h:250:9: note: in expansion of macro '_dynamic_func_call_cls' 250 | _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__) | ^~~~~~~~~~~~~~~~~~~~~~ include/linux/dynamic_debug.h:273:9: note: in expansion of macro '_dynamic_func_call' 273 | _dynamic_func_call(fmt, __dynamic_dev_dbg, \ | ^~~~~~~~~~~~~~~~~~ include/linux/dev_printk.h:165:9: note: in expansion of macro 'dynamic_dev_dbg' 165 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~~~~~~~~ drivers/net/mctp/mctp-pcc.c:291:9: note: in expansion of macro 'dev_dbg' 291 | dev_dbg(&adev->dev, "Adding mctp_pcc device for HID %s\n", | ^~~~~~~ drivers/net/mctp/mctp-pcc.c:293:22: error: implicit declaration of function 'acpi_device_handle'; did you mean 'acpi_device_dep'? [-Werror=implicit-function-declaration] 293 | dev_handle = acpi_device_handle(adev); | ^~~~~~~~~~~~~~~~~~ | acpi_device_dep drivers/net/mctp/mctp-pcc.c:293:20: warning: assignment to 'acpi_handle' {aka 'void *'} from 'int' makes pointer from integer without a cast [-Wint-conversion] 293 | dev_handle = acpi_device_handle(adev); | ^ In file included from include/linux/device.h:15, from include/linux/acpi.h:14: drivers/net/mctp/mctp-pcc.c:297:30: error: invalid use of undefined type 'struct acpi_device' 297 | dev_err(&adev->dev, "FAILURE to lookup PCC indexes from CRS"); | ^~ include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap' 110 | _p_func(dev, fmt, ##__VA_ARGS__); \ | ^~~ drivers/net/mctp/mctp-pcc.c:297:17: note: in expansion of macro 'dev_err' 297 | dev_err(&adev->dev, "FAILURE to lookup PCC indexes from CRS"); | ^~~~~~~ drivers/net/mctp/mctp-pcc.c:302:50: error: invalid use of undefined type 'struct acpi_device' 302 | return create_mctp_pcc_netdev(adev, &adev->dev, inbox_index, | ^~ drivers/net/mctp/mctp-pcc.c: At top level: drivers/net/mctp/mctp-pcc.c:336:15: error: variable 'mctp_pcc_driver' has initializer but incomplete type 336 | static struct acpi_driver mctp_pcc_driver = { | ^~~~~~~~~~~ drivers/net/mctp/mctp-pcc.c:337:10: error: 'struct acpi_driver' has no member named 'name' 337 | .name = "mctp_pcc", | ^~~~ drivers/net/mctp/mctp-pcc.c:337:17: warning: excess elements in struct initializer 337 | .name = "mctp_pcc", | ^~~~~~~~~~ drivers/net/mctp/mctp-pcc.c:337:17: note: (near initialization for 'mctp_pcc_driver') drivers/net/mctp/mctp-pcc.c:338:10: error: 'struct acpi_driver' has no member named 'class' 338 | .class = "Unknown", | ^~~~~ drivers/net/mctp/mctp-pcc.c:338:18: warning: excess elements in struct initializer 338 | .class = "Unknown", | ^~~~~~~~~ drivers/net/mctp/mctp-pcc.c:338:18: note: (near initialization for 'mctp_pcc_driver') drivers/net/mctp/mctp-pcc.c:339:10: error: 'struct acpi_driver' has no member named 'ids' 339 | .ids = mctp_pcc_device_ids, | ^~~ vim +/rc +116 drivers/net/mctp/mctp-pcc.c 109 110 static netdev_tx_t mctp_pcc_tx(struct sk_buff *skb, struct net_device *ndev) 111 { 112 struct mctp_pcc_hdr pcc_header; 113 struct mctp_pcc_ndev *mpnd; 114 void __iomem *buffer; 115 unsigned long flags; > 116 int rc; 117 118 ndev->stats.tx_bytes += skb->len; 119 ndev->stats.tx_packets++; 120 mpnd = netdev_priv(ndev); 121 122 spin_lock_irqsave(&mpnd->lock, flags); 123 buffer = mpnd->pcc_comm_outbox_addr; 124 pcc_header.signature = PCC_MAGIC | mpnd->hw_addr.outbox_index; 125 pcc_header.flags = PCC_HEADER_FLAGS; 126 memcpy(pcc_header.mctp_signature, MCTP_SIGNATURE, SIGNATURE_LENGTH); 127 pcc_header.length = skb->len + SIGNATURE_LENGTH; 128 memcpy_toio(buffer, &pcc_header, sizeof(struct mctp_pcc_hdr)); 129 memcpy_toio(buffer + sizeof(struct mctp_pcc_hdr), skb->data, skb->len); 130 mpnd->out_chan->mchan->mbox->ops->send_data(mpnd->out_chan->mchan, 131 NULL); 132 spin_unlock_irqrestore(&mpnd->lock, flags); 133 134 dev_consume_skb_any(skb); 135 return NETDEV_TX_OK; 136 } 137
On Wed, 19 Jun 2024 23:24:41 -0400 Adam Young wrote: > > drivers/net/mctp/mctp-pcc.c:344:3: error: field designator 'owner' does not refer to any field in type 'struct acpi_driver' > > 344 | .owner = THIS_MODULE, > > | ~^~~~~~~~~~~~~~~~~~~ > > Not sure how you are getting that last error. I do not, and the v6.9.3 > code base has this in include/acpi/acpi_bus.h at line 166 v6.9.3 is not a development kernel. Your patches will be merged to net-next. Read more of the process doc I linked in the previous message. > That runs clean. It doesn't on patches 1 and 2, but you're right, I think it's intentional / because of the "historical" ACPI coding style :(
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rafael-pm/linux-next]
[also build test WARNING on rafael-pm/bleeding-edge linus/master v6.10-rc4 next-20240619]
[cannot apply to horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/admiyo-os-amperecomputing-com/mctp-pcc-Check-before-sending-MCTP-PCC-response-ACK/20240620-040816
base: https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
patch link: https://lore.kernel.org/r/20240619200552.119080-4-admiyo%40os.amperecomputing.com
patch subject: [PATCH v2 3/3] mctp pcc: Implement MCTP over PCC Transport
config: arm64-kismet-CONFIG_ACPI-CONFIG_MCTP_TRANSPORT_PCC-0-0 (https://download.01.org/0day-ci/archive/20240620/202406202206.9e7oGmfh-lkp@intel.com/config)
reproduce: (https://download.01.org/0day-ci/archive/20240620/202406202206.9e7oGmfh-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202406202206.9e7oGmfh-lkp@intel.com/
kismet warnings: (new ones prefixed by >>)
>> kismet: WARNING: unmet direct dependencies detected for ACPI when selected by MCTP_TRANSPORT_PCC
WARNING: unmet direct dependencies detected for ACPI
Depends on [n]: ARCH_SUPPORTS_ACPI [=n]
Selected by [y]:
- MCTP_TRANSPORT_PCC [=y] && NETDEVICES [=y] && MCTP [=y]
diff --git a/drivers/net/mctp/Kconfig b/drivers/net/mctp/Kconfig index ce9d2d2ccf3b..ff4effd8e99c 100644 --- a/drivers/net/mctp/Kconfig +++ b/drivers/net/mctp/Kconfig @@ -42,6 +42,19 @@ config MCTP_TRANSPORT_I3C A MCTP protocol network device is created for each I3C bus having a "mctp-controller" devicetree property. +config MCTP_TRANSPORT_PCC + tristate "MCTP PCC transport" + select ACPI + help + Provides a driver to access MCTP devices over PCC transport, + A MCTP protocol network device is created via ACPI for each + entry in the DST/SDST that matches the identifier. The Platform + commuinucation channels are selected from the corresponding + entries in the PCCT. + + Say y here if you need to connect to MCTP endpoints over PCC. To + compile as a module, use m; the module will be called mctp-pcc. + endmenu endif diff --git a/drivers/net/mctp/Makefile b/drivers/net/mctp/Makefile index e1cb99ced54a..492a9e47638f 100644 --- a/drivers/net/mctp/Makefile +++ b/drivers/net/mctp/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_MCTP_TRANSPORT_PCC) += mctp-pcc.o obj-$(CONFIG_MCTP_SERIAL) += mctp-serial.o obj-$(CONFIG_MCTP_TRANSPORT_I2C) += mctp-i2c.o obj-$(CONFIG_MCTP_TRANSPORT_I3C) += mctp-i3c.o diff --git a/drivers/net/mctp/mctp-pcc.c b/drivers/net/mctp/mctp-pcc.c new file mode 100644 index 000000000000..1ce9c58099cb --- /dev/null +++ b/drivers/net/mctp/mctp-pcc.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * mctp-pcc.c - Driver for MCTP over PCC. + * Copyright (c) 2024, Ampere Computing LLC + */ + +#include <linux/acpi.h> +#include <linux/if_arp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/string.h> + +#include <acpi/acpi_bus.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acrestyp.h> +#include <acpi/actbl.h> +#include <net/mctp.h> +#include <net/mctpdevice.h> +#include <acpi/pcc.h> + +#define SPDM_VERSION_OFFSET 1 +#define SPDM_REQ_RESP_OFFSET 2 +#define MCTP_PAYLOAD_LENGTH 256 +#define MCTP_CMD_LENGTH 4 +#define MCTP_PCC_VERSION 0x1 /* DSP0253 defines a single version: 1 */ +#define MCTP_SIGNATURE "MCTP" +#define SIGNATURE_LENGTH 4 +#define MCTP_HEADER_LENGTH 12 +#define MCTP_MIN_MTU 68 +#define PCC_MAGIC 0x50434300 +#define PCC_HEADER_FLAG_REQ_INT 0x1 +#define PCC_HEADER_FLAGS PCC_HEADER_FLAG_REQ_INT +#define PCC_DWORD_TYPE 0x0c +#define PCC_ACK_FLAG_MASK 0x1 + +struct mctp_pcc_hdr { + u32 signature; + u32 flags; + u32 length; + char mctp_signature[4]; +}; + +struct mctp_pcc_hw_addr { + u32 inbox_index; + u32 outbox_index; +}; + +/* The netdev structure. One of these per PCC adapter. */ +struct mctp_pcc_ndev { + struct list_head next; + /* spinlock to serialize access to pcc buffer and registers*/ + spinlock_t lock; + struct mctp_dev mdev; + struct acpi_device *acpi_device; + struct pcc_mbox_chan *in_chan; + struct pcc_mbox_chan *out_chan; + struct mbox_client outbox_client; + struct mbox_client inbox_client; + void __iomem *pcc_comm_inbox_addr; + void __iomem *pcc_comm_outbox_addr; + struct mctp_pcc_hw_addr hw_addr; +}; + +static struct list_head mctp_pcc_ndevs; + +static void mctp_pcc_client_rx_callback(struct mbox_client *c, void *buffer) +{ + struct mctp_pcc_ndev *mctp_pcc_dev; + struct mctp_pcc_hdr mctp_pcc_hdr; + struct mctp_skb_cb *cb; + struct sk_buff *skb; + void *skb_buf; + u32 data_len; + u32 flags; + + mctp_pcc_dev = container_of(c, struct mctp_pcc_ndev, inbox_client); + memcpy_fromio(&mctp_pcc_hdr, mctp_pcc_dev->pcc_comm_inbox_addr, + sizeof(struct mctp_pcc_hdr)); + data_len = mctp_pcc_hdr.length + MCTP_HEADER_LENGTH; + + if (data_len > mctp_pcc_dev->mdev.dev->max_mtu) { + mctp_pcc_dev->mdev.dev->stats.rx_dropped++; + return; + } + + skb = netdev_alloc_skb(mctp_pcc_dev->mdev.dev, data_len); + if (!skb) { + mctp_pcc_dev->mdev.dev->stats.rx_dropped++; + return; + } + mctp_pcc_dev->mdev.dev->stats.rx_packets++; + mctp_pcc_dev->mdev.dev->stats.rx_bytes += data_len; + skb->protocol = htons(ETH_P_MCTP); + skb_buf = skb_put(skb, data_len); + memcpy_fromio(skb_buf, mctp_pcc_dev->pcc_comm_inbox_addr, data_len); + skb_reset_mac_header(skb); + skb_pull(skb, sizeof(struct mctp_pcc_hdr)); + skb_reset_network_header(skb); + cb = __mctp_cb(skb); + cb->halen = 0; + netif_rx(skb); + + flags = mctp_pcc_hdr.flags; + mctp_pcc_dev->in_chan->ack_rx = (flags & PCC_ACK_FLAG_MASK) > 0; +} + +static netdev_tx_t mctp_pcc_tx(struct sk_buff *skb, struct net_device *ndev) +{ + struct mctp_pcc_hdr pcc_header; + struct mctp_pcc_ndev *mpnd; + void __iomem *buffer; + unsigned long flags; + int rc; + + ndev->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + mpnd = netdev_priv(ndev); + + spin_lock_irqsave(&mpnd->lock, flags); + buffer = mpnd->pcc_comm_outbox_addr; + pcc_header.signature = PCC_MAGIC | mpnd->hw_addr.outbox_index; + pcc_header.flags = PCC_HEADER_FLAGS; + memcpy(pcc_header.mctp_signature, MCTP_SIGNATURE, SIGNATURE_LENGTH); + pcc_header.length = skb->len + SIGNATURE_LENGTH; + memcpy_toio(buffer, &pcc_header, sizeof(struct mctp_pcc_hdr)); + memcpy_toio(buffer + sizeof(struct mctp_pcc_hdr), skb->data, skb->len); + mpnd->out_chan->mchan->mbox->ops->send_data(mpnd->out_chan->mchan, + NULL); + spin_unlock_irqrestore(&mpnd->lock, flags); + + dev_consume_skb_any(skb); + return NETDEV_TX_OK; +} + +static void +mctp_pcc_net_stats(struct net_device *net_dev, + struct rtnl_link_stats64 *stats) +{ + struct mctp_pcc_ndev *mpnd; + + mpnd = (struct mctp_pcc_ndev *)netdev_priv(net_dev); + stats->rx_errors = 0; + stats->rx_packets = mpnd->mdev.dev->stats.rx_packets; + stats->tx_packets = mpnd->mdev.dev->stats.tx_packets; + stats->rx_dropped = 0; + stats->tx_bytes = mpnd->mdev.dev->stats.tx_bytes; + stats->rx_bytes = mpnd->mdev.dev->stats.rx_bytes; +} + +static const struct net_device_ops mctp_pcc_netdev_ops = { + .ndo_start_xmit = mctp_pcc_tx, + .ndo_get_stats64 = mctp_pcc_net_stats, +}; + +static void mctp_pcc_setup(struct net_device *ndev) +{ + ndev->type = ARPHRD_MCTP; + ndev->hard_header_len = 0; + ndev->addr_len = 0; + ndev->tx_queue_len = 0; + ndev->flags = IFF_NOARP; + ndev->netdev_ops = &mctp_pcc_netdev_ops; + ndev->needs_free_netdev = true; +} + +static int create_mctp_pcc_netdev(struct acpi_device *acpi_dev, + struct device *dev, int inbox_index, + int outbox_index) +{ + struct mctp_pcc_ndev *mctp_pcc_dev; + struct net_device *ndev; + int mctp_pcc_mtu; + char name[32]; + int rc; + + snprintf(name, sizeof(name), "mctpipcc%d", inbox_index); + ndev = alloc_netdev(sizeof(struct mctp_pcc_ndev), name, NET_NAME_ENUM, + mctp_pcc_setup); + if (!ndev) + return -ENOMEM; + mctp_pcc_dev = (struct mctp_pcc_ndev *)netdev_priv(ndev); + INIT_LIST_HEAD(&mctp_pcc_dev->next); + spin_lock_init(&mctp_pcc_dev->lock); + + mctp_pcc_dev->hw_addr.inbox_index = inbox_index; + mctp_pcc_dev->hw_addr.outbox_index = outbox_index; + mctp_pcc_dev->inbox_client.rx_callback = mctp_pcc_client_rx_callback; + mctp_pcc_dev->out_chan = + pcc_mbox_request_channel(&mctp_pcc_dev->outbox_client, + outbox_index); + if (IS_ERR(mctp_pcc_dev->out_chan)) { + rc = PTR_ERR(mctp_pcc_dev->out_chan); + goto free_netdev; + } + mctp_pcc_dev->in_chan = + pcc_mbox_request_channel(&mctp_pcc_dev->inbox_client, + inbox_index); + if (IS_ERR(mctp_pcc_dev->in_chan)) { + rc = PTR_ERR(mctp_pcc_dev->in_chan); + goto cleanup_out_channel; + } + mctp_pcc_dev->pcc_comm_inbox_addr = + devm_ioremap(dev, mctp_pcc_dev->in_chan->shmem_base_addr, + mctp_pcc_dev->in_chan->shmem_size); + if (!mctp_pcc_dev->pcc_comm_inbox_addr) { + rc = -EINVAL; + goto cleanup_in_channel; + } + mctp_pcc_dev->pcc_comm_outbox_addr = + devm_ioremap(dev, mctp_pcc_dev->out_chan->shmem_base_addr, + mctp_pcc_dev->out_chan->shmem_size); + if (!mctp_pcc_dev->pcc_comm_outbox_addr) { + rc = -EINVAL; + goto cleanup_in_channel; + } + mctp_pcc_dev->acpi_device = acpi_dev; + mctp_pcc_dev->inbox_client.dev = dev; + mctp_pcc_dev->outbox_client.dev = dev; + mctp_pcc_dev->mdev.dev = ndev; + acpi_dev->driver_data = mctp_pcc_dev; + + /* There is no clean way to pass the MTU + * to the callback function used for registration, + * so set the values ahead of time. + */ + mctp_pcc_mtu = mctp_pcc_dev->out_chan->shmem_size - + sizeof(struct mctp_pcc_hdr); + ndev->mtu = MCTP_MIN_MTU; + ndev->max_mtu = mctp_pcc_mtu; + ndev->min_mtu = MCTP_MIN_MTU; + + rc = register_netdev(ndev); + if (rc) + goto cleanup_in_channel; + list_add_tail(&mctp_pcc_dev->next, &mctp_pcc_ndevs); + return 0; + +cleanup_in_channel: + pcc_mbox_free_channel(mctp_pcc_dev->in_chan); +cleanup_out_channel: + pcc_mbox_free_channel(mctp_pcc_dev->out_chan); +free_netdev: + unregister_netdev(ndev); + free_netdev(ndev); + return rc; +} + +struct lookup_context { + int index; + u32 inbox_index; + u32 outbox_index; +}; + +static acpi_status lookup_pcct_indices(struct acpi_resource *ares, + void *context) +{ + struct acpi_resource_address32 *addr; + struct lookup_context *luc = context; + + switch (ares->type) { + case PCC_DWORD_TYPE: + break; + default: + return AE_OK; + } + + addr = ACPI_CAST_PTR(struct acpi_resource_address32, &ares->data); + switch (luc->index) { + case 0: + luc->outbox_index = addr[0].address.minimum; + break; + case 1: + luc->inbox_index = addr[0].address.minimum; + break; + } + luc->index++; + return AE_OK; +} + +static int mctp_pcc_driver_add(struct acpi_device *adev) +{ + int outbox_index; + int inbox_index; + acpi_handle dev_handle; + acpi_status status; + struct lookup_context context = {0, 0, 0}; + + dev_dbg(&adev->dev, "Adding mctp_pcc device for HID %s\n", + acpi_device_hid(adev)); + dev_handle = acpi_device_handle(adev); + status = acpi_walk_resources(dev_handle, "_CRS", lookup_pcct_indices, + &context); + if (!ACPI_SUCCESS(status)) { + dev_err(&adev->dev, "FAILURE to lookup PCC indexes from CRS"); + return -EINVAL; + } + inbox_index = context.inbox_index; + outbox_index = context.outbox_index; + return create_mctp_pcc_netdev(adev, &adev->dev, inbox_index, + outbox_index); +} + +/* pass in adev=NULL to remove all devices + */ +static void mctp_pcc_driver_remove(struct acpi_device *adev) +{ + struct mctp_pcc_ndev *mctp_pcc_dev = NULL; + struct list_head *ptr; + struct list_head *tmp; + + list_for_each_safe(ptr, tmp, &mctp_pcc_ndevs) { + struct net_device *ndev; + + mctp_pcc_dev = list_entry(ptr, struct mctp_pcc_ndev, next); + if (adev && mctp_pcc_dev->acpi_device != adev) + continue; + pcc_mbox_free_channel(mctp_pcc_dev->out_chan); + pcc_mbox_free_channel(mctp_pcc_dev->in_chan); + ndev = mctp_pcc_dev->mdev.dev; + if (ndev) + mctp_unregister_netdev(ndev); + list_del(ptr); + if (adev) + break; + } +} + +static const struct acpi_device_id mctp_pcc_device_ids[] = { + { "DMT0001", 0}, + { "", 0}, +}; + +static struct acpi_driver mctp_pcc_driver = { + .name = "mctp_pcc", + .class = "Unknown", + .ids = mctp_pcc_device_ids, + .ops = { + .add = mctp_pcc_driver_add, + .remove = mctp_pcc_driver_remove, + }, + .owner = THIS_MODULE, +}; + +static int __init mctp_pcc_mod_init(void) +{ + int rc; + + pr_debug("Initializing MCTP over PCC transport driver\n"); + INIT_LIST_HEAD(&mctp_pcc_ndevs); + rc = acpi_bus_register_driver(&mctp_pcc_driver); + if (rc < 0) + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering driver\n")); + return rc; +} + +static __exit void mctp_pcc_mod_exit(void) +{ + pr_debug("Removing MCTP over PCC transport driver\n"); + mctp_pcc_driver_remove(NULL); + acpi_bus_unregister_driver(&mctp_pcc_driver); +} + +module_init(mctp_pcc_mod_init); +module_exit(mctp_pcc_mod_exit); + +MODULE_DEVICE_TABLE(acpi, mctp_pcc_device_ids); + +MODULE_DESCRIPTION("MCTP PCC device"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Adam Young <admiyo@os.amperecomputing.com>");