Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752524AbcLDAK6 (ORCPT ); Sat, 3 Dec 2016 19:10:58 -0500 Received: from esa2.dell-outbound.iphmx.com ([68.232.149.220]:31275 "EHLO esa2.dell-outbound.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752458AbcLDAK4 (ORCPT ); Sat, 3 Dec 2016 19:10:56 -0500 DomainKey-Signature: s=smtpout; d=dell.com; c=simple; q=dns; h=Received:Received:Received:X-DKIM:Received:Received:From: To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type: Content-Transfer-Encoding:X-Mailer:Content-Language: Thread-Index:X-RSA-Classifications:X-Sentrion-Hostname; b=B7oEpHsh3nZYViSindD7FXQSu0UGd4geEGpB2LIJx6zoyT2/JJDzy7eA vuRTWfdsOwvgGu1AM4SJQGhyVDjGKMPUsrb49Gs/k86sxknWPDJIN0BHh Iogq5YWC4AodS1aOjATfobpekoCVJVCyUjiYDvUE8CPojIeRzKvo/Mf38 g=; X-DKIM: OpenDKIM Filter v2.4.3 mailuogwprd54.lss.emc.com uB405R91030703 From: "Allen Hubbe" To: "'Serge Semin'" , , , Cc: , , Subject: RE: [PATCH 04/22] NTB: Add messaging NTB API Date: Sat, 3 Dec 2016 19:05:17 -0500 Message-ID: <003f01d24dc2$18faf5e0$4af0e1a0$@dell.com> MIME-Version: 1.0 Content-Type: text/plain; charset="Windows-1252" Content-Transfer-Encoding: 7bit X-Mailer: Microsoft Outlook 14.0 Content-Language: en-us Thread-Index: AdJNwgt3jTjQ8+Q/TSqgizr1/jE2Eg== X-RSA-Classifications: Source Code, public X-Sentrion-Hostname: mailuogwprd54.lss.emc.com Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 12890 Lines: 398 From: Serge Semin > IDT PCIe-switches have message registers to communicate with peer devices. > This patch adds new NTB API callback methods, which can be used to utilize > these registers functionality. > Please split: add msg api; make spads optional. See comments below on ntb_dev_ops_is_valid. > Signed-off-by: Serge Semin > > --- > drivers/ntb/ntb.c | 13 +++ > include/linux/ntb.h | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 241 insertions(+), 8 deletions(-) > > diff --git a/drivers/ntb/ntb.c b/drivers/ntb/ntb.c > index 2e25307..4b2cc60 100644 > --- a/drivers/ntb/ntb.c > +++ b/drivers/ntb/ntb.c > @@ -191,6 +191,19 @@ void ntb_db_event(struct ntb_dev *ntb, int vector) > } > EXPORT_SYMBOL(ntb_db_event); > > +void ntb_msg_event(struct ntb_dev *ntb) > +{ > + unsigned long irqflags; > + > + spin_lock_irqsave(&ntb->ctx_lock, irqflags); > + { > + if (ntb->ctx_ops && ntb->ctx_ops->msg_event) > + ntb->ctx_ops->msg_event(ntb->ctx); > + } > + spin_unlock_irqrestore(&ntb->ctx_lock, irqflags); > +} > +EXPORT_SYMBOL(ntb_msg_event); > + > static int ntb_probe(struct device *dev) > { > struct ntb_dev *ntb; > diff --git a/include/linux/ntb.h b/include/linux/ntb.h > index 4a150b5..59de1f6 100644 > --- a/include/linux/ntb.h > +++ b/include/linux/ntb.h > @@ -146,10 +146,12 @@ static inline int ntb_client_ops_is_valid(const struct > ntb_client_ops *ops) > * struct ntb_ctx_ops - ntb driver context operations > * @link_event: See ntb_link_event(). > * @db_event: See ntb_db_event(). > + * @msg_event: See ntb_msg_event(). > */ > struct ntb_ctx_ops { > void (*link_event)(void *ctx); > void (*db_event)(void *ctx, int db_vector); > + void (*msg_event)(void *ctx); > }; > > static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > @@ -158,6 +160,7 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > return > /* ops->link_event && */ > /* ops->db_event && */ > + /* ops->msg_event && */ > 1; > } > > @@ -202,6 +205,15 @@ static inline int ntb_ctx_ops_is_valid(const struct ntb_ctx_ops *ops) > * @peer_spad_addr: See ntb_peer_spad_addr(). > * @peer_spad_read: See ntb_peer_spad_read(). > * @peer_spad_write: See ntb_peer_spad_write(). > + * @msg_count: See ntb_msg_count(). > + * @msg_inbits: See ntb_msg_inbits(). > + * @msg_outbits: See ntb_msg_outbits(). > + * @msg_read_sts: See ntb_msg_read_sts(). > + * @msg_clear_sts: See ntb_msg_clear_sts(). > + * @msg_set_mask: See ntb_msg_set_mask(). > + * @msg_clear_mask: See ntb_msg_clear_mask(). > + * @msg_read: See ntb_msg_read(). > + * @msg_write: See ntb_msg_write(). > */ > struct ntb_dev_ops { > int (*port_number)(struct ntb_dev *ntb); > @@ -263,6 +275,16 @@ struct ntb_dev_ops { > phys_addr_t *spad_addr); > u32 (*peer_spad_read)(struct ntb_dev *ntb, int idx); > int (*peer_spad_write)(struct ntb_dev *ntb, int idx, u32 val); > + > + int (*msg_count)(struct ntb_dev *ntb); > + u64 (*msg_inbits)(struct ntb_dev *ntb); > + u64 (*msg_outbits)(struct ntb_dev *ntb); > + u64 (*msg_read_sts)(struct ntb_dev *ntb); > + int (*msg_clear_sts)(struct ntb_dev *ntb, u64 sts_bits); > + int (*msg_set_mask)(struct ntb_dev *ntb, u64 mask_bits); > + int (*msg_clear_mask)(struct ntb_dev *ntb, u64 mask_bits); > + int (*msg_read)(struct ntb_dev *ntb, int midx, int *pidx, u32 *msg); > + int (*msg_write)(struct ntb_dev *ntb, int midx, int pidx, u32 msg); > }; > > static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops *ops) > @@ -304,13 +326,22 @@ static inline int ntb_dev_ops_is_valid(const struct ntb_dev_ops > *ops) > /* ops->peer_db_read_mask && */ > /* ops->peer_db_set_mask && */ > /* ops->peer_db_clear_mask && */ > - /* ops->spad_is_unsafe && */ > - ops->spad_count && > - ops->spad_read && > - ops->spad_write && > - /* ops->peer_spad_addr && */ > - /* ops->peer_spad_read && */ > - ops->peer_spad_write && > + ((/* ops->spad_is_unsafe && */ > + ops->spad_count && > + ops->spad_read && > + ops->spad_write && > + /* ops->peer_spad_addr && */ > + /* ops->peer_spad_read && */ > + ops->peer_spad_write) || > + (ops->msg_count && > + ops->msg_inbits && > + ops->msg_outbits && > + ops->msg_read_sts && > + ops->msg_clear_sts && > + /* ops->msg_set_mask && */ > + /* ops->msg_clear_mask && */ > + ops->msg_read && > + ops->msg_write)) && Don't enforce "must have spad or msg" here, leave it to application to check spad_count != 0 or msg_count != 0 else fail. If an ntb doesn't have either, it may be rather limited, but let's not prevent the driver to register that device. As written above has a subtle bug. We should say, if spad is implemented at all, then the basic spad api is fully implemented; likewise if msg is implemented at all, then the basic msg api is fully implemented. As written below, the required basic api of spad ops must have the same truth-value of spad_count (and likewise for msg_count). /* !ops->spad_is_unsafe == !ops->spad_count && */ !ops->spad_read == !ops->spad_count && !ops->spad_write == !ops->spad_count && /* !ops->peer_spad_addr == !ops->spad_count && */ /* !ops->peer_spad_read == !ops->spad_count && */ !ops->peer_spad_write == !ops->spad_count && !ops->msg_inbits == !ops->msg_count && !ops->msg_outbits == !ops->msg_count && !ops->msg_read_sts == !ops->msg_count && !ops->msg_clear_sts == !ops->msg_count && /* !ops->msg_set_mask == !ops->msg_count && */ /* !ops->msg_clear_mask == !ops->msg_count && */ !ops->msg_read == !ops->msg_count && !ops->msg_write == !ops->msg_count && > 1; > } > > @@ -456,6 +487,18 @@ void ntb_link_event(struct ntb_dev *ntb); > void ntb_db_event(struct ntb_dev *ntb, int vector); > > /** > + * ntb_msg_event() - notify driver context of a message event > + * @ntb: NTB device context. > + * > + * Notify the driver context of a message event. If hardware supports > + * message registers, this event indicates, that a new message arrived in > + * some incoming message register or last sent message couldn't be delivered. > + * The events can be masked/unmasked by the methods ntb_msg_set_mask() and > + * ntb_msg_clear_mask(). > + */ > +void ntb_msg_event(struct ntb_dev *ntb); > + > +/** > * ntb_port_number() - get the local port number > * @ntb: NTB device context. > * > @@ -1154,7 +1197,7 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb) > } > > /** > - * ntb_mw_count() - get the number of scratchpads > + * ntb_spad_count() - get the number of scratchpads > * @ntb: NTB device context. > * > * Hardware and topology may support a different number of scratchpads. > @@ -1163,6 +1206,9 @@ static inline int ntb_spad_is_unsafe(struct ntb_dev *ntb) > */ > static inline int ntb_spad_count(struct ntb_dev *ntb) > { > + if (!ntb->ops->spad_count) > + return 0; > + > return ntb->ops->spad_count(ntb); > } > > @@ -1177,6 +1223,9 @@ static inline int ntb_spad_count(struct ntb_dev *ntb) > */ > static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx) > { > + if (!ntb->ops->spad_read) > + return ~(u32)0; > + > return ntb->ops->spad_read(ntb, idx); > } > > @@ -1192,6 +1241,9 @@ static inline u32 ntb_spad_read(struct ntb_dev *ntb, int idx) > */ > static inline int ntb_spad_write(struct ntb_dev *ntb, int idx, u32 val) > { > + if (!ntb->ops->spad_write) > + return -EINVAL; > + > return ntb->ops->spad_write(ntb, idx, val); > } > > @@ -1226,6 +1278,9 @@ static inline int ntb_peer_spad_addr(struct ntb_dev *ntb, int idx, > */ > static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx) > { > + if (!ntb->ops->peer_spad_read) > + return ~(u32)0; > + > return ntb->ops->peer_spad_read(ntb, idx); > } > > @@ -1241,7 +1296,172 @@ static inline u32 ntb_peer_spad_read(struct ntb_dev *ntb, int idx) > */ > static inline int ntb_peer_spad_write(struct ntb_dev *ntb, int idx, u32 val) > { > + if (!ntb->ops->peer_spad_write) > + return -EINVAL; > + > return ntb->ops->peer_spad_write(ntb, idx, val); > } > > +/** > + * ntb_msg_count() - get the number of message registers > + * @ntb: NTB device context. > + * > + * Hardware may support a different number of messge registers. > + * > + * Return: the number of message registers. > + */ > +static inline int ntb_msg_count(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_count) > + return 0; > + > + return ntb->ops->msg_count(ntb); > +} > + > +/** > + * ntb_msg_inbits() - get a bitsfield of inbound message registers status > + * @ntb: NTB device context. > + * > + * The method returns the bitsfield of status and mask registers, which related > + * to inbound message registers. > + * > + * Return: bitsfield of inbound message registers. > + */ > +static inline u64 ntb_msg_inbits(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_inbits) > + return 0; > + > + return ntb->ops->msg_inbits(ntb); > +} > + > +/** > + * ntb_msg_outbits() - get a bitsfield of outbound message registers status > + * @ntb: NTB device context. > + * > + * The method returns the bitsfield of status and mask registers, which related > + * to outbound message registers. > + * > + * Return: bitsfield of outbound message registers. > + */ > +static inline u64 ntb_msg_outbits(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_outbits) > + return 0; > + > + return ntb->ops->msg_outbits(ntb); > +} > + > +/** > + * ntb_msg_read_sts() - read the message registers status > + * @ntb: NTB device context. > + * > + * Read the status of message register. Inbound and outbound message registers > + * related bits can be filetered by masks retrieved from ntb_msg_inbits() and > + * ntb_msg_outbits(). > + * > + * Return: status bits of message registers > + */ > +static inline u64 ntb_msg_read_sts(struct ntb_dev *ntb) > +{ > + if (!ntb->ops->msg_read_sts) > + return 0; > + > + return ntb->ops->msg_read_sts(ntb); > +} > + > +/** > + * ntb_msg_clear_sts() - clear status bits of message registers > + * @ntb: NTB device context. > + * @sts_bits: Status bits to clear. > + * > + * Clear bits in the status register. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_clear_sts(struct ntb_dev *ntb, u64 sts_bits) > +{ > + if (!ntb->ops->msg_clear_sts) > + return -EINVAL; > + > + return ntb->ops->msg_clear_sts(ntb, sts_bits); > +} > + > +/** > + * ntb_msg_set_mask() - set mask of message register status bits > + * @ntb: NTB device context. > + * @mask_bits: Mask bits. > + * > + * Mask the message registers status bits from raising the message event. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_set_mask(struct ntb_dev *ntb, u64 mask_bits) > +{ > + if (!ntb->ops->msg_set_mask) > + return -EINVAL; > + > + return ntb->ops->msg_set_mask(ntb, mask_bits); > +} > + > +/** > + * ntb_msg_clear_mask() - clear message registers mask > + * @ntb: NTB device context. > + * @mask_bits: Mask bits to clear. > + * > + * Clear bits in the message events mask register. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_clear_mask(struct ntb_dev *ntb, u64 mask_bits) > +{ > + if (!ntb->ops->msg_clear_mask) > + return -EINVAL; > + > + return ntb->ops->msg_clear_mask(ntb, mask_bits); > +} > + > +/** > + * ntb_msg_read() - read message register with specified index > + * @ntb: NTB device context. > + * @midx: Message register index > + * @pidx: OUT - Port index of peer device a message retrieved from > + * @msg: OUT - Data > + * > + * Read data from the specified message register. Source port index of a > + * message is retrieved as well. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_read(struct ntb_dev *ntb, int midx, int *pidx, > + u32 *msg) > +{ > + if (!ntb->ops->msg_read) > + return -EINVAL; > + > + return ntb->ops->msg_read(ntb, midx, pidx, msg); > +} > + > +/** > + * ntb_msg_write() - write data to the specified message register > + * @ntb: NTB device context. > + * @midx: Message register index > + * @pidx: Port index of peer device a message being sent to > + * @msg: Data to send > + * > + * Send data to a specified peer device using the defined message register. > + * Message event can be raised if the midx registers isn't empty while > + * calling this method and the corresponding interrupt isn't masked. > + * > + * Return: Zero on success, otherwise a negative error number. > + */ > +static inline int ntb_msg_write(struct ntb_dev *ntb, int midx, int pidx, > + u32 msg) > +{ > + if (!ntb->ops->msg_write) > + return -EINVAL; > + > + return ntb->ops->msg_write(ntb, midx, pidx, msg); > +} > + > #endif > -- > 2.6.6